Zahid Habib
Zahid Habib

Reputation: 21

My cursor becomes null when I use async task?

I have a database code that takes data from my table & stores it into my cursor but running the database code on the main thread slows down my app when I open the activity that displays the data on a recycler view. So I moved the database code to an asyntask inner class & tried running it.

However, after asyntask runs in the onCreate () my recycler view adapter code runs & the getItemCount () called on the cursor object throws a null pointer exception because the cursor is null.

From debugging I have found where the cursor becomes null but don't understand why it becomes null. the cursor when the accessDatabase () runs is not null but after the asynctask inner class runs in the onCreate () the cursor becomes null.

Code in the onCreate method:

protected void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.item_grocery);

    RecyclerView groceryRecycler = (RecyclerView) findViewById(R.id.grocery_recycler_view);

    StartDatabase sd = new StartDatabase();
    sd.execute(databaseHelper);
    Log.d ("blue", "sd has ran");

    if (cursor == null) {
        Log.d ("green", "cursor is null");//I receive this in the log cat
    }

    captionedImagesAdapter adapter = new captionedImagesAdapter (this, cursor);
    GridLayoutManager layoutManager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
    groceryRecycler.setLayoutManager(layoutManager);
    groceryRecycler.setAdapter (adapter);
}

The async task inner class:

private class StartDatabase extends AsyncTask<MyDatabaseHelper, Void, Boolean> {

    protected void onPreExecute () {}

    @Override
    protected Boolean doInBackground(MyDatabaseHelper... myDatabaseHelpers) {
        try {
            accessDataBase();

            return true;
        } catch (SQLiteException e) {
            return false;

        }
    }

    protected void onPostExecute (Boolean success) {
        if (!success) {
            Toast toast = Toast.makeText(grocery_item.this, "Database unavailable", Toast.LENGTH_SHORT);
            toast.show();
        }

        }
    }
}

The access database method:

public void accessDataBase () {

    try {

        db = databaseHelper.getReadableDatabase();

        cursor = db.query ("GROCERY_DATA", new String[] {"NAME", "PATHS"}, null, null, null, null, null);

        if (cursor == null) {
            Log.d ("blue", "cursor is null");
        }

    } catch (SQLiteException e) {
        e.printStackTrace();
    }

}

My recycle view adapter:

public class captionedImagesAdapter extends RecyclerView.Adapter <captionedImagesAdapter.ViewHolder> {

private Context context;
private Cursor cursor;

public captionedImagesAdapter (Context context, Cursor cursor) {
    this.context = context;
    this.cursor = cursor;

    if (this.cursor == null) {
        Log.d ("red", "cursor is null");//I receive this in the log cat 
    }
}

public captionedImagesAdapter.ViewHolder onCreateViewHolder (ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(context);
    CardView cv = (CardView) inflater.inflate(R.layout.card_view, parent, false);

    return new ViewHolder (cv);
}

public void onBindViewHolder(ViewHolder holder, int position) {
    if (!cursor.moveToPosition(position)) {
        return;
    }

    String info_text = cursor.getString (0);
    holder.textView.setText(info_text);


    String image_Path = cursor.getString(1);
    File file = new File (image_Path);

    if (file.exists()) {

        Bitmap bitmap = BitmapFactory.decodeFile (file.getAbsolutePath());

        holder.imageView.setImageBitmap(bitmap);
    }
}

public int getItemCount() {
    return cursor.getCount();//Line throwing the exception
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    private ImageView imageView;
    private TextView textView;

    public ViewHolder(CardView view) {
        super(view);
        imageView = view.findViewById(R.id.info_image);
        textView = view.findViewById(R.id.info_text);
    }
}

}

The exception I am receiving:

java.lang.NullPointerException: Attempt to invoke interface method 'int android.database.Cursor.getCount()' on a null object reference
    at com.myapps.myapplication.captionedImagesAdapter.getItemCount(captionedImagesAdapter.java:58)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:4135)
    at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3939)
    at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4499)
    at android.view.View.layout(View.java:22085)
    at android.view.ViewGroup.layout(ViewGroup.java:6290)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
    at android.view.View.layout(View.java:22085)
    at android.view.ViewGroup.layout(ViewGroup.java:6290)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
    at android.view.View.layout(View.java:22085)
    at android.view.ViewGroup.layout(ViewGroup.java:6290)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
    at android.view.View.layout(View.java:22085)
    at android.view.ViewGroup.layout(ViewGroup.java:6290)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1829)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1673)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1582)
    at android.view.View.layout(View.java:22085)
    at android.view.ViewGroup.layout(ViewGroup.java:6290)
    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:332)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:270)
    at com.android.internal.policy.DecorView.onLayout(DecorView.java:786)
    at android.view.View.layout(View.java:22085)
    at android.view.ViewGroup.layout(ViewGroup.java:6290)
    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:3333)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2810)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1930)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7988)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1154)
    at android.view.Choreographer.doCallbacks(Choreographer.java:977)
    at android.view.Choreographer.doFrame(Choreographer.java:893)
    at android.view.Choreographer$FrameHandler.handleMessage(Choreographer.java:1082)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7682)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

Upvotes: 0

Views: 191

Answers (1)

Blackbelt
Blackbelt

Reputation: 157457

One of the reasons you are getting it null is due to the wrong assumption that the Main thread is waiting for the async task to complete. That is, of course, wrong (otherwise you won't be needing a different thread). You have different options to fix it, for example:

  • Use the CursorLoader (deprecated)
  • Use a callback to notify the UI Thread, when the AsyncTask (deprecated) is done loading the cursor. An example here
  • Look into a different technology, like coroutines

Upvotes: 1

Related Questions