最近用户反映打开APP的时候非常卡顿。对ViewPager的延迟加载进行了探究。
private void addFragments() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
for (Fragment f : mFragments) {
ft.add(R.id.fl_content, f);
}
ft.commit();
}
private void showFragment(int index) {
FragmentTransaction transaction = mManager.beginTransaction();
for (int i = 0; i < mFragments.size(); i++) {
if (i == index) {
transaction.show(mFragments.get(i));
} else {
transaction.hide(mFragments.get(i));
}
}
transaction.commit();
}
初始的时候,将所有涉及到的Fragment都添加进来,根据用户点击的tab来显示相应的Fragment。
1.新启动MainActivity的时候:
四个Fragment都有创建。在Fragment onResume中加载网络数据,必然导致进入主页非常慢(AsyncTask默认是串行执行的)。
2.切换到任何一个Fragment,该Fragment的onResume都没有调用。尝试使用setUserVisibleHint,测试结果这种方法也行不通。
3.进入子页面返回后:
这是正常的,Fragment和它所在的Activity有相似的生命周期。
可见,单纯的在onResume中,刷新网络数据时行不通了。只能将更新网络数据的逻辑放在了MainActivity中了,这样一来,Activity和Fragment的耦合度太高了,这种方式的确不大好啊!!!
1.科普一下:FragmentPagerAdapter和FragmentStatePagerAdapter来自android.support.v4.app包用来构建ViewPager。
FragmentPagerAdapter更多的用于少量界面的ViewPager,比如Tab。划过的fragment会保存在内存中,尽管已经划过。 而FragmentStatePagerAdapter和ListView有点类似,会保存当前界面,以及下一个界面和上一个界面(如果有),最多保存3 个,其他会被销毁掉。所以,我们这里使用FragmentPagerAdapter,FragmentPagerAdapter默认仅仅加载当前页面和两侧页面到内存中其他都从内存中移除,我们这里设置mPager.setOffscreenPageLimit(3);保证一次将所有的Fragment都添加到内存中,当tab进行切换的时候,不会再有Fragment的创建。
2.初始情况:
可以看到C的延迟加载有调用
3.点击A:
这里延迟加载有调用哦!
4.进入子页面然后返回:
现在仅仅在Fragment的layzLoad中更新数据就好了。如果想要获取fragment从二级子页面返回的事件,使用startActivityForResult 来进行处理就好啦!
package com.example.fragmentstatepageradapterdemo.fragment;
import android.support.v4.app.Fragment;
/** * Author: msdx ([email protected]) * Time: 14-7-17 下午5:46 */
public abstract class LazyFragment extends Fragment {
protected boolean isVisible;
/** * 在这里实现Fragment数据的缓加载. * @param isVisibleToUser */
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
protected void onVisible(){
lazyLoad();
}
protected abstract void lazyLoad();
protected void onInvisible(){}
}
package com.example.fragmentstatepageradapterdemo.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.fragmentstatepageradapterdemo.SecondActivity;
import com.example.fragmentstatepageradapterdemo.ViewPagerMainActivity;
public class AFragment extends LazyFragment {
// 标志位,标志已经初始化完成。
private boolean isPrepared;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
//获取当前class名的方法
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
//获取当前method名的方法
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
tv.setText(clazz);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getActivity(), SecondActivity.class));
}
});
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
isPrepared = true;
lazyLoad();
return tv;
}
@Override
public void onResume() {
super.onResume();
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
}
@Override
protected void lazyLoad() {
if(!isPrepared || !isVisible) {
return;
}
String clazz = Thread.currentThread().getStackTrace()[2]
.getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
//填充各控件的数据
}
}
B/C/D和A相似。
package com.example.fragmentstatepageradapterdemo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
tv.setText(clazz);
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
setContentView(tv);
}
@Override
protected void onResume() {
super.onResume();
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
}
@Override
protected void onPause() {
super.onPause();
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#eeeeee" android:orientation="vertical" >
<android.support.v4.view.ViewPager android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1" >
</android.support.v4.view.ViewPager>
<View android:id="@+id/line" android:layout_width="fill_parent" android:layout_height="1px" android:background="#cacaca" />
<LinearLayout android:id="@+id/ll_bottoms" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#f5f5f5" android:baselineAligned="false" android:orientation="horizontal" >
<FrameLayout android:id="@+id/fl_a" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:clickable="true" >
<RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:button="@drawable/ic_launcher" android:clickable="false" />
</FrameLayout>
<FrameLayout android:id="@+id/fl_b" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:clickable="true" >
<RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:button="@drawable/ic_launcher" android:clickable="false" />
</FrameLayout>
<FrameLayout android:id="@+id/fl_c" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:clickable="true" >
<RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:button="@drawable/ic_launcher" android:clickable="false" />
</FrameLayout>
<FrameLayout android:id="@+id/fl_d" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:clickable="true" >
<RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:button="@drawable/ic_launcher" android:clickable="false" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
package com.example.fragmentstatepageradapterdemo;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import com.example.fragmentstatepageradapterdemo.fragment.AFragment;
import com.example.fragmentstatepageradapterdemo.fragment.BFragment;
import com.example.fragmentstatepageradapterdemo.fragment.CFragment;
import com.example.fragmentstatepageradapterdemo.fragment.DFragment;
public class ViewPagerMainActivity extends FragmentActivity implements View.OnClickListener {
public static final String TAG = ViewPagerMainActivity.class.getSimpleName();
public static final int FRAG_A = 0;
public static final int FRAG_B = 1;
public static final int FRAG_C = 2;
public static final int FRAG_D = 3;
private List<Fragment> mFragments = new ArrayList<Fragment>();
MyAdapter mAdapter;
ViewPager mPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_main_viewpager);
LinearLayout bottomLayout = (LinearLayout) findViewById(R.id.ll_bottoms);
LinearLayout.LayoutParams bottomParams = (LayoutParams) bottomLayout
.getLayoutParams();
bottomParams.height = 98;
findViewById(R.id.fl_a).setOnClickListener(this);
findViewById(R.id.fl_b).setOnClickListener(this);
findViewById(R.id.fl_c).setOnClickListener(this);
findViewById(R.id.fl_d).setOnClickListener(this);
mFragments = new ArrayList<Fragment>();
mFragments.add(FRAG_A, new AFragment());
mFragments.add(FRAG_B, new BFragment());
mFragments.add(FRAG_C, new CFragment());
mFragments.add(FRAG_D, new DFragment());
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setOffscreenPageLimit(3);
mPager.setAdapter(mAdapter);
mPager.setCurrentItem(2);
}
public class MyAdapter extends FragmentPagerAdapter{
public MyAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int postion) {
return mFragments.get(postion);
}
@Override
public int getCount() {
return mFragments==null? 0:mFragments.size();
}
}
@Override
protected void onResume() {
super.onResume();
String clazz = Thread.currentThread().getStackTrace()[2].getClassName();
String method = Thread.currentThread().getStackTrace()[2]
.getMethodName();
String msg = " " + clazz + " " + method;
Log.d(ViewPagerMainActivity.TAG, msg);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fl_b: {
// loginOrShow(FRAG_B);
mPager.setCurrentItem(1);
break;
}
case R.id.fl_c: {
// loginOrShow(FRAG_C);
mPager.setCurrentItem(2);
break;
}
case R.id.fl_d: {
mPager.setCurrentItem(3);
// loginOrShow(FRAG_D);
break;
}
default:
case R.id.fl_a: {
mPager.setCurrentItem(0);
// loginOrShow(FRAG_A);
break;
}
}
}
}