Reputation: 299
I am trying to implement the Cursor Loader
and Custom Cursor Adapter
with the database(Sqlite local database) in
my android project. I actually want to feed my listview asynchronously with data from my local database with the help of the Cursor Loader and Adapter`. Below is are my class,subclass and methods
// Home Activity class
public class HomeActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
DotCursorAdapter mAdapter;
private ListView lv;
private final int LOADER_ID = 1932;
DatabaseHandler dbHelper = new DatabaseHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
lv = (ListView) findViewById(R.id.lists);
mAdapter = new DotCursorAdapter(this, null,0);
lv.setAdapter(mAdapter);
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new DumbLoader(this);
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
mAdapter.swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
mAdapter.swapCursor(null);
}
/**
* DumbLoader sub class
*/
public class DumbLoader extends CursorLoader {
private static final String TAG = "DumbLoader";
public DumbLoader(Context context) {
super(context);
}
@Override
public Cursor loadInBackground() {
Cursor c = dbHelper.fetchAllCountries();
return c;
}
}
/**
* DotCursor Adapter sub class
*/
public final class DotCursorAdapter extends CursorAdapter {
public DotCursorAdapter(Context context, Cursor cursor, int flags) {
super(context, cursor, 0);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Find fields to populate in inflated template
TextView tvBody = (TextView) view.findViewById(R.id.header_text);
String body = cursor.getString(cursor.getColumnIndexOrThrow("fname"));
// Populate fields with extracted properties
tvBody.setText(body);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.list_cardview_activity, parent, false);
}
}
}
Below also is my database handler method which fetches the data from the database.
public Cursor fetchAllCountries() {
SQLiteDatabase db = this.getReadableDatabase();
Cursor mCursor = db.query(TABLE_LOGIN, new String[] {KEY_ID,KEY_FIRSTNAME},
null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
The Problem On executing this codes above it gives a message error from the log cat and craches the app.
the main error
Object returned from onCreateLoader must not be a non-static inner member class
Below also is my log cat details
09-21 16:13:25.563: D/AbsListView(26541): Get MotionRecognitionManager 09-21 16:13:25.568: D/AndroidRuntime(26541): Shutting down VM 09-21 16:13:25.573: W/dalvikvm(26541): threadid=1: thread exiting with uncaught exception (group=0x411372a0) 09-21 16:13:25.573: E/AndroidRuntime(26541): FATAL EXCEPTION: main 09-21 16:13:25.573: E/AndroidRuntime(26541): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.alliswell.alliswell/com.alliswell.alliswell.HomeActivity}: java.lang.IllegalArgumentException: Object returned from onCreateLoader must not be a non-static inner member class: DumbLoader{418dc668 id=0} 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2110) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.ActivityThread.access$700(ActivityThread.java:140) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.os.Handler.dispatchMessage(Handler.java:99) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.os.Looper.loop(Looper.java:137) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.ActivityThread.main(ActivityThread.java:4921) 09-21 16:13:25.573: E/AndroidRuntime(26541): at java.lang.reflect.Method.invokeNative(Native Method) 09-21 16:13:25.573: E/AndroidRuntime(26541): at java.lang.reflect.Method.invoke(Method.java:511) 09-21 16:13:25.573: E/AndroidRuntime(26541): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038) 09-21 16:13:25.573: E/AndroidRuntime(26541): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805) 09-21 16:13:25.573: E/AndroidRuntime(26541): at dalvik.system.NativeStart.main(Native Method) 09-21 16:13:25.573: E/AndroidRuntime(26541): Caused by: java.lang.IllegalArgumentException: Object returned from onCreateLoader must not be a non-static inner member class: DumbLoader{418dc668 id=0} 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.support.v4.app.LoaderManagerImpl$LoaderInfo.start(LoaderManager.java:257) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.support.v4.app.LoaderManagerImpl.doStart(LoaderManager.java:714) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:556) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1178) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.Activity.performStart(Activity.java:5198) 09-21 16:13:25.573: E/AndroidRuntime(26541): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2083) 09-21 16:13:25.573: E/AndroidRuntime(26541): ... 11 more
I think I am doing something wrong within my codes, I would be grateful if someone could help me solve this problem. Thank you.
Upvotes: 4
Views: 3473
Reputation: 4287
LuksProg and BamsBamx suggestions are correct. Just to give more context to it, if you use a non-static inner class which extends AsyncTask
or AsyncTaskLoader
or if any kind of activity is happening in that class which is not on the main thread then the Runtime Exception is thrown. The reason is that if some background task is going on in a non-static inner class and at that time the parent activity is destroyed then there will be a memory leak as the inner classes always have a context stored of their parent classes. That's why to prevent the memory leak, any background operations have to be carried out in a static inner class or in a separate individual class. For more insights see this SO thread
Upvotes: 0
Reputation: 4256
You have 2 ways to fix this:
1.- Create DumbLoader.java file and set it like this:
public class DumbLoader extends CursorLoader {
private DatabaseHandler mDBHelper;
public DumbLoader(Context context, DatabaseHandler dbHelper) {
super(context);
mDBHelper = dbHelper;
}
@Override
public Cursor loadInBackground() {
return mDBHelper.fetchAllCountries();
}
}
2.- Use static
modifier for your Activity's DumbLoader nested class so it gets as following:
public class HomeActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
//onCreate(), etc...
//Make DumbLoader nested class STATIC
public static class DumbLoader extends CursorLoader {
private DatabaseHandler mDBHelper;
public DumbLoader(Context context, DatabaseHandler dbHelper) {
super(context);
mDBHelper = dbHelper;
}
@Override
public Cursor loadInBackground() {
return mDBHelper.fetchAllCountries();
}
}
Upvotes: 7