问题
Ok I'll try one more time. Last time I asked about passing data between recyclerview and item and one person helped me with open item by click, but I still don't have idea how to show the data of clicked item in new activity. I want to click on an item and then display the data of that item in new activity. In this activity I want to edit data. Does anyone knows how to do it? I need any idea.
RecyclerView Adapter with OnItemClickListener interface:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {
private List<MainViewModel> mTasks;
private List<Task> tasks = new ArrayList<>();
private Context context;
private EditTaskViewModel editTaskViewModel;
public RecyclerViewAdapter(List<MainViewModel> tasks, Context context, EditTaskViewModel editTaskViewModel) {
this.mTasks = tasks;
this.context = context;
this.editTaskViewModel = editTaskViewModel;
}
@NonNull
@Override
public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
final RecyclerViewItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.recycler_view_item, parent, false);
binding.setItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(View view) {
Intent intent = new Intent(view.getContext(), EditTaskActivity.class);
intent.putExtra("id", binding.getPosition());
view.getContext().startActivity(intent);
Toast.makeText(view.getContext(), "ID " + binding.getPosition(), Toast.LENGTH_SHORT).show();
}
});
return new TaskViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
Task currentTask = tasks.get(position);
holder.mBinding.descriptionItem.setText(currentTask.getDescription());
holder.mBinding.dateItem.setText(currentTask.getDate());
holder.mBinding.timeItem.setText(currentTask.getTime());
holder.mBinding.setPosition(position);
}
@Override
public int getItemCount() {
return tasks.size();
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
notifyDataSetChanged();
}
public Task getTaskPosition(int position) {
return tasks.get(position);
}
public class TaskViewHolder extends RecyclerView.ViewHolder {
private final RecyclerViewItemBinding mBinding;
public TaskViewHolder(RecyclerViewItemBinding binding) {
super(binding.getRoot());
this.mBinding = binding;
}
public void bind (MainViewModel mainViewModel){
mBinding.setItemView(mainViewModel);
mBinding.executePendingBindings();
}
}
public interface OnItemClickListener {
void onItemClick(View view);
}
Item XML file:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="itemView"
type="com.example.daniellachacz.taskmvvm.viewmodel.MainViewModel">
</variable>
<variable
name="itemClickListener"
type="com.example.daniellachacz.taskmvvm.adapter.RecyclerViewAdapter.OnItemClickListener">
</variable>
<variable
name="task"
type="com.example.daniellachacz.taskmvvm.model.Task">
</variable>
<variable
name="position"
type="int">
</variable>
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:shadowColor="@color/colorPrimary"
android:backgroundTint="@color/cardview_shadow_end_color">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="110dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:onClick="@{(view)-> itemClickListener.onItemClick(view)}">
<TextView
android:id="@+id/description_item"
android:layout_width="250dp"
android:layout_height="96dp"
android:layout_marginStart="5dp"
android:layout_marginTop="9dp"
android:layout_marginBottom="5dp"
android:text="@{itemView.description}"
android:textSize="18sp"
android:textColor="#020202"
android:focusable="true" />
<TextView
android:id="@+id/date_item"
android:layout_width="90dp"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="9dp"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{itemView.date}"
android:textColor="#020202"
android:textSize="16sp" />
<TextView
android:id="@+id/time_item"
android:layout_width="90dp"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_alignStart="@+id/date_item"
android:layout_marginBottom="10dp"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{itemView.time}"
android:textColor="#020202"
android:textSize="16sp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</layout>
onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
floatingActionButton = findViewById(R.id.floating_action_button);
List<Task> tasks = new ArrayList<>();
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(context, tasks);
recyclerView.setAdapter(recyclerViewAdapter);
mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
mainViewModel.getAllTasks().observe(this, recyclerViewAdapter::setTasks);
回答1:
Here are a couple of suggestions you might find useful:
Don't depend on ViewModel
s in your adapters. ViewModel
s are meant to handle events from views (Fragments or Activities) and broadcast updates back to the views via some observable mechanism (most commonly LiveData
instances). Referencing your ViewModel
s directly inside an adapter is bad, since it couples them together. This means that it will be very hard for you to reuse your adapter with a different ViewModel
if needed. I know it doesn't seem likely at this point in time, but just trust me on this one. After the changes have been applied, your adapter should look something like this:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.TaskViewHolder> {
private LayoutInflater mLayoutInflater;
private List<Task> mTasks;
private OnItemClickListener mOnItemClickListener;
public RecyclerViewAdapter(@NonNull Context context, @NonNull List<Task> tasks) {
mLayoutInflater = LayoutInflater.fromContext(context);
mTasks = tasks;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
@NonNull
@Override
public RecyclerViewAdapter.TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final RecyclerViewItemBinding binding = DataBindingUtil.inflate(mLayoutInflater, R.layout.recycler_view_item, parent, false);
return new TaskViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull final RecyclerViewAdapter.TaskViewHolder holder, final int position) {
Task currentTask = tasks.get(position);
holder.bind(currentTask, mOnItemClickListener);
}
@Override
public int getItemCount() {
return tasks.size();
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
notifyDataSetChanged();
}
public Task getTaskPosition(int position) {
return tasks.get(position);
}
public class TaskViewHolder extends RecyclerView.ViewHolder {
private final RecyclerViewItemBinding mBinding;
public TaskViewHolder(RecyclerViewItemBinding binding) {
super(binding.getRoot());
this.mBinding = binding;
}
public void bind (Task item, OnItemClickListener onItemClickListener) {
mBinding.setItem(item);
mBinding.executePendingBindings();
itemView.setOnClickListener(view -> {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(view, item);
}
}
}
}
public interface OnItemClickListener {
void onItemClick(View view, Task item);
}
}
The OnItemClickListener.onItemClick()
method now passes the view and the item itself as parameters. This is the easiest way to expose the clicked item to whoever might be interested. The on click listener is not set at the adapter level, using setOnItemClickListener()
.
The setting of the OnClickListener
of the item view is now done in the bind()
method of the TaskViewHolder
. When binding, we know the exact item that is going to populate the view, so we can return it to the OnItemClickListener
.
You have to simplify the layout as well, since there are a lot of things that are not really needed. It may look like this:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="task"
type="com.example.daniellachacz.taskmvvm.model.Task">
</variable>
</data>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="120dp"
android:shadowColor="@color/colorPrimary"
android:backgroundTint="@color/cardview_shadow_end_color">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="110dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp">
<TextView
android:id="@+id/description_item"
android:layout_width="250dp"
android:layout_height="96dp"
android:layout_marginStart="5dp"
android:layout_marginTop="9dp"
android:layout_marginBottom="5dp"
android:text="@{item.description}"
android:textSize="18sp"
android:textColor="#020202"
android:focusable="true" />
<TextView
android:id="@+id/date_item"
android:layout_width="90dp"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="9dp"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{item.date}"
android:textColor="#020202"
android:textSize="16sp" />
<TextView
android:id="@+id/time_item"
android:layout_width="90dp"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_alignStart="@+id/date_item"
android:layout_marginBottom="10dp"
android:layout_marginEnd="10dp"
android:gravity="center"
android:text="@{item.time}"
android:textColor="#020202"
android:textSize="16sp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
</layout>
The only variable is the item
and we are binding it's properties to the TextView
s.
I guess this should be enough to get you going.
Just a couple of other things that are not directly related to the question, but are important.
- Null safety - you never check the input when calling
setTask()
in the adapter. A client may passnull
and cause crashes all over the place. You should try and prevent that. - Calling
notifyDataSetChanged()
is not a good practice when working withRecyclerView.Adapter
since this will cancel all the built-in animations of theRecyclerView
. It's better to use the othernotify...
methods. You might want to checkDiffUtil
at some point.
回答2:
It depends on how your data is stored and if it accessible in the second activity. If you have a static ArrayList of your data you can pull the data from it using the index you passed in your onclick of the RV item. For example:
class myData{
private ArrayList<Data> myDataArray;
static ArrayList<Data> getMyDataArray(){
return myDataArray;
}
static void setMyDataArray(array)
myDataArray = array;
}
So you fill your RV with getMyDataArray() then you set the onlclick to send the index clicked in the RV to the next activity. In onLoad of the second activity:
int myDataIndex = getIntent().getIntExtra("id",0);
Data myData = myData.getMyDataArray().get(myDataIndex);
Note: Data is whatever your data is, could be strings, or ints, or a custom class/object with data.
回答3:
Here is what I have done for item click listener in recycler view using data binding.
ADAPTER CODE
public class TC_DashboardRecViewAdapter extends RecyclerView.Adapter<TC_DashboardRecViewAdapter.ViewHolder> {
Context context;
List<String> list;
private TcDashboardItemBinding tcDashboardItemBinding;
ItemClickListener itemClickListener;
public TC_DashboardRecViewAdapter(Context context, List<String> dashboardItems, ItemClickListener itemClickListener) {
this.context = context;
this.list = dashboardItems;
this.itemClickListener = itemClickListener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
ViewDataBinding binding = DataBindingUtil.inflate(inflater, R.layout.tc_dashboard_item, parent, false);
tcDashboardItemBinding = (TcDashboardItemBinding) parent.getTag();
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.bind(list.get(position), itemClickListener, position);
}
@Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
private ViewDataBinding binding;
public ViewHolder(ViewDataBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
public void bind(String s, ItemClickListener itemClickListener, int position) {
this.binding.setVariable(BR.itemModel, s);
this.binding.executePendingBindings();
binding.getRoot().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(itemClickListener !=null){
itemClickListener.onItemClicked(binding.getRoot(), s, position);
}
}
});
}
}
ITEM CLICK INTERFACE:
public interface ItemClickListener {
void onItemClicked(View vh, Object item, int pos);
}
FRAGMENT/ACTIVITY CODE:
public class TC_DashboardFragment extends BaseFragment implements ItemClickListener {
public void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
tc_dashboardRecViewAdapter = new TC_DashboardRecViewAdapter(getContext(), getDashboardItems(), this);
linearLayoutManager = new LinearLayoutManager(getContext());
dashboardrecyclerview.setLayoutManager(new LinearLayoutManager(getContext()));
binding.setAdapter(tc_dashboardRecViewAdapter);
}
@Override
public void onItemClicked(View vh, Object item, int pos) {
Toast.makeText(mainActivity, item.toString(), Toast.LENGTH_SHORT).show();
}
When you run the code and click on recycler view item it would show a toast with the text from the item clicked.
来源:https://stackoverflow.com/questions/53233354/databinding-recyclerview-and-onclick