Android:RecyclerView 项目的 onClick() 在另一个 activity 调用 finish() 后无意中激活(由该 RecyclerView 启动)
Android: RecyclerView item's onClick() unintentionally activated after call to finish() by another activity (which was started by that RecyclerView)
我创建了一个带有 RecyclerView 的 "ListItemActivity",其中显示了与我的项目 class 实例关联的图像。
这些图像上有一个 onClick 方法,可以打开另一个 "ItemDetailActivity" 显示有关该特定项目的更多详细信息。
在 "ItemListActivity" 中有一个浮动操作按钮,它启动 "ItemAddActivity" 以添加新项目。当用户在此 activity 中并添加一个新项目时,他们单击一个调用 finish() 和 returns 的按钮到 "ListItemActivity".
一切正常,除了:
在 "ItemAddActivity" 中添加新项目并调用 finish() 后,我们返回到 "ItemListActivity",有时(通常情况下)似乎"ItemListActivity" 的 RecyclerView 中看似随机的图像被激活。
我不确定这是否与单击 "ItemAddActivity" 按钮本身有关,或者我不知道的 RecyclerView 的某些功能、finish() 的使用或 . .. ?
如果您需要更多信息或代码,请告诉我。
"ItemListActivity":
public class ItemListActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ClosetSampleViewModel mViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mRecyclerView = findViewById(R.id.item_list_rv);
final ItemListAdapter adapter = new ItemListAdapter(this);
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL));
mViewModel = ViewModelProviders.of(this).get(ClosetSampleViewModel.class);
mViewModel.getAllItems().observe(this, new Observer<List<Item>>() {
@Override
public void onChanged(@Nullable List<Item> items) {
adapter.setItems(items);
}
});
}
public void addItem(View view) {
Intent intent = new Intent(this, ItemAddActivity.class);
startActivity(intent);
}
public void viewItemDetail(View view) {
final int itemPosition = mRecyclerView.getChildLayoutPosition(view);
mViewModel.getAllItems().observe(this, new Observer<List<Item>>() {
@Override
public void onChanged(@Nullable List<Item> items) {
Item item = items.get(itemPosition);
Intent intent = new Intent(getApplicationContext(), ItemDetailActivity.class);
intent.putExtra("itemId", item.getId());
startActivity(intent);
}
});
}
}
"ItemListAdapter":
public class ItemListAdapter extends RecyclerView.Adapter<ItemListAdapter.ItemViewHolder> {
private final LayoutInflater mInflater;
private List<Item> mItems;
public ItemListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.item_list_rv_item, parent, false);
return new ItemViewHolder(itemView);
}
@Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
if (mItems != null) {
Item currentItem = mItems.get(position);
String uriString = "none";
if (currentItem.getImageUri() != null) {
uriString = currentItem.getImageUri().toString();
// TODO
GlideApp.with(holder.pictureImageView.getContext()).load(uriString).placeholder(R.color.colorPrimaryDark).dontTransform().into(holder.pictureImageView);
} else {
holder.pictureImageView.setVisibility(View.INVISIBLE);
}
} else {
// TODO: data not ready yet.
}
}
public void setItems(List<Item> items) {
mItems = items;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return mItems == null ? 0 : mItems.size();
}
class ItemViewHolder extends RecyclerView.ViewHolder {
private final ImageView pictureImageView;
private ItemViewHolder(View itemView) {
super(itemView);
pictureImageView = itemView.findViewById(R.id.item_list_rv_image);
}
}
}
RecyclerView 项目的布局:
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_list_rv_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:adjustViewBounds="true"
android:padding="5dp"
android:layout_margin="3dp"
android:onClick="viewItemDetail" />
"ItemListActivity" 的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemListActivity">
<!-- Load the toolbar here -->
<android.support.v7.widget.RecyclerView
android:id="@+id/item_list_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/item_list_rv_item"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/item_list_fab"
app:fabSize="normal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_add_white_24dp"
android:background="@color/colorAccent"
android:onClick="addItem" />
</android.support.design.widget.CoordinatorLayout>
相关代码来自"ItemAddActivity":
public void onAddItemClicked(View view) {
if (currentPhotoPath == null) {
Toast.makeText(this, "Can't add item without image.", Toast.LENGTH_LONG).show();
} else {
final String itemName = itemNameEditText.getText().toString();
final String itemDescription = itemDescriptionEditText.getText().toString();
// Image set for this Item.
final Uri imageUri = Uri.parse(currentPhotoPath);
// Set the photo path to null in the shared prefs so we don't accidently delete it next time.
SharedPreferences prefs = getApplicationContext().getSharedPreferences(ITEM_IMAGE_SHARED_PREFS_FILE, MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putString(PREF_PHOTO_PATH, null);
prefsEditor.apply();
if (itemCategorySpinner.getSelectedItemPosition() >= 0) {
mViewModel.getAllCategories().observe(this, new Observer<List<Category>>() {
@Override
public void onChanged(@Nullable List<Category> categories) {
addItem(new Item(itemName, itemDescription, imageUri, categories.get(itemCategorySpinner.getSelectedItemPosition())));
}
});
} else {
addItem(new Item(itemName, itemDescription, imageUri, null));
}
}
}
private void addItem(Item item) {
mViewModel.insertItem(item);
finish();
}
"ItemAddActivity" 的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemAddActivity">
<!-- Load the toolbar here -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<EditText
android:id="@+id/item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:importantForAutofill="no"
android:hint="@string/item_name" />
<EditText
android:id="@+id/item_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:importantForAutofill="no"
android:hint="@string/item_description" />
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/item_category_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/take_photo_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/take_photo"
android:onClick="onTakePhotoClicked" />
<Button
android:id="@+id/add_item_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_item"
android:onClick="onAddItemClicked"/>
<ImageView
android:id="@+id/item_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
截图:
ItemListActivity
ItemAddActivity
我一直在为这个绞尽脑汁,我想不通这是怎么回事。如果缺少什么,请告诉我。我在使格式正常工作时遇到了很多麻烦。
非常非常感谢。
viewItemDetail 方法看起来很奇怪。第一次单击后,您已经注册了一个观察者,因此只要有新项目可用,它就会启动 ItemDetailActivity。为什么要注册一个观察者来启动activity。您获得了获取项目的索引。从回收者视图中获取适配器,然后使用索引获取项目,然后使用 itemid 触发一个 intent。
我创建了一个带有 RecyclerView 的 "ListItemActivity",其中显示了与我的项目 class 实例关联的图像。
这些图像上有一个 onClick 方法,可以打开另一个 "ItemDetailActivity" 显示有关该特定项目的更多详细信息。
在 "ItemListActivity" 中有一个浮动操作按钮,它启动 "ItemAddActivity" 以添加新项目。当用户在此 activity 中并添加一个新项目时,他们单击一个调用 finish() 和 returns 的按钮到 "ListItemActivity".
一切正常,除了:
在 "ItemAddActivity" 中添加新项目并调用 finish() 后,我们返回到 "ItemListActivity",有时(通常情况下)似乎"ItemListActivity" 的 RecyclerView 中看似随机的图像被激活。
我不确定这是否与单击 "ItemAddActivity" 按钮本身有关,或者我不知道的 RecyclerView 的某些功能、finish() 的使用或 . .. ?
如果您需要更多信息或代码,请告诉我。
"ItemListActivity":
public class ItemListActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private ClosetSampleViewModel mViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mRecyclerView = findViewById(R.id.item_list_rv);
final ItemListAdapter adapter = new ItemListAdapter(this);
mRecyclerView.setAdapter(adapter);
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, LinearLayoutManager.VERTICAL));
mViewModel = ViewModelProviders.of(this).get(ClosetSampleViewModel.class);
mViewModel.getAllItems().observe(this, new Observer<List<Item>>() {
@Override
public void onChanged(@Nullable List<Item> items) {
adapter.setItems(items);
}
});
}
public void addItem(View view) {
Intent intent = new Intent(this, ItemAddActivity.class);
startActivity(intent);
}
public void viewItemDetail(View view) {
final int itemPosition = mRecyclerView.getChildLayoutPosition(view);
mViewModel.getAllItems().observe(this, new Observer<List<Item>>() {
@Override
public void onChanged(@Nullable List<Item> items) {
Item item = items.get(itemPosition);
Intent intent = new Intent(getApplicationContext(), ItemDetailActivity.class);
intent.putExtra("itemId", item.getId());
startActivity(intent);
}
});
}
}
"ItemListAdapter":
public class ItemListAdapter extends RecyclerView.Adapter<ItemListAdapter.ItemViewHolder> {
private final LayoutInflater mInflater;
private List<Item> mItems;
public ItemListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
@Override
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = mInflater.inflate(R.layout.item_list_rv_item, parent, false);
return new ItemViewHolder(itemView);
}
@Override
public void onBindViewHolder(ItemViewHolder holder, int position) {
if (mItems != null) {
Item currentItem = mItems.get(position);
String uriString = "none";
if (currentItem.getImageUri() != null) {
uriString = currentItem.getImageUri().toString();
// TODO
GlideApp.with(holder.pictureImageView.getContext()).load(uriString).placeholder(R.color.colorPrimaryDark).dontTransform().into(holder.pictureImageView);
} else {
holder.pictureImageView.setVisibility(View.INVISIBLE);
}
} else {
// TODO: data not ready yet.
}
}
public void setItems(List<Item> items) {
mItems = items;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return mItems == null ? 0 : mItems.size();
}
class ItemViewHolder extends RecyclerView.ViewHolder {
private final ImageView pictureImageView;
private ItemViewHolder(View itemView) {
super(itemView);
pictureImageView = itemView.findViewById(R.id.item_list_rv_image);
}
}
}
RecyclerView 项目的布局:
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/item_list_rv_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
android:adjustViewBounds="true"
android:padding="5dp"
android:layout_margin="3dp"
android:onClick="viewItemDetail" />
"ItemListActivity" 的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemListActivity">
<!-- Load the toolbar here -->
<android.support.v7.widget.RecyclerView
android:id="@+id/item_list_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/item_list_rv_item"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/item_list_fab"
app:fabSize="normal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_add_white_24dp"
android:background="@color/colorAccent"
android:onClick="addItem" />
</android.support.design.widget.CoordinatorLayout>
相关代码来自"ItemAddActivity":
public void onAddItemClicked(View view) {
if (currentPhotoPath == null) {
Toast.makeText(this, "Can't add item without image.", Toast.LENGTH_LONG).show();
} else {
final String itemName = itemNameEditText.getText().toString();
final String itemDescription = itemDescriptionEditText.getText().toString();
// Image set for this Item.
final Uri imageUri = Uri.parse(currentPhotoPath);
// Set the photo path to null in the shared prefs so we don't accidently delete it next time.
SharedPreferences prefs = getApplicationContext().getSharedPreferences(ITEM_IMAGE_SHARED_PREFS_FILE, MODE_PRIVATE);
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putString(PREF_PHOTO_PATH, null);
prefsEditor.apply();
if (itemCategorySpinner.getSelectedItemPosition() >= 0) {
mViewModel.getAllCategories().observe(this, new Observer<List<Category>>() {
@Override
public void onChanged(@Nullable List<Category> categories) {
addItem(new Item(itemName, itemDescription, imageUri, categories.get(itemCategorySpinner.getSelectedItemPosition())));
}
});
} else {
addItem(new Item(itemName, itemDescription, imageUri, null));
}
}
}
private void addItem(Item item) {
mViewModel.insertItem(item);
finish();
}
"ItemAddActivity" 的布局:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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_width="match_parent"
android:layout_height="match_parent"
tools:context=".ItemAddActivity">
<!-- Load the toolbar here -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<EditText
android:id="@+id/item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:importantForAutofill="no"
android:hint="@string/item_name" />
<EditText
android:id="@+id/item_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:importantForAutofill="no"
android:hint="@string/item_description" />
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/item_category_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/take_photo_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/take_photo"
android:onClick="onTakePhotoClicked" />
<Button
android:id="@+id/add_item_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_item"
android:onClick="onAddItemClicked"/>
<ImageView
android:id="@+id/item_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
截图: ItemListActivity ItemAddActivity
我一直在为这个绞尽脑汁,我想不通这是怎么回事。如果缺少什么,请告诉我。我在使格式正常工作时遇到了很多麻烦。
非常非常感谢。
viewItemDetail 方法看起来很奇怪。第一次单击后,您已经注册了一个观察者,因此只要有新项目可用,它就会启动 ItemDetailActivity。为什么要注册一个观察者来启动activity。您获得了获取项目的索引。从回收者视图中获取适配器,然后使用索引获取项目,然后使用 itemid 触发一个 intent。