imin imin - 1 month ago 10
Android Question

Using Loaders with sqlite query that returns object

Here's what I've been doing all this while to get data from my database - my fragment will call a dbhelper which will run the query and pass the resulting data in an object.

I should have used a loader so that the querying is not done in the UI thread, but previously I didn't bother since my app's database is very small. Moving forward, this was a bad idea since my app has grown larger and so do the database. So now I'm reading all I can about Loaders including CursorLoader and custom loaders, but I still have problem implementing it in my app.

So here's my current code (simplified, just to show the relevant parts):

public class CategoryEdit extends Fragment{

private DbControl dbc;
private ObjectCategory objCategory;
private int categoryID = 3;
private EditText etName;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
dbc = new DbControl(getActivity());
try{
dbc.open();
objCategory = new ObjectCategory();
objCategory = dbc.getCategoryData(categoryID);
dbc.close();
}catch (SQLException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}

etName.setText(objCategory.name);
}
}

public class DbControl {

public static final String FILE_NAME = "DbControl.java";
private SQLiteDatabase database;
private MySQLiteHelper dbHelper;

public DbControl(Context context) {
dbHelper = new MySQLiteHelper(context);
}

public void open() throws SQLException {
database = dbHelper.getWritableDatabase();
}

public void close() {
dbHelper.close();
}

public ObjectCategory getCategoryData(int itemID) throws Exception{
ObjectCategory objCategory = new ObjectCategory();
Cursor cursor = database.query(MySQLiteHelper.TABLE_CATEGORY, new String[] {"name"},
"id = " + itemID, null, null, null, null);
if (cursor!=null && cursor.getCount()>0 && cursor.moveToFirst()) {
objCategory.name = cursor.getString(cursor.getColumnIndex("name"));
}
return objCategory;
}
}


Can anyone point me in the right direction, in implementing Loader the right way in my case here? If possible, I don't want to alter the codes inside class DbControl too much - especially the return data type of the functions inside it.

Btw amongst the tutorials about loaders that I've read is:



Anyway here's what I've done so far:

public class CategoryEdit extends Fragment implements LoaderManager.LoaderCallbacks<ObjectCategory> {

@Override
public Loader<ObjectCategory> onCreateLoader(int id, Bundle args){
try{
dbc.open();
objCategory = new ObjectCategory();
objCategory = dbc.getCategoryData(categoryID);
dbc.close();
}catch (SQLException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}

return objCategory; //this returns error, it says required Loader<ObjectCategory> instead of objCategory, but I'm not sure how to do that here
}

@Override
public void onLoadFinished(Loader<ObjectCategory> cursorLoader, ObjectCategory cursor) {
//Since onCreateLoader has error above, I'm not sure how to implement this part
}

@Override
public void onLoaderReset(Loader<ObjectCategory> cursorLoader) {
//Can I just leave this empty?
}
}

kws kws
Answer

Can anyone point me in the right direction, in implementing Loader the right way in my case here?

You have to use an AsyncTaskLoader like this:

public class CategoryEdit extends Fragment implements LoaderManager.LoaderCallbacks<ObjectCategory> {

    @Override
    public Loader<ObjectCategory> onCreateLoader(int id, Bundle args) {
        return new AsyncTaskLoader<ObjectCategory>(getActivity()) {
            @Override
            public ObjectCategory loadInBackground() {
                try {
                    dbc.open();
                    objCategory = new ObjectCategory();
                    objCategory = dbc.getCategoryData(categoryID);
                    dbc.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return objCategory;
            }

            @Override
            protected void onStartLoading() {
                forceLoad();
            }
        };

    }

    @Override
    public void onLoadFinished(Loader<ObjectCategory> loader, ObjectCategory data) {
        //do some stuff here
    }

    @Override
    public void onLoaderReset(Loader<ObjectCategory> loader) {
        //Yes, you can leave it empty
    }
}
Comments