jeudi 29 octobre 2015

Fragment crash: IndexOutOfBoundsException: Invalid index x, size is x after updating my database

Im making an app where i download the data from an api. The data is downloaded every X minutes. When the data has been downloaded, it is stored in my DB. However, the problem i have is that whenever i update the db, the generateData() method in FragmentTrend crashes when i switch to another tab and comeback again. I get the the index out of bound exception as seen below. It crashes at line:

int y = Integer.parseInt(listDatastream.get(i).getCurrent_value());

Ive tried to test out that whenever the count != getNumberOfElementsInDatabase() then just return the value to see whether or not it would help, however, i end up with another error which is similar to this thread: DB error code 14

Any help would be appreciated! Ive been stuck with this problem for more than 3 days now! Thank you!

Additional information: I have 4 tabs and use FragmentStatePagerAdapter to navigate. Ive noticed one thing while navigating. Whenever i navigate to the neighboring tab (such as tab1 to tab2), the previous tab is not terminated. It is still on the run. I found this out by printing an endless forloop with text. The for loop stops only when im 2 tabs away (such as from tab1 to tab3 / tab4 or tab 2 to tab4 etc). So the app crashes only when i select tab3 or tab4 then reselect tab1 or tab2 respectively.

Error:

10-29 19:37:09.693 2618-2618/? E/AndroidRuntime: FATAL EXCEPTION: main
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime: Process: com.thesis.dell.MaterialTest2, PID: 2618
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime: java.lang.IndexOutOfBoundsException: Invalid index 166, size is 166
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at java.util.ArrayList.get(ArrayList.java:308)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at com.thesis.dell.MaterialTest2.fragments.FragmentTrend.generateData(FragmentTrend.java:166)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at com.thesis.dell.MaterialTest2.fragments.FragmentTrend.drawGraphVolt(FragmentTrend.java:112)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at com.thesis.dell.MaterialTest2.fragments.FragmentTrend.onCreateView(FragmentTrend.java:86)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
10-29 19:37:09.693 2618-2618/? E/AndroidRuntime:     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)

FragmentTrend.java

package com.thesis.dell.MaterialTest2.fragments;

import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.LegendRenderer;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import com.thesis.dell.MaterialTest2.MyApplication;
import com.thesis.dell.MaterialTest2.R;
import com.thesis.dell.MaterialTest2.log.L;
import com.thesis.dell.MaterialTest2.pojo.Datastream;

import java.util.ArrayList;

