You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Spinner选年月从SQLite列取值求和的问题排查

解决Android中Spinner选择年月后求和并显示的问题

先看你遇到的核心错误:SQL语法错误,同时数据库操作方法和Activity的事件监听也存在问题,下面一步步帮你修复:

1. 修复SQL语句的语法错误

错误日志里的SQL SELECT CAST(SUM(Jumlah)as Double) FROM tb_periode WHERE strftime('%Y',2010) AND strftime('%M,'01) 有几个关键问题:

  • strftime用法错误:strftime的第二个参数应该是表中的日期字段(比如你的AwalPeriode或AkhirPeriode),而不是直接传年份/月份值
  • 月份格式符错误:%M是分钟,正确的两位月份格式符是%m
  • WHERE条件逻辑错误:需要明确匹配年月等于选中值,应该用=连接,同时用参数化查询避免语法错误和SQL注入
  • String转数值求和:COLUMN_JUMLAH是String类型,求和前必须转成数值类型(比如REAL)

2. 修正DatabaseOperations中的方法

修复getAllPeriode方法

你的getAllPeriode方法把cursor.close()放在了while循环内部,导致第一次循环就关闭游标,只能拿到第一条数据,移到循环外面即可:

public ArrayList<Periode> getAllPeriode(){
    Cursor cursor = database.query(TABLE_PERIODE, allColumns, null,null,null,null,null);
    ArrayList<Periode> periodes = new ArrayList<>();
    cursor.moveToFirst();
    while (!cursor.isAfterLast()){
        Periode periode = cursorToPeriode(cursor);
        periodes.add(periode);
        cursor.moveToNext();
    }
    cursor.close(); // 移到循环外面
    return periodes;
}

重写addAllValues方法

完全重构这个方法,正确编写SQL并处理参数:

public double calculateTotalByMonthYear(String bulan, String tahun){
    double total = 0.0;
    // 假设你的日期字段是AwalPeriode,你可以根据实际换成AkhirPeriode
    String sql = "SELECT SUM(CAST(" + COLUMN_JUMLAH + " AS REAL)) FROM " + TABLE_PERIODE + 
                 " WHERE strftime('%Y', " + COLUMN_AWAL_PERIODE + ") = ? " +
                 " AND strftime('%m', " + COLUMN_AWAL_PERIODE + ") = ?";
    // 注意:这里要确保COLUMN_AWAL_PERIODE是你表中存储日期的列名,比如"AwalPeriode"
    
    Cursor c = database.rawQuery(sql, new String[]{tahun, bulan});
    if(c.moveToFirst()){
        // 用getDouble避免精度丢失
        total = c.getDouble(0);
    }
    c.close();
    return total;
}

注意:如果你的AwalPeriode存储的不是SQLite支持的日期格式(比如YYYY-MM-DD),strftime可能无法正确解析,需要先确保日期格式符合要求。

3. 修正HitungFinalBulanActivity的逻辑

添加Spinner选择监听

你现在在onCreate里直接调用求和方法,只会执行一次,用户切换Spinner不会更新结果,需要添加OnItemSelectedListener:

public class HitungFinalBulanActivity extends AppCompatActivity {
    Spinner MonthSpinner;
    Spinner YearSpinner;
    TextView totalJumlah;
    private DatabaseOperations transaksiOperations;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hitung_final_bulan);
        
        transaksiOperations = new DatabaseOperations(this);
        transaksiOperations.Open();
        
        MonthSpinner = findViewById(R.id.monthSpinner);
        YearSpinner = findViewById(R.id.yearspinner);
        totalJumlah = findViewById(R.id.txtViewJumlah);
        
        // 初始化月份Spinner
        ArrayAdapter<CharSequence> MonthAdapter = ArrayAdapter.createFromResource(this, 
                R.array.months_array, android.R.layout.simple_spinner_item);
        MonthAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        MonthSpinner.setAdapter(MonthAdapter);
        
        // 初始化年份Spinner
        ArrayList<String> years = new ArrayList<String>();
        int thisYear = Calendar.getInstance().get(Calendar.YEAR);
        for (int i = 2010; i <= thisYear; i++) {
            years.add(Integer.toString(i));
        }
        ArrayAdapter<String> YearAdapter = new ArrayAdapter<String>(this, 
                android.R.layout.simple_spinner_item, years);
        YearSpinner.setAdapter(YearAdapter);
        
        // 添加选择监听
        MonthSpinner.setOnItemSelectedListener(spinnerListener);
        YearSpinner.setOnItemSelectedListener(spinnerListener);
        
        // 初始化时计算一次默认选中值的总和
        calculateAndDisplayTotal();
    }
    
    // 共享的Spinner监听
    private AdapterView.OnItemSelectedListener spinnerListener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            calculateAndDisplayTotal();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            // 可选:处理未选中的情况
        }
    };
    
    // 计算并显示总和的方法
    private void calculateAndDisplayTotal(){
        String selectedMonth = MonthSpinner.getSelectedItem().toString();
        String selectedYear = YearSpinner.getSelectedItem().toString();
        
        // 注意:如果你的months_array是月份名称(比如"January"),需要转成两位数字("01"),否则strftime无法匹配
        // 这里假设你的months_array是两位数字格式,比如"01","02"...,如果是名称需要额外转换
        double total = transaksiOperations.calculateTotalByMonthYear(selectedMonth, selectedYear);
        
        // 格式化显示结果,保留两位小数
        totalJumlah.setText(String.format("Total: %.2f", total));
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 关闭数据库连接,避免内存泄漏
        transaksiOperations.close();
    }
}

注意事项:月份格式转换

如果你的months_array是月份名称(比如"January"、"February"),需要把选中的月份名称转换成两位数字(比如"01"、"02")才能和strftime的%m匹配,你可以添加一个转换方法:

private String convertMonthNameToNumber(String monthName){
    // 根据你的months_array顺序对应数字
    String[] months = getResources().getStringArray(R.array.months_array);
    for(int i=0; i<months.length; i++){
        if(months[i].equals(monthName)){
            // 转成两位数字,比如1→"01"
            return String.format("%02d", i+1);
        }
    }
    return "01"; // 默认返回1月
}

然后在calculateAndDisplayTotal里调用:

String selectedMonth = convertMonthNameToNumber(MonthSpinner.getSelectedItem().toString());

4. 其他潜在问题修复

  • 你的getJumlahPeriode方法的query参数错误,第三个参数是selection,你传了COLUMN_JUMLAH,会导致SQL语法错误,如果这个方法是用来获取所有Jumlah记录,可以改成:
public ArrayList<Periode> getJumlahPeriode(){
    Cursor cursor = database.query(TABLE_PERIODE, null, null, null,null,null,null);
    ArrayList<Periode> periodes = new ArrayList<>();
    cursor.moveToFirst();
    while (!cursor.isAfterLast()){
        Periode periode = cursorToPeriode(cursor);
        periodes.add(periode);
        cursor.moveToNext();
    }
    cursor.close();
    return periodes;
}

这样修改后,应该就能正确根据Spinner选择的年月求和并显示结果了。

内容的提问来源于stack exchange,提问作者XVallerie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:58:01