【问题标题】:Converting Adapter onBindViewHolder itemView context to Class context with SQLite database使用 SQLite 数据库将适配器 onBindViewHolder itemView 上下文转换为类上下文
【发布时间】:2018-01-13 00:08:33
【问题描述】:

我有一个有效的回收视图:

public class MtbListAdapter extends RecyclerView.Adapter<MtbListAdapter.RecyclerViewHolder> implements Filterable {
private ArrayList<ApiObject> arrayList;
private ArrayList<ApiObject> arrayListFiltered;
private DatabaseHelper databaseHelper;

public MtbListAdapter(ArrayList<ApiObject> arrayList) {
    this.arrayList =arrayList;
    this.arrayListFiltered =arrayList;
}

@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_mtb, viewGroup, false);
    return new RecyclerViewHolder(view);
}

@Override
public void onBindViewHolder(RecyclerViewHolder recyclerViewHolder, int position){

    //load texts to card
    recyclerViewHolder.tv_name.setText(arrayListFiltered.get(position).getName());
    recyclerViewHolder.tv_length.setText(arrayListFiltered.get(position).getLength());

    //is card already saved?
    String s_identifier = arrayListFiltered.get(position).getId();
    databaseHelper = new DatabaseHelper(recyclerViewHolder.tv_name.getContext());
    boolean isSaved = databaseHelper.isSaved(s_identifier);

    if (isSaved) recyclerViewHolder.iv_isSaved.setVisibility(View.VISIBLE);
    else recyclerViewHolder.iv_isSaved.setVisibility(View.INVISIBLE);
}

onBindViewHolder 中,我检查该项目是否已保存,如果已保存,则在卡上放置一个“已保存”图像。我通过检查我的 SQLite 数据库中已经保存的项目的 ID 值来做到这一点。我担心的一件事是databaseHelper = new DatabaseHelper(recyclerViewHolder.tv_name.getContext()); 经常被调用。问题 1. 这是一个问题吗?

为了减轻我的顾虑,我尝试通过构造函数传递上下文并使 databaseHelper 成为类对象,但是无论我传递什么上下文都会导致我的 SQLite 数据库方法在 databaseHelper 类中崩溃。我尝试传递 Activity.this、应用程序上下文、基本上下文等。我只成功传递了 viewHolder 项上下文,如图所示。就像我说的代码作为书面作品,但我担心它很昂贵。

这是我试过的代码:

 public class MtbListAdapter extends RecyclerView.Adapter<MtbListAdapter.RecyclerViewHolder> implements Filterable {
    private Context context;
    private ArrayList<ApiObject> arrayList;
    private ArrayList<ApiObject> arrayListFiltered;
    private DatabaseHelper databaseHelper = new DatabaseHelper(context);

public MtbListAdapter(ArrayList<ApiObject> arrayList, Context context) {
    this.arrayList =arrayList;
    this.arrayListFiltered =arrayList;
    this.context =context;
}

@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_mtb, viewGroup, false);
    return new RecyclerViewHolder(view);
}

@Override
public void onBindViewHolder(RecyclerViewHolder recyclerViewHolder, int position){

    //load texts to card
    recyclerViewHolder.tv_name.setText(arrayListFiltered.get(position).getName());
    recyclerViewHolder.tv_length.setText(arrayListFiltered.get(position).getLength());

    //is card already saved?
    String s_identifier = arrayListFiltered.get(position).getId();
    boolean isSaved = databaseHelper.isSaved(s_identifier);

    if (isSaved) recyclerViewHolder.iv_isSaved.setVisibility(View.VISIBLE);
    else recyclerViewHolder.iv_isSaved.setVisibility(View.INVISIBLE);
}

这是我的 SQLite 方法:

 //returns true if is already saved
public boolean isSaved(String s) {
    SQLiteDatabase db = getReadableDatabase();
    String[] columns = new String[] {KEY_IDENTIFIER};
    String where = KEY_IDENTIFIER + " = ?";
    String[] whereArgs = new String[] {s};

    // select column_word from table where column_word = 's' limit 1;
    try (Cursor c = db.query(TABLE_NAME, columns, where, whereArgs, null, null, null, "1")){
        return c.moveToFirst();
    }
}

