察觉网友给的两种解决方案,基本上都是综合 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,别的啥也没有