我的应用程序不断崩溃,光标未正确初始化
Posted
技术标签:
【中文标题】我的应用程序不断崩溃,光标未正确初始化【英文标题】:My app keeps crashing, Cursor is not initialized correctly 【发布时间】:2017-09-18 20:01:27 【问题描述】:我的应用在 3 个不同的模拟器(api 16、21、24 和 25)上运行良好,但在真实设备上测试时一直崩溃。我收到这些错误消息。但由于我是 android 编程新手,我不太明白它们的含义。我正在使用 RecycleView。最后调用的方法是调用 swapCursor 方法的 onloadfinished 方法。谢谢你的帮助。
09-18 23:41:30.699 8324-8324/com.a2sigma.workermanager E/CursorWindow:
Failed to read row 0, column 0 from a CursorWindow which has 0 rows, 45 columns.
09-18 23:41:30.706 8324-8324/com.a2sigma.workermanager D/AndroidRuntime: Shutting down VM
09-18 23:41:30.719 8324-8324/com.a2sigma.workermanager E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.a2sigma.workermanager, PID: 8324
java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
at android.database.CursorWindow.nativeGetLong(Native Method)
at android.database.CursorWindow.getLong(CursorWindow.java:524)
at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:75)
at android.database.CursorWrapper.getLong(CursorWrapper.java:127)
at com.a2sigma.workermanager.CursorRecyclerViewAdapter.onBindViewHolder(CursorRecyclerViewAdapter.java:56)
at com.a2sigma.workermanager.CursorRecyclerViewAdapter.onBindViewHolder(CursorRecyclerViewAdapter.java:16)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6400)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6433)
at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5377)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5640)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5482)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5478)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2215)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1542)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1502)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3625)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3354)
at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3886)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.support.constraint.ConstraintLayout.onLayout(ConstraintLayout.java:1197)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:131)
at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1389)
at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:868)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
at android.view.View.layout(View.java:18874)
09-18 23:41:30.720 8324-8324/com.a2sigma.workermanager E/AndroidRuntime: at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
at com.android.internal.policy.DecorView.onLayout(DecorView.java:910)
at android.view.View.layout(View.java:18874)
at android.view.ViewGroup.layout(ViewGroup.java:5954)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2697)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2413)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1550)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7190)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:959)
at android.view.Choreographer.doCallbacks(Choreographer.java:734)
at android.view.Choreographer.doFrame(Choreographer.java:670)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:945)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
我的适配器类
package com.a2sigma.workermanager;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
class CursorRecyclerViewAdapter extends
RecyclerView.Adapter<CursorRecyclerViewAdapter.WorkerViewHolder>
private static final String TAG = "CursorRecyclerViewAdapt";
private Cursor mCursor;
private OnTaskClickListener mListener;
interface OnTaskClickListener
void onEditClick(Worker worker);
void onDeleteClick(Worker worker);
void onWorkerClick(Worker worker);
CursorRecyclerViewAdapter(Cursor cursor, OnTaskClickListener listener)
Log.d(TAG, "CursorRecyclerViewAdapter: Constructor called");
mCursor = cursor;
mListener = listener;
@Override
public WorkerViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
Log.d(TAG, "onCreateViewHolder: new view requested");
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.worker_list_items, parent,false);
return new WorkerViewHolder(view);
@Override
public void onBindViewHolder(WorkerViewHolder holder, int position)
Log.d(TAG, "onBindViewHolder: starts position " +position );
if((mCursor == null)||(mCursor.getCount() == 0))
Log.d(TAG, "onBindViewHolder: providing instructions");
holder.name.setText(R.string.instructions_heading);
holder.noIndukKaryawan.setText(R.string.instructions);
holder.editButton.setVisibility(View.GONE);
holder.deleteButton.setVisibility(View.GONE);
else
if(!mCursor.moveToPosition(position))
throw new IllegalStateException("Couldn't move cursor to position " +position);
Log.d(TAG, "onBindViewHolder: Hallooooooooo");
final Worker worker = new Worker(mCursor.getLong(mCursor.getColumnIndex(WorkersContract.Columns._ID)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.NAMA_KARYAWAN)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.JENIS_KELAMIN)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.TGL_LAHIR)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.TEMPAT_LAHIR)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.NKTP)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.NO_HP_1)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.NO_HP_2)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.NO_KK)),
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.IBU_KANDUNG)),
mCursor.getBlob(mCursor.getColumnIndex(WorkersContract.Columns.FOTO)));
Log.d(TAG, "onBindViewHolder: worker id "+ worker.getId());
holder.name.setText(worker.getmName());
holder.noIndukKaryawan.setText("NIK: " + worker.getmNIK());
holder.editButton.setVisibility(View.VISIBLE);//TODO add onClick listener
holder.deleteButton.setVisibility(View.VISIBLE); //TODO add onClick Listener
View.OnClickListener buttonListener = new View.OnClickListener()
@Override
public void onClick(View view)
Log.d(TAG, "onClick: starts");
switch (view.getId())
case R.id.wli_edit:
if(mListener != null)
mListener.onEditClick(worker);
break;
case R.id.wli_delete:
if(mListener!=null)
mListener.onDeleteClick(worker);
break;
default:
Log.d(TAG, "onClick: found unexpected button id");
;
holder.editButton.setOnClickListener(buttonListener);
holder.deleteButton.setOnClickListener(buttonListener);
@Override
public int getItemCount()
Log.d(TAG, "getItemCount: starts");
if((mCursor == null) || (mCursor.getCount() == 0))
return 1; // fib, because we populate a single viewHolder with instructions
else
return mCursor.getCount();
/**
* Swap in a new Cursor, returning the old Cursor.
* The returned old Cursor is <em>not</em> closed.
*
* @param newCursor The new cursor to be used
* @return Returns the previously set Cursor, or null if there wasn't one.
* If the given new Cursor is the same instance as the previously set
* Cursor, null is also returned.
*/
Cursor swapCursor(Cursor newCursor)
Log.d(TAG, "swapCursor: Called");
if(newCursor == mCursor)
return null;
final Cursor oldCursor = mCursor;
mCursor = newCursor;
if(newCursor !=null)
// notify the observers about the new cursor
notifyDataSetChanged();
else
// notify the obeservers about the lack of a data set
notifyItemRangeRemoved(0, getItemCount());
return oldCursor;
static class WorkerViewHolder extends RecyclerView.ViewHolder
private static final String TAG = "TaskViewHolder";
TextView name = null;
TextView noIndukKaryawan = null;
ImageButton editButton = null;
ImageButton deleteButton = null;
public WorkerViewHolder(View itemView)
super(itemView);
Log.d(TAG, "TaskViewHolder: starts");
this.name = (TextView) itemView.findViewById(R.id.wli_name);
this.noIndukKaryawan = (TextView)itemView.findViewById(R.id.wli_nik);
this.editButton = (ImageButton) itemView.findViewById(R.id.wli_edit);
this.deleteButton = (ImageButton) itemView.findViewById(R.id.wli_delete);
XML 文件 1.worker_list_items
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:orientation="vertical">
<TextView
android:id="@+id/wli_name"
android:layout_
android:layout_
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="16dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/wli_edit"
app:layout_constraintTop_toTopOf="parent"
tools:text="Nama Karyawan" />
<TextView
android:id="@+id/wli_nik"
android:layout_
android:layout_
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="1dp"
android:textColor="?android:attr/textColorSecondary"
android:textSize="18sp"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/wli_edit"
app:layout_constraintTop_toBottomOf="@+id/wli_name"
tools:text="123.256.478" />
<ImageButton
android:id="@+id/wli_delete"
android:layout_
android:layout_
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="16dp"
android:contentDescription="@string/delete_button"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@android:drawable/ic_menu_delete" />
<ImageButton
android:id="@+id/wli_edit"
android:layout_
android:layout_
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="0dp"
android:contentDescription="@string/edit_button"
app:layout_constraintRight_toLeftOf="@+id/wli_delete"
app:layout_constraintTop_toTopOf="@+id/wli_delete"
app:srcCompat="@android:drawable/ic_menu_edit" />
</android.support.constraint.ConstraintLayout>
还有 RycycleView XML 文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_
android:layout_>
<android.support.v7.widget.RecyclerView
android:id="@+id/worker_list"
android:layout_
android:layout_
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" />
</android.support.constraint.ConstraintLayout>
【问题讨论】:
看起来这不是整个堆栈跟踪...你能发布整个堆栈跟踪吗? 您的 xml 中的RecyclerView
中有 android:animateLayoutChanges="true"
吗?
@MosesAprico 不,我没有,我编辑了我的问题。
@10101010 其实我只有这些
哇,现在是凌晨 4 点,哈哈。顺便说一句,您是否尝试过使用断点进行调试?它通常显示像这样奇怪的事情的问题。
【参考方案1】:
这通常是通货膨胀错误。您需要比较您尝试填充的 View ID,确保它们不为空,并且您已正确设置 Recycler View Holder Adapter。
发布您的适配器、您要填充的行的 xml、您的查看器模式以及您的适配器设置和分配,我们当然可以帮助您解决问题。
只是为了更新答案,您的光标应该在访问之前正确填充,并且您应该在访问之前确保内容存在。
填充光标的示例
Cursor cursor = null;
try
cursor = queryBuilder.query(mysqlDBHelper.openDatabase(<YOUR CONTEXT>), projection, selection, selectionArgs, null, null, sortOrder);
catch (Exception e)
e.printStackTrace();
return cursor;
接下来,当您决定从光标访问值时,您可以进行一些安全检查,而不是直接访问它们。它可能会变得相当冗长,所以我建议创建一个从光标创建对象的方法,然后在那里进行所有的 null 安全检查。
代替:
mCursor.getString(mCursor.getColumnIndex(WorkersContract.Columns.IBU_KANDUNG)));
执行以下操作:
int IBU_KANDUNG_INDEX = mCursor.getColumnIndex(WorkersContract.Columns.IBU_KANDUNG);
myObject.setString(mCursor.getString(IBU_KANDUNG_INDEX) == null ? "" : mCursor.getString(IBU_KANDUNG_INDEX));
这将确保您不会在对象中设置空值或尝试访问空游标的 -1 索引。
【讨论】:
感谢您的快速回复,我已使用 xml 和适配器类编辑了我的问题。 抱歉,本可以在这里回复,您能否为我提供更多关于错误方面的信息。充气机错误基本上无法创建您的 UI 元素,但有一个根本原因。可能是交换游标在绘制第一行时发生或其他一百万个原因,但我确信这些日志中嵌套了更多信息,也许我们可以找到它:) 嗯,这有帮助。完美的。所以你有一个有效的游标对象,但它是空的。您正在崩溃,因为您的光标内容未从数据库中正确填充。因此,无论您从何处创建游标(通常在某种 contentProvider 中,您的格式设置不正确或可能在 SQL 中遇到错误。无论如何,您的游标没有数据库内容,因此 getString 会使您的尝试填充 UI 元素的应用程序。以上是关于我的应用程序不断崩溃,光标未正确初始化的主要内容,如果未能解决你的问题,请参考以下文章
由于 Firebase 初始化,App Delegate 崩溃