这是我的错误(我只收到通过构造函数传递上下文的代码)。否则一切正常。

java.lang.NullPointerException: 尝试调用虚拟方法 'android.database.sqlite.SQLiteDatabase android.content.Context.openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase$CursorFactory, android. database.DatabaseErrorHandler)' 在空对象引用上

【问题讨论】:

  • 能否请您显示您尝试的代码,以及您遇到的错误。
  • @cricket.... 已添加。如果您需要更多错误代码,请告诉我

标签: android sqlite android-recyclerview adapter android-context


【解决方案1】:

您可以通过构造函数包含 上下文,然后在构造函数中创建助手的实例。

例如而不是:-

public MtbListAdapter(ArrayList<ApiObject> arrayList) {
    this.arrayList =arrayList;
    this.arrayListFiltered =arrayList;
}

使用:-

public MtbListAdapter(Context context, ArrayList<ApiObject> arrayList) {
    this.arrayList =arrayList;
    this.arrayListFiltered =arrayList;
    databaseHelper = new DatabaseHelper(context);
}

并删除该行:-

    databaseHelper = new DatabaseHelper(recyclerViewHolder.tv_name.getContext());

我担心的一件事是 databaseHelper = new DatabaseHelper(recyclerViewHolder.tv_name.getContext());被称为 很多。问题 1. 这是一个问题吗?

这不是最好的方法,因为您正在重新构建实例。关于打开数据库,实际上不是在构造时完成,而是在调用getReableDatabasegetWriteableDatabase 时完成,这与调用isSaved 方法时所做的相同。 get????ableDatabase 旨在应对多次调用。所以,我相信没什么好担心的。

但是,您不会在 isSaved 方法中关闭光标。这应该引起关注,因为如果您打开了太多游标,则会发生异常。

你可能想改变:-

//returns true if is already saved
public boolean isSaved(String s) {
    SQLiteDatabase db = getReadableDatabase();
    String[] columns = new String[] {KEY_IDENTIFIER};
    String where = KEY_IDENTIFIER + " = ?";
    String[] whereArgs = new String[] {s};

    // select column_word from table where column_word = 's' limit 1;
    try (Cursor c = db.query(TABLE_NAME, columns, where, whereArgs, null, null, null, "1")){
        return c.moveToFirst();
    }
}

类似于:-

//returns true if is already saved
public boolean isSaved(String s) {
    boolean rv = false;
    SQLiteDatabase db = getReadableDatabase();
    String[] columns = new String[] {KEY_IDENTIFIER};
    String where = KEY_IDENTIFIER + " = ?";
    String[] whereArgs = new String[] {s};

    // select column_word from table where column_word = 's' limit 1;
    (Cursor c = db.query(TABLE_NAME, columns, where, whereArgs, null, null, null, "1"));
    if(c.moveToFirst) {
            rv = true;
    }
    c.close()
    return rv;
}

【讨论】:

  • 是的,我试过了。请再次查看问题。谢谢!
  • 那么您可能会将 null 传递给适配器。也许添加类似if (context == null) { Log.d("MTBLISTADPTR","Null passed to constructor"); } 的内容。此外,在isSaved 方法中。附言如果您不关闭光标,您很可能会遇到问题。大约 100 次,你会得到太多 DB 的打开异常(无法立即回忆起确切的消息错误)。
  • 刚刚更仔细地查看了您添加的新代码。您将数据库助手的实例创建为类变量。这是行不通的。您需要在构造函数中实例化databaseHelper。在类中声明 databaseHelper 即private DatabaseHelper databaseHelper;,然后在构造函数中使用databaseHelper = new DatabaseHelper(context);进行实例化
  • 这么好的答案。清晰明了。我希望我可以点击它 10 次。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
相关资源
最近更新 更多