为什么 DBFlow 馈送的 RecyclerView 在 Marshmallow 中得到更新并且在 M 之前没有这样做?
Why does a DBFlow fed RecyclerView get updated in Marshmallow and fails to do so pre-M?
我正在尝试显示从 DBFlow (SQLite) 后端提供的 RecyclerView 列表。列表中的每个项目代表一个项目,一旦选择该项目将转换为详细信息 activity 视图。与任何 CursorLoader 一样,我希望每次支持视图的加载程序发生更改时,布局都会自行更新。
这在 Marshmallow 中测试时成立,但在 Lollipop 和 Jelly Bean (4.3)。在失败的情况下,单个项目会显示在列表中,尽管在调试器中看到 onBindViewHolder() 为每个项目调用一次(适当的数据到达光标,顺便说一句) .
以下是我认为涉及的主要内容。我特意简化了代码,如有必要,请随时索取更多详细信息:
onResume() 在显示列表的 activity 中覆盖:
@Override
protected void onResume() {
super.onResume();
getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle cursor) {
return BackendManager.getListCursorLoader(mContext);
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
int numItemsRetrieved = cursor.getCount();
if ((numItemsRetrieved == 1) {
Optional<Item> selectedItemOpt = BackendManager.getSingleItem();
if (selectedItemOpt.isPresent()) {
Item selectedItem = selectedItemOpt.get();
Intent t = new Intent(mContext, ItemDetailActivity.class);
Bundle b = new Bundle();
b.putSerializable("item", selectedItem);
it.putExtras(b);
startActivityForResult(it, SHOW_ITEM_DETAIL);
}
}
((ItemListRecyclerAdapter) mRecyclerListView.getAdapter()).swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
((ItemListRecyclerAdapter) mRecyclerListView.getAdapter()).swapCursor(null);
}
});
}
静态管理器中的 CursorLoader 生成:
public static CursorLoader getListCursorLoader(Context ctx) {
return new CursorLoader(
ctx, // Context
Item.CONTENT_URI, // Uri
null, // Projection
null, // Selection
null, // selectionArgs
null // sortOrder
);
}
RecyclerView 游标适配器。当前使用 skyfish's:
public class ItemListRecyclerAdapter extends CursorRecyclerViewAdapter<ItemListRecyclerAdapter.ViewHolder> {
private Context mContext;
public ItemListRecyclerAdapter(Context context, Cursor cursor) {
super(context, cursor);
mContext = context;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView itemText;
public ImageView itemImage;
public ViewHolder(View view) {
super(view);
itemText = (TextView) view.findViewById(R.id.itemTitle);
itemImage = (ImageView) view.findViewById(R.id.itemPicture);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_6_list_item, parent, false);
ViewHolder vh = new ViewHolder(itemView);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
// Find fields to populate in inflated template
String itemTextData = cursor.getString(cursor.getColumnIndex("itemText"));
viewHolder.itemText.setText(itemTextData);
// Force text fit
AutofitHelper afh = AutofitHelper.create(viewHolder.itemText);
afh.setMaxTextSize(TypedValue.COMPLEX_UNIT_SP, 22.0f);
String itemImageUrl = cursor.getString(cursor.getColumnIndex("logo"));
if ((itemImageUrl != null) && (!itemImageUrl.isEmpty())) {
Picasso.with(mContext)
.load(itemImageUrl)
.resize(300, 300)
.centerCrop()
.placeholder(R.drawable.placeholder)
.into(viewHolder.itemImage);
} else {
viewHolder.itemImage.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.placeholder));
}
}
}
如上所述,已通过以下方式进行测试和验证:
- Nexus 6 上的 Marshmallow (6.0.1):工作
- Galaxy S5 上的 Lollipop (5.0):不工作
- Galaxy S3 上的 Jelly Bean (4.3):不工作
我是不是漏掉了什么?关于进一步查看的任何提示?
由于没有任何答案,我将解释我最终做了什么来解决这个问题。
完全重写后,我摆脱了 skyfish 的 Cursor Adapter,并全力使用 Android 的 RecyclerView 界面。我没有使用 Cursor/Adapter 方案从 SQLite 后端提取数据并在对底层存储进行更改时交换游标,我只是启用了 get-all-items 静态方法在存储管理器中检索最新数据。为了在数据更改时更新列表,我使用了 DBFlow 的 Observables 来获得此类更改的通知。一旦检测到更改,我将使用 get-all-items 检索更新的数据,并相应地更新 RecyclerView 执行适当的 notifyItem() 调用动画布局更改。
不需要额外的依赖项或 Android 和 DBFlow 之外的代码。此方法已在原始问题中描述的所有设备中得到验证。
我正在尝试显示从 DBFlow (SQLite) 后端提供的 RecyclerView 列表。列表中的每个项目代表一个项目,一旦选择该项目将转换为详细信息 activity 视图。与任何 CursorLoader 一样,我希望每次支持视图的加载程序发生更改时,布局都会自行更新。
这在 Marshmallow 中测试时成立,但在 Lollipop 和 Jelly Bean (4.3)。在失败的情况下,单个项目会显示在列表中,尽管在调试器中看到 onBindViewHolder() 为每个项目调用一次(适当的数据到达光标,顺便说一句) .
以下是我认为涉及的主要内容。我特意简化了代码,如有必要,请随时索取更多详细信息:
onResume() 在显示列表的 activity 中覆盖:
@Override
protected void onResume() {
super.onResume();
getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle cursor) {
return BackendManager.getListCursorLoader(mContext);
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
int numItemsRetrieved = cursor.getCount();
if ((numItemsRetrieved == 1) {
Optional<Item> selectedItemOpt = BackendManager.getSingleItem();
if (selectedItemOpt.isPresent()) {
Item selectedItem = selectedItemOpt.get();
Intent t = new Intent(mContext, ItemDetailActivity.class);
Bundle b = new Bundle();
b.putSerializable("item", selectedItem);
it.putExtras(b);
startActivityForResult(it, SHOW_ITEM_DETAIL);
}
}
((ItemListRecyclerAdapter) mRecyclerListView.getAdapter()).swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
((ItemListRecyclerAdapter) mRecyclerListView.getAdapter()).swapCursor(null);
}
});
}
静态管理器中的 CursorLoader 生成:
public static CursorLoader getListCursorLoader(Context ctx) {
return new CursorLoader(
ctx, // Context
Item.CONTENT_URI, // Uri
null, // Projection
null, // Selection
null, // selectionArgs
null // sortOrder
);
}
RecyclerView 游标适配器。当前使用 skyfish's:
public class ItemListRecyclerAdapter extends CursorRecyclerViewAdapter<ItemListRecyclerAdapter.ViewHolder> {
private Context mContext;
public ItemListRecyclerAdapter(Context context, Cursor cursor) {
super(context, cursor);
mContext = context;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView itemText;
public ImageView itemImage;
public ViewHolder(View view) {
super(view);
itemText = (TextView) view.findViewById(R.id.itemTitle);
itemImage = (ImageView) view.findViewById(R.id.itemPicture);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_6_list_item, parent, false);
ViewHolder vh = new ViewHolder(itemView);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
// Find fields to populate in inflated template
String itemTextData = cursor.getString(cursor.getColumnIndex("itemText"));
viewHolder.itemText.setText(itemTextData);
// Force text fit
AutofitHelper afh = AutofitHelper.create(viewHolder.itemText);
afh.setMaxTextSize(TypedValue.COMPLEX_UNIT_SP, 22.0f);
String itemImageUrl = cursor.getString(cursor.getColumnIndex("logo"));
if ((itemImageUrl != null) && (!itemImageUrl.isEmpty())) {
Picasso.with(mContext)
.load(itemImageUrl)
.resize(300, 300)
.centerCrop()
.placeholder(R.drawable.placeholder)
.into(viewHolder.itemImage);
} else {
viewHolder.itemImage.setImageDrawable(ContextCompat.getDrawable(mContext, R.drawable.placeholder));
}
}
}
如上所述,已通过以下方式进行测试和验证:
- Nexus 6 上的 Marshmallow (6.0.1):工作
- Galaxy S5 上的 Lollipop (5.0):不工作
- Galaxy S3 上的 Jelly Bean (4.3):不工作
我是不是漏掉了什么?关于进一步查看的任何提示?
由于没有任何答案,我将解释我最终做了什么来解决这个问题。
完全重写后,我摆脱了 skyfish 的 Cursor Adapter,并全力使用 Android 的 RecyclerView 界面。我没有使用 Cursor/Adapter 方案从 SQLite 后端提取数据并在对底层存储进行更改时交换游标,我只是启用了 get-all-items 静态方法在存储管理器中检索最新数据。为了在数据更改时更新列表,我使用了 DBFlow 的 Observables 来获得此类更改的通知。一旦检测到更改,我将使用 get-all-items 检索更新的数据,并相应地更新 RecyclerView 执行适当的 notifyItem() 调用动画布局更改。
不需要额外的依赖项或 Android 和 DBFlow 之外的代码。此方法已在原始问题中描述的所有设备中得到验证。