GIithub源码
准备用 Fragment 实现页面切换的效果,就去 Github 看了下别人的源码,发现他利用 Factory 模式进行了优化。下面我就把这种方法介绍给大家。
下面我们就用边学边练的方式进行学习,首先打开你的 Android Studio,并新建一个 FactoryFragment 项目。
创建三个 fragment,分别是 OneFragment,TwoFragment,ThreeFragment,代码如下所示:
public class OneFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
ButterKnife.bind(this, view);
return view;
}
}
public class ThreeFragment extends Fragment{
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_three, container, false);
ButterKnife.bind(this, view);
return view;
}
}
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_two, container, false);
ButterKnife.bind(this, view);
return view;
}
上面的代码引入三个 fragment 布局,当我们点击相应的按钮时,会出现指定的布局, 布局文件就不再这里粘贴了,可以去上面的 Github 下载源码。
创建工厂类 FragmentFactory,这也是我们的重点。代码如下:
public class FragmentFactory {
public static final String ONE_TAG = "one";
public static final String TWO_TAG = "two";
public static final String THREE_TAG = "three";
private OneFragment oneFragment;
private TwoFragment twoFragment;
private ThreeFragment threeFragment;
private static FragmentFactory mFactory;
private HashMap mHashMap = new HashMap<>();
private FragmentFactory() {
}
public static FragmentFactory getInstance() {
if (mFactory == null) {
synchronized (FragmentFactory.class) {
if (mFactory == null) {
mFactory = new FragmentFactory();
}
}
}
return mFactory;
}
public Fragment getFragmentByTag(String tag) {
if (tag.equals(ONE_TAG) && oneFragment == null) {
oneFragment = new OneFragment();
mHashMap.put(ONE_TAG, oneFragment);
}
if (tag.equals(TWO_TAG) && twoFragment == null) {
twoFragment = new TwoFragment();
mHashMap.put(TWO_TAG, twoFragment);
}
if (tag.equals(THREE_TAG) && threeFragment == null) {
threeFragment = new ThreeFragment();
mHashMap.put(THREE_TAG, threeFragment);
}
return mHashMap.get(tag);
}
可以看到,我们定义了三个标记,用来判断我们点击的 fragment ,后面的代码会做详细介绍。
接着用 getInstance() 获得工厂类实例, 在这个方法里面,使用 synchronized 关键字,避免点击多次,多次创建实例,浪费资源。
获取工厂实例后,就要调用工厂类,帮我们获取每个 fragment 实例。接下来我们创建 getFragmentByTag () 方法, 用我们上面定义的标记来判断我们点击的哪个 fragment,并判断该 fragment 是否实例化,避免浪费资源。然后添加到 mHashMap 中。
最后通过 mHashMap.get() 获取点击的 fragment 实例并返回。
修改 MainActivity 中的代码,如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@BindView(R.id.one)
RadioButton one;
@BindView(R.id.two)
RadioButton two;
@BindView(R.id.three)
RadioButton three;
private FragmentFactory mFactory;
private String mCurrentTag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mFactory = FragmentFactory.getInstance();
one.setOnClickListener(this);
two.setOnClickListener(this);
three.setOnClickListener(this);
initFragment(FragmentFactory.ONE_TAG);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.one:
initFragment(FragmentFactory.ONE_TAG);
break;
case R.id.two:
initFragment(FragmentFactory.TWO_TAG);
break;
case R.id.three:
initFragment(FragmentFactory.THREE_TAG);
break;
}
}
private void initFragment(String tag) {
Fragment baseFragment = mFactory.getFragmentByTag(tag);
if (baseFragment == null) {
throw new IllegalAccessError("tag is error!");
}
if (tag.equals(mCurrentTag)) {
return;
} else {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!TextUtils.isEmpty(mCurrentTag)) {
transaction.hide(mFactory.getFragmentByTag(mCurrentTag));
}
if (!baseFragment.isAdded()) {
transaction.add(R.id.fragment_tab, baseFragment);
} else {
transaction.show(baseFragment);
}
transaction.commitAllowingStateLoss();
}
mCurrentTag = tag;
}
}
首先对三个按钮创建点击事件,点击不同的按钮,显示相应的fragment,比较简单。
接下来就重点介绍下 initFragment() 方法 ,首先调用工厂类获取相应的 fragment 实例,然后创建 fragment 容器。
后面跟着 if 判断,当 mCurrentTag 不为空时, 隐藏这个 fragment (就当你点击第一次后,点击第二次的时候,就隐藏第一次的)。
当 baseFragment 没有在容器中时,transaction.add() 添加这个 fragment并显示。
当 baseFragment 在容器中时, transaction.show() 直接显示 这个 fragment.
最终程序效果在最上面,以及 Github 源码。