public class FragmentTrend extends Fragment {

private static final String STATE_DATASTREAM2 = "state_datastream2";
private ArrayList<Datastream> listDatastream = new ArrayList<>();
//private SwipeRefreshLayout mSwipeRefreshLayout;
private View view;
private LineGraphSeries<DataPoint> mVolt;
private int count;


public FragmentTrend() {
    // Required empty public constructor
}

public static FragmentTrend newInstance(String param1, String param2) {
    FragmentTrend fragment = new FragmentTrend();
    Bundle args = new Bundle();
    //put any extra arguments that you may want to supply to this fragment
    fragment.setArguments(args);
    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    view = inflater.inflate(R.layout.tab_trend,container,false);

    count = getNumberOfElementsInDatabase();
    //setupSwipe();
    //printAllValuesInDatastream();


    if (savedInstanceState != null) {
        //if this fragment starts after a rotation or configuration change,
        // load the existing data from a parcelable
        L.t(getActivity(), "savedInstanceState not null");
        listDatastream = savedInstanceState.getParcelableArrayList(STATE_DATASTREAM2);
    }
    else {
        //if this fragment starts for the first time, load the list of data from a database
        //get a reference to our DB running on our main thread
        L.t(getActivity(), "savedInstanceState is null");
        listDatastream = MyApplication.getWritableDatabase().readDatastreams();
    }
    if (listDatastream != null && !listDatastream.isEmpty()) {
        drawGraphVolt();
    }

    return view;
}



public void drawGraphVolt () {
    // Setting up and drawing volt graph
    GraphView graph = (GraphView) view.findViewById(R.id.graph);

    mVolt = new LineGraphSeries<>(generateData());
    graph.addSeries(mVolt);

    // styling grid/labels
    graph.getGridLabelRenderer().setGridColor(getResources().getColor(R.color.colorGraphGrid));
    graph.getGridLabelRenderer().setHorizontalLabelsColor(getResources().getColor(R.color.colorGraphText));
    graph.getGridLabelRenderer().setVerticalLabelsColor(getResources().getColor(R.color.colorGraphText));
    graph.getGridLabelRenderer().setTextSize(45);
    graph.getGridLabelRenderer().reloadStyles();

    // styling series
    mVolt.setColor(getResources().getColor(R.color.colorAccent));
    mVolt.setThickness(4);
    //series.setDrawBackground(true);
    //series.setBackgroundColor(getResources().getColor(R.color.gridGraphColor));


    graph.getViewport().setYAxisBoundsManual(true);
    graph.getViewport().setMinY(graph.getViewport().getMinY(false));
    graph.getViewport().setMaxY(graph.getViewport().getMaxY(false));

    graph.getViewport().setXAxisBoundsManual(true);
    graph.getViewport().setMinX(graph.getViewport().getMinX(true));
    graph.getViewport().setMaxX(graph.getViewport().getMaxX(true));

    mVolt.setTitle("Volt");
    graph.getLegendRenderer().setVisible(true);
    graph.getLegendRenderer().setAlign(LegendRenderer.LegendAlign.TOP);
    graph.getLegendRenderer().setTextSize(45);
    graph.getLegendRenderer().setBackgroundColor(getResources().getColor(R.color.colorPrimary));
    graph.getLegendRenderer().setTextColor(getResources().getColor(R.color.colorPrimaryText));
    graph.getLegendRenderer().setPadding(15);
    graph.getLegendRenderer().setMargin(0);

    graph.getViewport().setScrollable(true);
}

private DataPoint[] generateData() {

    DataPoint[] values = new DataPoint[count];
    for (int i = 0; i < count; i++) {
//            if (count != getNumberOfElementsInDatabase()) {
//
//                return values;
//            }

        int x = i;
        int y = Integer.parseInt(listDatastream.get(i).getCurrent_value());
        DataPoint v = new DataPoint(x, y);
        values[i] = v
    }
    return values;
}

@Override
public void onPause() {
    super.onPause();
}



@Override
public void onResume() {
    super.onResume();
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putParcelableArrayList(STATE_DATASTREAM2, listDatastream);
}

public int getNumberOfElementsInDatabase() {
    int countListDatastream = MyApplication.getWritableDatabase().getTotalNumberOfElements();
    return countListDatastream;
}

}

My Database:

package com.thesis.dell.MaterialTest2.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;

import com.thesis.dell.MaterialTest2.pojo.Datastream;
import com.thesis.dell.MaterialTest2.log.L;

import java.util.ArrayList;
import java.util.Date;

