我们都知道,android中的View不是线程安全的,只有主线程/UI线程(主线程和UI是等同的)才能更新UI,否则会报错。runOnUIthread(Runnale)和Handler.post(Runnable)都是将更新UI的操作提交到主线程/UI线程中执行,很多人以为这两种方法是一样的,之前我也以为是一样的,而且为了方便,我也一直是使用runOnUIthread()这一个方法的,但是昨天在项目中解决的一个问题,让我有了不同的认识。
接下来跟大家讲下我的一个项目,其中涉及ScrollView嵌套RecyclerView的情况(不懂的可以忽略,类似于ScrollView嵌套ListView,之后有空会补上ScrollView嵌套ListView、RecyclerView的问题),即RecyclerView只能固定高度才能显示(ListView也一样),所以需要动态设置RecyclerView的高度:
动态设置View的高度先不多说了,就说通过接口回调机制动态更新这个RcyclerView的高度的时候,经本人实践,必须使用Handler.post(Runnable r)这种方法才能有效更新,使用RunOnUIThread(Runnable r)这种方法无效。
我去google了一下,原因是runOnUIThread()这个方法比较适合在异步线程之前去更新进度条之类的UI操作,在线程执行过程之中动态更新UI的方法最好还是选用Handler.post()这一种方法。
引:runOnUiThread
is basically suited to show a progress dialog or do some UI manipulations before an AsyncTask
call. If you want to update the UI in the middle of a thread execution, then the best approach is to create a Handler
which will update your UI, and let the thread continue running, for example, updating a text view periodically after a few sec, say timer functionality.
总之,使用runOnUiThread(Runnable r)和Handler.post(Runnable r)这两种方式去更新UI是有区别的,最好的方式是使用Handler,post()方法
不多说了,直接上代码:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> { private Context context; private List<String> list; private OnClickListener onClickListener; private Reset reset; public RecyclerViewAdapter(Context context) { this.context=context; } public void setList(List<String> list){ this.list=list; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView= LayoutInflater.from(context).inflate(R.layout.test) MyViewHolder holder=new MyViewHolder(itemView); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, final int position) { holder.textView.setText(list.get(position)); if(reset!=null){ //回调方法,返回Fragmeng中set RecyclerView的LayoutParams reset.resetHeight(holder.itemView); } holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(onClickListener!=null) { onClickListener.OnItemClick(position); } } }); } @Override public int getItemCount() { return list.size(); } class MyViewHolder extends RecyclerView.ViewHolder{ TextView textView; public MyViewHolder(View itemView) { super(itemView); textView=itemView.findViewById(R.id.tv_test); } } public interface OnClickListener{ public void OnItemClick(int position); } public void setOnClickListener(OnClickListener onClickListener){ this.onClickListener=onClickListener; } public interface Reset{ void resetHeight(View itemView); } public void setReset(Reset reset){ this.reset=reset; } }
在fragment中实现接口RecyclerAdapter.Reset,,实现该接口的resetHeight(View itemView)的方法
private RecyclerView recyclerView; private List<String> list; @Override public void resetHeight(View itemView) { int count=list.size(); itemView.measure(0,0); final ViewGroup.LayoutParams params=recyclerView.getLayoutParams(); params.height=count*itemView.getMeasuredHeight(); android.os.Handler handler=new android.os.Handler(); //第一种方法,是有效的 handler.post(new Runnable() { @Override public void run() { recyclerView.setLayoutParams(params); } }); //第二种方法,无效 getActivity().runOnUiThread(new Runnable() { @Override public void run() { recyclerView.setLayoutParams(params); } }); }