Search code examples
androidsqlitelogcat

My app is working on emulator, not on device. log cat says android.database.CursorIndexOutOfBoundsException


I am unable to find where on the database i have made a mistake. The app that i am making works on the emulator the emulator, but now that i am trying to run it on mobile device on 4.1.2 platform, it gets Forced Closed messages immediately. It was working fine one emulator as well as mobile before i started working on the database. I have kept Minimum Required SDK: API 11:Android 3.0(Honeycomb) and Target SDK: API 18: Android 4.3. I have added the activities on the Manifest file as well.

11-25 01:53:50.047: E/Trace(26246): error opening trace file: No such file or directory (2)    
11-25 01:53:50.057: D/ActivityThread(26246): setTargetHeapUtilization:0.25    
11-25 01:53:50.057: D/ActivityThread(26246): setTargetHeapIdealFree:8388608    
11-25 01:53:50.057: D/ActivityThread(26246): setTargetHeapConcurrentStart:2097152    
11-25 01:53:50.117: D/AndroidRuntime(26246): Shutting down VM    
11-25 01:53:50.117: W/dalvikvm(26246): threadid=1: thread exiting with uncaught exception (group=0x40ecf378)    
11-25 01:53:50.127: E/AndroidRuntime(26246): FATAL EXCEPTION: main
11-25 01:53:50.127: E/AndroidRuntime(26246): java.lang.RuntimeException: Unable to create application my.app.cal.CalApplication: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4196)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.app.ActivityThread.access$1300(ActivityThread.java:138)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1267)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.os.Handler.dispatchMessage(Handler.java:99)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.os.Looper.loop(Looper.java:213)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.app.ActivityThread.main(ActivityThread.java:4787)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at java.lang.reflect.Method.invokeNative(Native Method)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at java.lang.reflect.Method.invoke(Method.java:511)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at dalvik.system.NativeStart.main(Native Method)
11-25 01:53:50.127: E/AndroidRuntime(26246): Caused by: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:418)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:74)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at my.app.cal.CalApplication.readWeighingDetailFromDB(CalApplication.java:45)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at my.app.cal.CalApplication.onCreate(CalApplication.java:26)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:999)
11-25 01:53:50.127: E/AndroidRuntime(26246):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4193)
11-25 01:53:50.127: E/AndroidRuntime(26246):    ... 10 more

Here are my Data base files: WeighingDetailDatabaseHelper.java:

package my.app.cal;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class WeighingDetailDatabaseHelper extends SQLiteOpenHelper {

    public static final String DB_NAME = "MyWeighingDetail.SQLite";
    public static final int DB_VERSION = 1;
    public static String WEIGHING_DETAIL_TABLE ="WeighingDetailTable";
    public static String RECORD_ID = "ID";
    public static String DATE ="Date";
    public static String WEIGHT = "Weight";


    public WeighingDetailDatabaseHelper(Context context){
        super (context, DB_NAME, null, DB_VERSION);

    }

    @Override
    public void onCreate(SQLiteDatabase weighingDetailDB) {

        String sqlStatement = "create table " + WEIGHING_DETAIL_TABLE
                + " (" 
                + RECORD_ID + " integer primary key autoincrement not null,"
                + DATE + " integer,"
                + WEIGHT + " float"
                + ");";

        Log.d("Weighing Database", sqlStatement);

        weighingDetailDB.execSQL(sqlStatement);

    }

    @Override
    public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {


    }

}

WeighingDetail.java:

package my.app.cal;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;

public class WeighingDetail implements Comparable<WeighingDetail> {

    private long id;
    private float weight;
    private Date date;
    private float runningAverage;




    public WeighingDetail(float weight, Date date) {
        this.weight = weight;
        this.date = date;
    }

    public WeighingDetail(long id, long dateEpoch, float weight) {
        this.id = id;
        setDateEpoch(dateEpoch);
        this.weight = weight;
        this.date = date;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }



    public float getWeight() {
        return weight;
    }

    public void setWeight(float weight) {
        this.weight = weight;
    }

    public Date getDate() {
        return date;
    }

    public long getDateEpoch(){
        return date.getTime()/1000;

    }
    public void setDateEpoch(long seconds){
        date = new Date(seconds * 1000);
    }

    public void setDate(Date date) {
        this.date = date;
    }


    public float getRunningAverage() {
        return runningAverage;
    }


    public void setRunningAverage(float runningAverage) {
        this.runningAverage = runningAverage;
    }
    public float sumofWeight() {
        return weight;  //Its just the weight itself, its used to calculate the running average weight later
    }

    public float calculateWeightAverage() {
        return weight;// Its the weight itself, used in averageEditText as well as for calculating total of the weights till now added
    }