public class MyDatabase {

private MyHelper mHelper;
private SQLiteDatabase mDatabase;

public MyDatabase(Context context) {
    mHelper = new MyHelper(context);
    mDatabase = mHelper.getWritableDatabase();
    //mDatabase.close();
}

public void insertValues(ArrayList<Datastream> listValues, boolean clearPrevious) {
    if (clearPrevious) {
        deleteData();
    }
    //beginTransaction(null /* transactionStatusCallback */, true); allowed to comment like this?
    //create a sql prepared statement
    String sql = "INSERT INTO " + MyHelper.TABLE_NAME + " VALUES (?,?,?);";
    //compile the statement and start a transaction
    SQLiteStatement statement = mDatabase.compileStatement(sql);
    mDatabase.beginTransaction();
    for (int i = 0; i < listValues.size(); i++) {
        Datastream currentData = listValues.get(i);
        statement.clearBindings();
        //for a given column index, simply bind the data to be put inside that index
        statement.bindString(2, currentData.getCurrent_value());
        statement.bindLong(3, currentData.getCurrent_valueAt() == null ? -1 : currentData.getCurrent_valueAt().getTime());
        L.m("Inserting entry " +i);
        statement.execute();
    }
    //set the transaction as successful and end the transaction
    mDatabase.setTransactionSuccessful();
    mDatabase.endTransaction();
}

public int getTotalNumberOfElements() {

    int numberOfElements = -1;
    //get a list of columns to be retrieved, we need all of them
    String[] columns = {MyHelper.COLUMN_VALUE, MyHelper.COLUMN_DATE_AT};
    //make a simple query with dbname, columns and all other params as null
    Cursor cursor = mDatabase.query(MyHelper.TABLE_NAME, columns, null, null, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        numberOfElements = cursor.getCount();
        return numberOfElements;
    }
    return numberOfElements;
}
public ArrayList<Datastream> readDatastreams()
{
    //init an empty array list
    ArrayList<Datastream> listDatastream = new ArrayList<>();

    //get a list of columns to be retrieved, we need all of them
    String[] columns = {MyHelper.COLUMN_VALUE, MyHelper.COLUMN_DATE_AT};
    //make a simple query with dbname, columns and all other params as null
    Cursor cursor = mDatabase.query(MyHelper.TABLE_NAME, columns, null, null, null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        do {
            //create a new Datastream object and retrieve the data from the cursor to be stored in this Datastream object
            Datastream datastream = new Datastream();
            //each step is a 2 part process, find the index of the column first, find the data of that column using
            //that index and finally set our blank Datastream object to contain our data
            datastream.setCurrent_value(cursor.getString(cursor.getColumnIndex(MyHelper.COLUMN_VALUE)));
            long valueAtMilliseconds = cursor.getLong(cursor.getColumnIndex(MyHelper.COLUMN_DATE_AT));
            datastream.setCurrent_valueAt(valueAtMilliseconds != -1 ? new Date(valueAtMilliseconds) : null);
            //add the datastream to the list of datastream objects which we plan to return
            listDatastream.add(datastream);
        }
        while (cursor.moveToNext());
    }
    return listDatastream;
}

//delete all rows from our table
public void deleteData() {
    mDatabase.delete(MyHelper.TABLE_NAME, null, null);
}

public long insertData(String value, String valueDate) {
    SQLiteDatabase db = mHelper.getWritableDatabase();
    ContentValues cv = new ContentValues();
    cv.put(MyHelper.COLUMN_VALUE, value);
    cv.put(MyHelper.COLUMN_DATE_AT, valueDate);
    //ID indicates the row id that was inserted if successfull
    long id = db.insert(MyHelper.TABLE_NAME, null, cv);
    return id;
}

public String getColumnValueLast() {
    SQLiteDatabase db = mHelper.getWritableDatabase();
    String[] columns = {MyHelper.COLUMN_VALUE};
    Cursor cursor = db.query(MyHelper.TABLE_NAME, columns, null, null, null, null, null );

    String lastValue = "-1";
    if (cursor.moveToLast()) {
        int index1 = cursor.getColumnIndex(MyHelper.COLUMN_VALUE);
        String value = cursor.getString(index1);
        lastValue = value;
    }
    return lastValue;
}

static class MyHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "MyDB";
    private static final String TABLE_NAME = "TableValue";
    private static final int DB_VERSION = 2;
    private static final String COLUMN_UID = "_id";
    private static final String COLUMN_VALUE = "current_value";
    private static final String COLUMN_DATE_AT = "at";
    private static final String CREATE_TABLE = "CREATE TABLE "
            + TABLE_NAME
            + " ("
            + COLUMN_UID
            + " INTEGER PRIMARY KEY AUTOINCREMENT, "
            + COLUMN_VALUE
            + " VARCHAR(100), "
            + COLUMN_DATE_AT
            + " VARCHAR(100));";
    private static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
    private Context context; //mContext;

    public MyHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        // or mContext = context
        this.context = context;
        L.t(context, "constructor called");
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        try {
            db.execSQL(CREATE_TABLE);
            L.t(context, "onCreate called");
        } catch (SQLException e) {
            L.t(context, "" + e);
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            L.t(context, "onUpgrade called");
            db.execSQL(DROP_TABLE);
            onCreate(db);
        } catch (SQLException e) {
            L.t(context, "" + e);
        }
    }
}

}

Aucun commentaire:

Enregistrer un commentaire