RecyclerView.Adapter 中对应Fragment的回调

在Adapter中回调Fragment来更新UI
今天在工作中遇到这样一个问题:在Adapter中执行了异步任务,在更新UI的时候需要根据Fragment来回调,具体情况如下

首先看我们需要实现什么功能
在Content Subscriptions中我们有一个item1,我们通过异步任务取消item1的订阅:
存在一个item1在content subscriptions中
在我们取消订阅item1后我们理想中应该是这样:也就是把content subscription的这个linearlayout设置为不可见
取消订阅item1后应该的样子
** 但是其实实际中我们实现的是这样:**
实际的样子
从UI 来看"CONTENT SUBSCRIPTION"这一行字没有按照我们预想的那样消失,也就是在代码中没有把这个LinearLayout设置为不可见。我们必须重新进入这个界面以后"CONTENT SUBSCRIPTION"才会不可见。
问题出现了,我们需要的流程是这样:取消订阅item->content subscription消失,但是实际的流程却是这样:取消订阅item->重新打开界面->content subscription消失。
布局文件是这样的: 代码有删减,我们只关注Content Subscription这一块

<LinearLayout
	android:id="@+id/quota_detail_item_area"
	android:layout_marginTop="@dimen/margin_big"
	style="@style/div.vlist"
	android:visibility="gone">
	<TextView
		style="@style/v3.subtitle"
		android:paddingLeft="@dimen/margin_big"
		android:paddingRight="@dimen/margin_big"
		android:text="Content Subscription" />
	<android.support.v7.widget.CardView
		style="@style/v3.card.nopadding"
		android:layout_marginTop="@dimen/card_margin_top"
		android:layout_morginBottom="dimen/card_margin"
		android:layout_marginBottom="@dimen/card_margin_bottom"
		android:background="@color/white">
		<LinearLayout
			style="@style/div.vlist">
			<android.support.v7.widget.RecyclerView
			android:id="@+id/quota_detail_item_list"
			android:layout_width="match_parent"
			android:layout_height="wrap_content" />
		</LinearLayout>
	</android.support.v7.widget.CardView>
</LinearLayout>

那么为什么会出现这样的情况呢,我们去代码里看一看:在Adapter中我们通过一个异步任务来执行item的取消订阅操作,在这里就不放完整代码了,只放更新UI的代码。在Adapter.java中,我们在onPostExecute()中进行更新UI的操作(代码有删减,只显示和本文有关的部分):

public class VASAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private Context mContext;
private ArrayList<Item> mList;
public Adapter(Context context, ArrayList<Item> itemSubscriptions) {//Adapter构造函数
        mContext = context;
        mList = itemSubscriptions;
    }...
    class UnsubscribeTask extends AsyncTask<Void, Void, Boolean>{
 	 ...@Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            
            if (result) {
            	showSuccessfulDlg();
                mList.remove(mPosition); //移除这个item
                Adapter.this.notifyDataSetChanged(); // 提示更新mList

            } else {
                showFailDlg();
            }
        }
     }
}

在Fragment.java中我们这样设置适配器:

public class Fragment extends ToolbarFragment {
private boolean mHideItem;
private ArrayList<Item> mActiveItem;
private RecyclerView mItemList
private LinearLayout mItemArea;
mItemArea = mFragmentView.findViewById(R.id.quota_detail_item_area);//在这个fragment中找到content subscription所在的linearlayout
mItemList = mFragmentView.findViewById(R.id.quota_detail_item_list);


	public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
	...
	if (mActiveItem != null && mActiveItem.size() > 0) {// 如果订阅的item个数不是0,那么配置适配器
                        mItemList.setAdapter(new Adapter(getActivity(), mActiveItem));
                        hideItemQuota(false);
                        showLoadErrorView(false);
                    } else {//如果订阅的item个数是0,那么将linearlayout设置为不可见,但是取消订阅后的第一时间不会执行这一句,必须重新进入这个页面重新判断后才会执行
                        hideItemQuota(true);
                    }
    }...
    ...
   private void hideItemQuota(boolean hide) {
        mHideItem = hide;
        mItemArea.setVisibility(hide ? View.GONE : View.VISIBLE);
    }
}

