英文:
My cursor becomes null when I use async task?
问题
以下是翻译好的内容:
我有一个数据库代码,从我的表中获取数据并将其存储到我的游标中,但在主线程上运行数据库代码会使我的应用程序减速,尤其是当我打开显示数据的活动以在RecyclerView中显示数据时。因此,我将数据库代码移到了一个AsyncTask内部类中,并尝试运行它。
然而,在AsyncTask在onCreate()
方法中运行之后,我的RecyclerView适配器代码开始运行,对游标对象调用的getItemCount()
方法抛出了null指针异常
,因为游标为空。
通过调试,我已经找到了游标何时变为null,但不明白为什么它会变为null。当accessDatabase()
方法运行时,游标不为空,但在onCreate()
方法中的AsyncTask内部类运行后,游标变为null。
onCreate()
方法中的代码:
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 run");
if (cursor == null) {
Log.d("green", "cursor is null"); // 我在日志中收到这个消息
}
captionedImagesAdapter adapter = new captionedImagesAdapter(this, cursor);
GridLayoutManager layoutManager = new GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false);
groceryRecycler.setLayoutManager(layoutManager);
groceryRecycler.setAdapter(adapter);
}
AsyncTask内部类:
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();
}
}
}
accessDatabase()
方法:
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();
}
}
我的RecyclerView适配器:
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"); // 我在日志中收到这个消息
}
}
// ...(其余的适配器代码)
}
异常信息:
java.lang.NullPointerException: 尝试调用接口方法 'int android.database.Cursor.getCount()',但空对象引用
at com.myapps.myapplication.captionedImagesAdapter.getItemCount(captionedImagesAdapter.java:58)
// ...(其余的堆栈跟踪信息)
以上是您提供的代码内容的翻译。如果您需要进一步解决问题或有其他疑问,请随时提问。
英文:
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)
答案1
得分: 1
由于错误的假设是主线程在等待异步任务完成,所以你得到了 null。当然,这是错误的(否则你就不需要不同的线程)。你有不同的选项来修复它,例如:
-
使用 CursorLoader(已弃用)
-
使用回调通知 UI 线程,在异步任务完成加载游标时。一个示例在这里。
-
探索不同的技术,比如 协程。
英文:
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:
- <s>Use the CursorLoader </s> (deprecated)
- Use a callback to notify the UI Thread, when the <s>AsyncTask</s> (deprecated) is done loading the cursor. An example here
- Look into a different technology, like coroutines
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论