    public boolean equals(Object that){
        WeighingDetail wd = (WeighingDetail) that;

        return this.date.equals(wd.date);
    }
    @Override
    public int compareTo(WeighingDetail that) {
        int difference;
        difference = this.date.compareTo(date);
        return difference;
    }

    public static void updateRunningAverage (ArrayList<WeighingDetail> allWeighingDetail) {

        int weeks = 1;
        float total = 0;

        Collections.sort(allWeighingDetail);

        if(allWeighingDetail.size() >0){
            for(WeighingDetail wd : allWeighingDetail){
                total +=wd.calculateWeightAverage();
                wd.setRunningAverage((float) total / (weeks));// first it was weeks = 3
                weeks++;
            }
        }
    }

    public String toString() {
        String result;
        //"ID:" + id + " " + 

        DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);
        result = df.format(date) + " " + weight  
                + String.format("%.1f", runningAverage);
        return result;
    }


}

a show history button shows the data base along with the running average, so its java file is ShowHistory.java that i have made.

package my.app.cal;

import java.util.ArrayList;

import android.app.ListActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;

public class HistoryActivity extends ListActivity {

    private ArrayList<WeighingDetail> allWeighingDetail; //added an instance method to activity
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.history_layout);

        //get the data from the App
        CalApplication app = (CalApplication) getApplication();
        allWeighingDetail = app.getAllWeighingDetail();
        WeighingDetail.updateRunningAverage (allWeighingDetail);

        // View ------  Adapter    -----  Data

        setListAdapter(
                new ArrayAdapter<WeighingDetail>(this,
                        android.R.layout.simple_list_item_1,
                        allWeighingDetail)



        );

    }
}

CalApplication.java

package my.app.cal;

import java.util.ArrayList;

import android.app.Application;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import static my.app.cal.WeighingDetailDatabaseHelper.*;
public class CalApplication extends Application {

    private ArrayList<WeighingDetail> allWeighingDetail;
    private SQLiteDatabase weighingDetailDB;

    @Override
    public void onCreate() {

        super.onCreate();

        WeighingDetailDatabaseHelper databaseHelper = new WeighingDetailDatabaseHelper(this);
        weighingDetailDB = databaseHelper.getWritableDatabase();

        // TODO get the data out of the database

        readWeighingDetailFromDB ();

    }

    private void readWeighingDetailFromDB() {

        allWeighingDetail = new ArrayList<WeighingDetail>();

        Cursor weighingDetailCursor;

        weighingDetailCursor = weighingDetailDB.query(WEIGHING_DETAIL_TABLE,
                new String[]{RECORD_ID, DATE, WEIGHT},
                null, null, null, null,DATE);

        weighingDetailCursor.moveToFirst();
        WeighingDetail tempWD;

        if(weighingDetailCursor.isAfterLast()){
            do{
                long id = weighingDetailCursor.getLong(0);
                long dateEpoch = weighingDetailCursor.getLong(1);
                float weight = weighingDetailCursor.getFloat(2);

                tempWD = new WeighingDetail(id, dateEpoch, weight);

                allWeighingDetail.add(tempWD);

                Log.d("Weighing Database", tempWD.toString());
            }while(weighingDetailCursor.moveToNext());

        }
        weighingDetailCursor.close();

    }

    public void addWeighingDetail(WeighingDetail weighingDetail){

        assert weighingDetail != null;

        ContentValues cv = new ContentValues();//object that will put the data to the db
        cv.put(WeighingDetailDatabaseHelper.DATE, weighingDetail.getDateEpoch());//USE EPOCH
        cv.put(WeighingDetailDatabaseHelper.WEIGHT, weighingDetail.getWeight());

        Log.d("Weighing Database", "Before Inserting a record" + weighingDetail);

        long idPassedBack = weighingDetailDB.insert(WeighingDetailDatabaseHelper.WEIGHING_DETAIL_TABLE, null, cv);
        weighingDetail.setId(idPassedBack);

        Log.d("Weighing Database", "After Inserting a record" + weighingDetail);
        allWeighingDetail.add(weighingDetail);

    }

    public ArrayList<WeighingDetail> getAllWeighingDetail() {
        return allWeighingDetail;
    }

    private void setAllWeighingDetail(ArrayList<WeighingDetail> allWeighingDetail) {
        this.allWeighingDetail = allWeighingDetail;
    }
}

Solution

  • Always use this condition when dealing with cursors:

    if( cursor != null && cursor.moveToFirst() ) {
    //do operations with records
    }
    

    Check whether the cursor is null or not. If it not null, then move the cursor to the first record. The cursor here is probably null (has no records).