由于索引不正确,带有SQLite数据的RecyclerView崩溃

时间:2015-12-06 03:52:11

标签: android sqlite cursor android-recyclerview

我有一个recyclerView,它填充了来自SQLite数据库的数据。每个项目都有一个按钮,可以删除数据库中的标志,从而从recyclerView列表中消失。

我得到的问题是,当我尝试删除不同订单中的项目时,应用程序崩溃并引用错误/未知索引作为原因。

以下是我的recyclerView的(部分)代码,我认为问题在于:

@Override
    public BookmarksDetailRecycleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                                       int viewType) {
        // create a new view
        View itemLayoutView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.dua_detail_item_card, null);

        // create ViewHolder
        mHolder = new ViewHolder(itemLayoutView);
        return mHolder;
    }

    public void deleteRow(int position){
        mDuaData.remove(position); // this will remove row of data
        notifyItemRemoved(position); // this will do the animation of removal
        notifyItemRangeChanged(position, mDuaData.size()); // From GreenTech email
        // dataSetChanged();
    }

    @UiThread
    protected void dataSetChanged() {
        notifyDataSetChanged();
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder mHolder, int position){//final RecyclerView rv) {
        // - get data from your itemsData at this position
        // - replace the contents of the view with that itemsData
        final int finalPosition = position;

        mHolder.tvDuaNumber.setText(mDuaData.get(position).getReference() + "");
        mHolder.tvDuaArabic.setText(Html.fromHtml(mDuaData.get(position).getArabic()));

        final Spannable translation = new SpannableString(mDuaData.get(position).getTranslation());
        mHolder.tvDuaTranslation.setText(translation);

        if (mDuaData.get(position).getBook_reference() != null)
            mHolder.tvDuaReference.setText(Html.fromHtml(mDuaData.get(position).getBook_reference()));
        else
            mHolder.tvDuaReference.setText("null");

        if (mDuaData.get(position).getFav()) {
            mHolder.favButton.setText("{faw-star}");
        } else {
            mHolder.favButton.setText("{faw-star-o}");
        }

        final ViewHolder finalmHolder = mHolder;

        mHolder.shareButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View convertView) {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_SEND);
                intent.putExtra(Intent.EXTRA_TEXT,
                        myToolbarTitle + "\n\n" +
                                finalmHolder.tvDuaArabic.getText() + "\n\n" +
                                finalmHolder.tvDuaTranslation.getText() + "\n\n" +
                                finalmHolder.tvDuaReference.getText() + "\n\n" +
                                convertView.getResources().getString(R.string.action_share_credit)
                );
                intent.setType("text/plain");
                convertView.getContext().startActivity(
                        Intent.createChooser(
                                intent,
                                convertView.getResources().getString(R.string.action_share_title)
                        )
                );
            }
        });

        finalmHolder.favButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                boolean isFav = false;
                Log.d("K12_isFav", "isFav: " + isFav);

                int sql_position = Integer.parseInt(finalmHolder.tvDuaNumber.getText().toString());                

                Log.d("K12_sqlPosition", sql_position + "");

                deleteRow(finalPosition);

                Resources resources = v.getResources();
                String snack_begin = resources.getString(R.string.snackbar_text_begin);
                String snack_end = resources.getString(R.string.snackbar_text_end);
                String snack_action = resources.getString(R.string.snackbar_action).toUpperCase();

                // Following snippet taken from:
                // http://developer.android.com/training/basics/data-storage/databases.html#UpdateDbRow
                mDbHelper = new ExternalDbOpenHelper(v.getContext().getApplicationContext());

                SQLiteDatabase db = mDbHelper.getReadableDatabase();

                // New value for one column
                ContentValues values = new ContentValues();
                values.put(HisnDatabaseInfo.DuaTable.FAV, isFav);

                // Which row to update, based on the ID
                String selection = HisnDatabaseInfo.DuaTable.DUA_ID + " LIKE ?";
                String[] selectionArgs = {String.valueOf(finalmHolder.tvDuaNumber.getText().toString())};
                Log.d("K12_selectionArgs", "tvDuaNumber: " + String.valueOf(finalmHolder.tvDuaNumber.getText().toString()));

                int count = db.update(
                        HisnDatabaseInfo.DuaTable.TABLE_NAME,
                        values,
                        selection,
                        selectionArgs);

                if (count == 1) {
                    if (isFav) {
                        finalmHolder.favButton.setText("{faw-star}");
                    } else {
                        finalmHolder.favButton.setText("{faw-star-o}");                    
                    }                    
                }
                if (getItemCount() == 0) {
                    // I don't even know if this block is needed. Review once you have some sleep.
                }
            }
        });
    }

    // inner class to hold a reference to each item of RecyclerView
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView tvDuaNumber;
        public TextView tvDuaArabic;
        public TextView tvDuaTranslation;
        public TextView tvDuaReference;
        public IconicsButton shareButton;
        public IconicsButton favButton;

        public ViewHolder(View itemLayoutView) {
            super(itemLayoutView);
            tvDuaNumber = (TextView) itemLayoutView.findViewById(R.id.txtDuaNumber);
            tvDuaArabic = (TextView) itemLayoutView.findViewById(R.id.txtDuaArabic);
            tvDuaTranslation = (TextView) itemLayoutView.findViewById(R.id.txtDuaTranslation);
            tvDuaReference = (TextView) itemLayoutView.findViewById(R.id.txtDuaReference);
            shareButton = (IconicsButton) itemLayoutView.findViewById(R.id.button_share);
            favButton = (IconicsButton) itemLayoutView.findViewById(R.id.button_star);

            tvDuaArabic.setTypeface(sCachedTypeface);
            tvDuaArabic.setTextSize(prefArabicFontSize);
            tvDuaTranslation.setTextSize(prefOtherFontSize);
            tvDuaReference.setTextSize(prefOtherFontSize);
        }
    }

    // Return the size of your itemsData (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDuaData == null ? 0 : mDuaData.size();
    }

