Fragment在ViewPager中准确得知正在被查看

察觉网友给的两种解决方案,基本上都是综合 setUserVisibleHint 和 onHiddenChanged 两个方法执行操作,但是在ViewPager中似乎不太管用,有的时候会被调用很多次,这时候就需要有一种切实可行的方案解决这个问题,思来想去还是觉得用Activity调用Fragment中的方法执行操作最可靠,此处综合了我之前的一篇文章《FragmentStatePagerAdaper中获取到对应的Fragment》有兴趣的可以去看看,具体操作如下:

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * 单个的Fragment(里面只有一个textView,别的什么都没有)
 */
public class MineFragment extends Fragment {
    private final String TAG = MineFragment.class.getSimpleName();
    private View rootView;                                        // 根布局
    private boolean fragmentShowStatus;                           // 当前Fragment是否正在展示
    private TextView tvMsg;                                       // 文本信息展示器
    private String msg;                                           // 本页面分配的信息内容

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        rootView = inflater.inflate(R.layout.fragment_mine, null);
        initView(rootView);
        initData();
        return rootView;
    }

    private void initView(View rootView) {
        tvMsg = rootView.findViewById(R.id.tvMsg);
    }

    private void initData() {
        Object dataObj = getArguments().getSerializable("data");
        if (dataObj instanceof String) {
            msg = dataObj.toString();
            tvMsg.setText(msg);
        }
    }

    /**
     * 由Activity调用,设置当前展示状态
     * @param fragmentShowStatus
     */
    public void setShowStatus(boolean fragmentShowStatus) {
        this.fragmentShowStatus = fragmentShowStatus;
        if (fragmentShowStatus) {
            Log.e(TAG, msg + "显示中..");
        } else {
            Log.e(TAG, msg + "已隐藏..");
        }
    }
}

MineFragment的布局里面只有一个TextView,但是MineFragment内部包含一个属性fragmentShowStatus用于标识当前的展示状态,有一个特殊的方法setShowStatus用于让Activity调用设置它的显示状态,MineFragment对应的布局代码如下:




    

适配器本身的代码也没有什么特别的,添加了一个用于获取Fragment的Map

import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.view.ViewGroup;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Fragment适配器
 */
public class MineFragmentAdapter extends FragmentStatePagerAdapter {
    private List msgList;                              // 信息数据列表
    private Map mPageReferenceMap;      // 位置和页面的对应表

    public MineFragmentAdapter(FragmentManager fragmentManager, List msgList) {
        super(fragmentManager);
        this.msgList = msgList;
        this.mPageReferenceMap = new HashMap(getCount());
    }

    @Override
    public Fragment getItem(int position) {
        MineFragment fragment = new MineFragment();
        Bundle bundle = new Bundle();
        bundle.putSerializable("data", msgList.get(position));
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public int getCount() {
        if (msgList != null) return msgList.size();
        return 0;
    }

    @NonNull
    @Override
    public Fragment instantiateItem(@NonNull ViewGroup container, int position) {
        MineFragment fragment = (MineFragment) super.instantiateItem(container, position);
        // 添加到表中,不能在getItem方法里面添加,有的时候FragmentStatePagerAdapter会恢复一些Fragment,那些Fragment的恢复不会调用getItem方法
        mPageReferenceMap.put(position, fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        // 从表中删除
        mPageReferenceMap.remove(position);
        super.destroyItem(container, position, object);
    }

    // 根据位置获取到对应的页面,使用的时候也需要判空和判定 !fragment.isDetached() && !fragment.isRemoving(),否则会引发一些隐藏的问题
    public MineFragment getFragment(int position) {
        return mPageReferenceMap.get(position);
    }

    /**
     * 由于 fragment.setArguments(); 方法传递的参数会被 FragmentStatePagerAdapter 所缓存
     * ,为了节省内存,重写这个方法返回空可以阻止FragmentStatePagerAdapter的缓存操作
     * @return
     */
    @Override
    public Parcelable saveState() {
        return null;
    }
}

Activity本身也没做什么特殊的处理,记录一下上一次展示的Fragment,和当前展示的Fragment进行比对,然后调用Fragment的方法进行显示和隐藏的通知

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private final int MSG_COUNT = 5;

    private Activity context;                               // 上下文对象
    private ViewPager vpMain;                               // 内容展示器
    private MineFragmentAdapter mainAdapter;                // vp适配器
    private List msgList;                           // 信息数据
    private MineFragment curShowFragment;                   // 当前正在展示的Fragment

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = MainActivity.this;
        setContentView(R.layout.activity_main);
        vpMain = this.findViewById(R.id.vpMain);
        // 准备数据
        initData();
        // 设置适配器
        mainAdapter = new MineFragmentAdapter(getSupportFragmentManager(),msgList);
        vpMain.setAdapter(mainAdapter);
        vpMain.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener(){
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                MainActivity.this.onPageSelected(position);
            }
        });
        vpMain.post(new Runnable() {
            @Override
            public void run() {
                // 默认选中第一页
                onPageSelected(0);
                vpMain.removeCallbacks(this);
            }
        });
    }

    // 生成数据
    private void initData() {
        msgList = new ArrayList<>(MSG_COUNT);
        for (int i = 0; i < MSG_COUNT; i++) {
            msgList.add("这是第" + (i + 1) + "个页面");
        }
    }

    // 选中某一页需要调用的函数
    private void onPageSelected(int position) {
        // 执行操作,告知当前Fragment是可见的,告知上一个可见的Fragment是不可见的了,如此便能够调动主界面执行操作了
        MineFragment fragment = mainAdapter.getFragment(position);
        if (curShowFragment != null && curShowFragment != fragment) {
            curShowFragment.setShowStatus(false);
        }
        curShowFragment = fragment;
        curShowFragment.setShowStatus(true);
    }
}

Activity的布局内容,就一个ViewPager,别的啥也没有




    

你可能感兴趣的:(Fragment在ViewPager中准确得知正在被查看)