hideItemQuota()就是设置content subscription这个linearlayout为不可见的函数。在代码中我们已经进行了对mActiveItem进行了判空操作,如果它mActiveItem为空,那么就把LinearLayout设置为不可见,但是为什么还是会出现而没有按照预想消失呢?
这是因为我们并没有在adapter的onPostExecute()中把Content Subscription即时更新为不可见, 所以导致item1消失后Content Subscription这个linearlayout仍然出现。虽然在fragment中对存放item的ArrayList进行了判空后对linearlayout设置了不可见。但是在取消订阅后的第一时间并不会执行这一句,必须重新进入这个界面,才会判断ArrayList是否为空然后执行else里面的hideItemQuota(true)这一句。那么应该如何解决这个问题呢?就是要把linearlayout设置为不可见加入在更新UI的操作中,但是有一个问题就是我们在adapter中是不能得到fragment的,那么我们应该怎么在adapter中监听fragment呢?答案是用回调函数,也就是adapter中回调fragment。下面介绍具体的代码。
1.在Adapter中添加回调函数:

    public interface ContentAdapterCallback {
        void onNoItem();
    }

2.在Adapter的构造函数和onPostExecute()中加上callback 参数:

public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private Context mContext;
private ArrayList<Item> mList;
private ContentAdapterCallback mItemAdapterCallback;
public interface ContentAdapterCallback {
void onNoItem();
	}
public Adapter(Context context, ArrayList<Item> itemSubscriptions, ContentAdapterCallback callback) {
        mContext = context;
        mList = itemSubscriptions;
        mItemAdapterCallback = callback;
	}...
	class UnsubscribeTask extends AsyncTask<Void, Void, Boolean> {
    @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);

            if (result) {
                showSuccessfulDlg();
                mList.remove(mPosition);//移除这个item
                Adapter.this.notifyDataSetChanged();// 提示更新mList
                if ((mList.size() == 0) && mItemAdapterCallback != null) {
                    mItemAdapterCallback.onNoItem();
                }
            } else {
                showFailDlg();
            }
   		}
   	}
}

3.在Fragment.java的setAdapter()中添加callback参数:

public class Fragment extends ToolbarFragment {
private RecyclerView mItemList;

public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
...
if (mActiveItem != null && mActiveItem.size() > 0) {
                       mItemList.setAdapter(new Adapter(getActivity(), mActiveItem, new Adapter.ContentAdapterCallback() {
                           @Override
                           public void onNoItem() {
                               hideItemQuota(true);
                           }
                       }));
                       hideItemQuota(false);
                       showLoadErrorView(false);
                   }
     }
     ...
     private void hideItemQuota(boolean hide) {
        mHideItem = hide;
        mItemArea.setVisibility(hide ? View.GONE : View.VISIBLE);
    }
}

这样的话就可以实现在执行了异步任务后实时更新UI,问题也就解决了。

好的,这是一个比较常见的需求,您可以按照以下步骤来实现: 1. 在您的RecyclerView adapter,定义一个接口,用于通知Activity哪个button被点击了,同时传递该按钮对应fragment类型。 2. 在Activity,实现该接口,并在回调方法根据传递的fragment类型,切换到对应fragment页面。 以下是具体的实现步骤: 1. 在RecyclerView adapter,定义一个接口,例如: ```java public interface OnButtonClickListener { void onButtonClicked(int position); } ``` 2. 在RecyclerView adapter,为每个按钮设置点击事件,并在点击事件调用该接口的回调方法,例如: ```java public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> { private OnButtonClickListener mListener; public void setOnButtonClickListener(OnButtonClickListener listener) { this.mListener = listener; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mListener != null) { mListener.onButtonClicked(position); } } }); } } ``` 3. 在Activity,实现该接口,并在回调方法根据传递的fragment类型,切换到对应fragment页面,例如: ```java public class MainActivity extends AppCompatActivity implements MyAdapter.OnButtonClickListener { private FragmentManager mFragmentManager; private Fragment mFragment1; private Fragment mFragment2; private Fragment mFragment3; private Fragment mFragment4; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFragmentManager = getSupportFragmentManager(); mFragment1 = new Fragment1(); mFragment2 = new Fragment2(); mFragment3 = new Fragment3(); mFragment4 = new Fragment4(); MyAdapter adapter = new MyAdapter(); adapter.setOnButtonClickListener(this); // ... 初始化 RecyclerView ... // 默认显示第一个 fragment mFragmentManager.beginTransaction() .replace(R.id.fragment_container, mFragment1) .commit(); } @Override public void onButtonClicked(int position) { Fragment fragment; switch (position) { case 0: fragment = mFragment1; break; case 1: fragment = mFragment2; break; case 2: fragment = mFragment3; break; case 3: fragment = mFragment4; break; default: fragment = mFragment1; break; } mFragmentManager.beginTransaction() .replace(R.id.fragment_container, fragment) .commit(); } } ``` 这样,当用户点击RecyclerView的按钮时,就会触发回调方法,根据传递的参数切换到对应fragment页面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值