我目前正在处理我的项目,RecyclerViewer
Java类文件中遇到了一些麻烦,每次我单击完整按钮时,都将代码((Activity)itemView.getContext()).finish();
放入它时,它会强制关闭应用程序。怎么解决呢?当我单击完成按钮时,它将完成活动,然后重新加载活动。
这是我的代码:
package com.example.asus.hatidtubigandriversapp.adapter;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.asus.hatidtubigandriversapp.DeliveryListActivity;
import com.example.asus.hatidtubigandriversapp.R;
import com.example.asus.hatidtubigandriversapp.http.HttpHelper;
import com.example.asus.hatidtubigandriversapp.http.UrlList;
import java.util.ArrayList;
import java.util.List;
public class DeliveryListHelper extends RecyclerView.Adapter<DeliveryListHelper.ViewHolder> {
private List<Integer> id = new ArrayList<>();
private List<String> customer = new ArrayList<>();
private List<String> qty = new ArrayList<>();
private List<String> type = new ArrayList<>();
private List<String> address = new ArrayList<>();
public DeliveryListHelper(List<Integer> id, List<String> customer, List<String> qty, List<String> type, List<String> address) {
this.id = id;
this.customer = customer;
this.qty = qty;
this.type = type;
this.address = address;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View getView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_list_delivery, viewGroup, false);
ViewHolder viewHolder = new ViewHolder(getView);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
viewHolder.itemId = this.id.get(i);
viewHolder.tCustomer.setText(this.customer.get(i));
viewHolder.tOrderQty.setText(this.qty.get(i));
viewHolder.tWaterType.setText(this.type.get(i));
viewHolder.tAddress.setText(this.address.get(i));
}
@Override
public int getItemCount() {
return this.id.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
int itemId = 0;
TextView tCustomer, tOrderQty, tWaterType, tAddress;
Button btnCompelete;
public ViewHolder(@NonNull final View itemView) {
super(itemView);
tCustomer = (TextView) itemView.findViewById(R.id.tCustomer);
tOrderQty = (TextView) itemView.findViewById(R.id.tOrderQty);
tWaterType = (TextView) itemView.findViewById(R.id.tType);
tAddress = (TextView) itemView.findViewById(R.id.tAddress);
btnCompelete = (Button) itemView.findViewById(R.id.btnComplete);
btnCompelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String endpoint = UrlList.main_url + "type=completedeliver&id=" + String.valueOf(itemId);
new DeliveryListHelper.CompleteDeliver(itemView.getContext()).execute(endpoint);
itemView.getContext().startActivity(new Intent(itemView.getContext(), DeliveryListActivity.class));
((Activity)itemView.getContext()).finish(); `// and here i put this finish`
}
});
}
}
public class CompleteDeliver extends AsyncTask<String, Void, String> {
ProgressDialog pd;
private Context context;
public CompleteDeliver(Context context) {
this.context = context;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
pd = new ProgressDialog(this.context);
pd.setMessage("Completing...");
pd.setCancelable(false);
pd.show();
}
@Override
protected void onPostExecute(String result) {
pd.dismiss();
getResult(result);
}
@Override
protected String doInBackground(String... url) {
HttpHelper httpHelper = new HttpHelper(this.context);
return httpHelper.httpConnect(url[0]);
}
private void getResult(String result) {
Toast.makeText(this.context,
result,
Toast.LENGTH_SHORT).show();
}
}
}
答案 0 :(得分:0)
正如评论所建议的那样,您想取出.finish()
并想在适配器上调用.notifyDataSetChanged()
。
答案 1 :(得分:0)
这将很长,但是我建议您遵循更传统的方法,将Adapter与Activity(如果需要)和ViewHolder与Adapter分离。即使您从未在其他地方重复使用它们。
这是什么意思,而不是依靠ViewHolder来获取活动,而是为您的viewHolder提供回调。顺便说一下,itemView.getContext()
不一定是一项活动; itemView是View
,因此,它的上下文不一定需要是Activity
,在假设它时要小心。
现在您执行此操作:
Activity->Adapter->ViewHolder->try to cast context to Activity and do things
我要做的是:
View#onClickListener()
分配给您要触发操作的按钮/视图/小部件。onClickListener
中,您可以将适配器传递给您的监听器(可能带有单击视图的getAdapterPosition()
)称为侦听器。 为什么要选择更复杂的路由?
您应该尽量使事物解耦;您的解决方案是通过尝试做不属于自己的事情来与框架作斗争。
您已经亲身体验了为什么ViewHolder在运行后台操作上不好;它不是为它创建/设计的。 它真的不知道(也不应该)开始活动。
适配器...适配器就是这样,它“适应”以一种格式(您的列表)出现的数据,以供某人(RecyclerView)使用。适配器是中间对象,它会与RecyclerView对话并为其提供实际视图,并在数据源(列表)和所述视图之间(通过ViewHolders)绑定数据,同时有效地缓存/重用有关意见;它当然不知道活动,也不必。
另一方面,活动/片段在上下文艺术中很精通。他们本身就是一个人,或者有能力完美地获得一个。 (注意:正如您通过itemView.getContext()所知,视图持有者也可以获取上下文),但是此上下文仅应用于“查看事物”。即,获取资源(字符串,颜色,可绘制对象),获取主题值等。不要替换(或更糟糕的是,跳过组件之间的正确通信)。
这在实践中看起来有多复杂?
我将发布一个简单的示例,并在适用的情况下主要使用伪代码。
(我将在下面解释这些内容)
在您的适配器中,添加以下内容:
// This is the interface to pass to the adapter
interface OnItemClickedListener {
void onCompleteDeliver(int itemId);
}
在您的ViewHolder中,添加以下内容:
// This is the interface to pass to the ViewHolders. (put this in your ViewHolder, it makes it cleaner).
interface OnClickListener {
void onCompleteClicked(int position);
}
让我们开始修改您的活动。
您需要为视图充气,然后创建适配器并将其设置为RecyclerView。这是活动的工作,而您已经在做。
但是现在您已经定义了两个接口,请修改您的活动:
recyclerView = findViewById(…);
Adapter adapter = new Adapter(…);
// THIS IS NEW
adapter.setItemClickListener(itemId -> {
String endpoint = UrlList.main_url + "type=completedeliver&id=" + String.valueOf(itemId);
new DeliveryListHelper.CompleteDeliver(getContext()).execute(endpoint);
// that’s it, when the AsyncTask is done, you can finish or whatever is that you wanted to do. You are in an activity anyway.
});
recyclerView.setAdapter(adapter);
到目前为止,很好,我们只添加了怪异的setItemClickListener ...
现在在您的适配器中,添加上述方法,如下所示:
void setCompleteListener(OnItemClickedListener listener) {
this.listener = listener; // save it, you will need it!
}
作为避免创建N个此类匿名类的好方法,通常最好只创建一个。因此在适配器中添加一个字段:
private ViewHolder.OnClickListener onClickListener;
此字段的类型是上面在ViewHolder内部定义的接口类型。
然后在您的onCreateViewHolder(仍在适配器内!)中进行延迟创建:
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View getView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_list_delivery, viewGroup, false);
// Lazy create one, if it’s null, create it, otherwise, use it.
if (onClickListener == null) {
// note: the getItem(position) method is part of `ListAdapter`, if you are not using that, then you need to either create a similar way or access your data directly… like myList.get(position) or anywhere you store the object that is bound to this view holder. DataAdapter is very convenient :)
onClickListener = (position) -> listener. onCompleteClicked(getItem(position));
}
// Pass the internal click listener to the viewHolder
return new ViewHolder(getView, onClickListener); // need to modify VH to accept this… see below…
}
现在,我们来修改 ViewHolder :
向其中添加一个使用OnClickListener的构造函数:
ViewHolder(View itemView, OnClickListener listener) {
super(itemView);
this.listener = listener; //keep it
…
}
现在,我将要做的,而不是创建超过9000个View.OnClickListeners…,只需一个并重复使用它即可:
(仍在ViewHolder内部)
View.OnClickListener onViewClickedListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.onCompleteClicked(getAdapterPosition());
}
};
所有这些操作都是在单击时进行的,它将使用适配器本身的位置调用侦听器(请记住这是一个ViewHolder)。
通过这种方式,可以在任何位置重用此侦听器……因此,例如在ViewHolder构造函数中……在this.listener=listener
行下方
btnCompelete = (Button) itemView.findViewById(R.id.btnComplete);
btnCompelete.setOnClickListener(onViewClickedListener);
...
此时,图片或多或少完整。
如果从ViewHolder向后退:
OnClickListener
分配给按钮(或其他任何按钮)。OnItemClicked
(在构造时提供给您),然后执行listener.onCompleteClicked(getAdapterPosition());
onClickListener
上。这是同一实例,因为它通过参数接收受影响的(被点击的)排名(因此我们可以重复使用它!)。 onClickListener
,因此,当ViewHolder在此处传递事件时…适配器所需要做的就是从其数据源中获取项目…(即up2you…getItem(pos)
很方便ListAdapter<T>
的方法,但是如果使用 raw RecyclerView.Adapter<T>
,则通常会在适配器中保留要显示的项目列表……因此,请查询数据源/列表/无论如何,以获取对与单击的视图持有者绑定的项目的引用。我希望这篇漫长的(可能是错别字)文章能帮助您了解这种方法的优点。
是否还有更多代码? 是的。
调试起来更难吗? 可能,但不是真的。
这是最佳方式吗? 不太可能,但是它在多个项目中使用了这些方法(以及许多其他相似但不太相似的方法),却从未听到过任何不好的消息。
当然,您可能会想将其短路,而不是传递位置,而是传递商品的实际“ ID”,但是又为什么呢?适配器负责提供(并维护)每个列表“项目”与您的ViewHolder之间的关系,让他们完成工作。
另一方面,ViewHolder寿命短,可重复使用且笨拙;不要让它做无法控制的事情;想象您的情况,从ViewHolder触发一个异步任务需要1分钟。用户在那个时间滚动…ViewHolder被重用…地狱休息。
无论如何,祝您好运,并欢迎您使用Stack Overflow。