可以在Github上查看适配器的完整代码。

以下是错误的logcat报告:

12-06 12:01:08.288 7104-7135/com.khalid.hisnulmuslim D/OpenGLRenderer: endAllStagingAnimators on 0x67b72220 (RippleDrawable) with handle 0x67b3ad40
12-06 12:01:08.288 7104-7135/com.khalid.hisnulmuslim D/OpenGLRenderer: endAllStagingAnimators on 0x7e596df8 (ListView) with handle 0x67b3ad28
12-06 12:01:08.308 7104-7104/com.khalid.hisnulmuslim I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@10886dfe time:55529721
12-06 12:01:10.968 7104-7104/com.khalid.hisnulmuslim D/K12_isFav: isFav: false
12-06 12:01:10.968 7104-7104/com.khalid.hisnulmuslim D/K12_sqlPosition: 3
12-06 12:01:10.978 7104-7104/com.khalid.hisnulmuslim D/K12_selectionArgs: tvDuaNumber: 3
12-06 12:01:12.573 7104-7104/com.khalid.hisnulmuslim D/K12_isFav: isFav: false
12-06 12:01:12.573 7104-7104/com.khalid.hisnulmuslim D/K12_sqlPosition: 1
12-06 12:01:12.583 7104-7104/com.khalid.hisnulmuslim D/K12_selectionArgs: tvDuaNumber: 1
12-06 12:01:14.228 7104-7104/com.khalid.hisnulmuslim D/K12_isFav: isFav: false
12-06 12:01:14.228 7104-7104/com.khalid.hisnulmuslim D/K12_sqlPosition: 4
12-06 12:01:14.228 7104-7104/com.khalid.hisnulmuslim D/AndroidRuntime: Shutting down VM
12-06 12:01:14.233 7104-7104/com.khalid.hisnulmuslim E/AndroidRuntime: FATAL EXCEPTION: main
                                                                       Process: com.khalid.hisnulmuslim, PID: 7104
                                                                       java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
                                                                           at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
                                                                           at java.util.ArrayList.remove(ArrayList.java:403)
                                                                           at com.khalid.hisnulmuslim.adapter.BookmarksDetailRecycleAdapter.deleteRow(BookmarksDetailRecycleAdapter.java:90)
                                                                           at com.khalid.hisnulmuslim.adapter.BookmarksDetailRecycleAdapter$2.onClick(BookmarksDetailRecycleAdapter.java:160)
                                                                           at android.view.View.performClick(View.java:4789)
                                                                           at android.view.View$PerformClick.run(View.java:19881)
                                                                           at android.os.Handler.handleCallback(Handler.java:739)
                                                                           at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                           at android.os.Looper.loop(Looper.java:135)
                                                                           at android.app.ActivityThread.main(ActivityThread.java:5294)
                                                                           at java.lang.reflect.Method.invoke(Native Method)
                                                                           at java.lang.reflect.Method.invoke(Method.java:372)
                                                                           at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
                                                                           at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
                                                                           at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:114)

我一直试图解决这个问题,但我真的不知道问题是什么。将不胜感激任何帮助。

感谢。

1 个答案:

答案 0 :(得分:0)

有关onBindViewHolder

的文档
  

请注意,与ListView不同,RecyclerView不会调用此方法   再次,如果项目的位置在数据集中发生变化,除非   项目本身无效或无法确定新职位。   因此,您应该只使用position参数   获取此方法中的相关数据项,不应保留   它的副本。 如果您稍后需要某个项目的位置(例如,在   点击监听器),使用将更新的getAdapterPosition()   适配器位置。

clicklisteners构造函数中设置ViewHolder,可能不在onBindViewHolder内。

例如。

public class ViewHolder implements View.OnClickListener {
   //member view variables
   private Button mButton;
   public ViewHolder(View v) {
     //findByViewId calls
     super(v);
     mButton = (Button) v.findViewById(R.id.button);
     mButton.setOnClickListener(this);
   }

   @Override
   public void onClick(View v) {
     switch(v.getId()) {
        case R.id.button:
           int position = getAdapterPosition();
           //do stuff

           break;
   }
}