猛然发现已经有近一年的时间没有更新博客了,一方面是因为自己的懒惰,另一方面是自从换公司后工作压力的增大没有太多的精力与时间进行维护。在我看来,博客是一个记录经验,并且分享的平台。这一年里,我从一个技术菜鸟,开始独自带队开发项目,维护项目,虽然忙,但是各方面都有了一定的进步。
对于Fragment是什么,它的生命周期,有什么作用,我这里就不多介绍了。如今大部分的App的首页都设计成在FrameLayout的底部放置一个tab用于切换Fragment的样式。但是在开发的过程中,依然有许多问题需要注意。
首先,我们先创建一个Activity 与Fragment ,并且添加对应的点击事件, 对应的布局文件我就不贴出来了,文末的链接会有可供下载的demo
因为我Fragment 都复用同一个,所以就直接在Fragment内部添加了创建对象的方法,先看下代码:
public class TestFragment extends Fragment {
private TextView tv_info;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test, container, false);
tv_info = (TextView) view.findViewById(R.id.tv_info);
Bundle args = getArguments();
if (args != null) {
String content = args.getString("content");
tv_info.setText(content);
}
return view;
}
public static TestFragment newInstance(String content) {
TestFragment testFragment = new TestFragment();
Bundle bundle = new Bundle();
bundle.putString("content", content);
testFragment.setArguments(bundle);
return testFragment;
}
}
通过 newInstance(String content)我创建了一个对象,该方法在Activity中直接调用就好,同时传入了一个String类型的数据,用于设置该界面TextView 的内容
划重点:我们创建了一个Bundle对象,用于数据传输,并且我们将content值传进去。
现在,我们看看我们的Activity
public class MainActivity extends FragmentActivity implements View.OnClickListener{
private TextView tv_tab1,tv_tab2,tv_tab3;
private TestFragment f1,f2,f3;
private FragmentManager manager;
private FragmentTransaction transaction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
tv_tab1 = (TextView) findViewById(R.id.tv_tab1);
tv_tab2 = (TextView) findViewById(R.id.tv_tab2);
tv_tab3 = (TextView) findViewById(R.id.tv_tab3);
tv_tab1.setOnClickListener(this);
tv_tab2.setOnClickListener(this);
tv_tab3.setOnClickListener(this);
/**
* 启动默认选中第一个
*/
// rGroup.check(R.id.rb_1);
f1 = TestFragment.newInstance("FIRST");
transaction.replace(R.id.fl_main, f1);
transaction.commit();
}
@Override
public void onClick(View v) {
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
switch (v.getId()) {
case R.id.tv_tab1 :
/**
* 为了防止重叠,先移除其他Fragment
*/
hideFragment(transaction);
f1 = TestFragment.newInstance("FIRST_FRAGMENT");
transaction.replace(R.id.fl_main, f1);
transaction.commit();
break;
case R.id.tv_tab2 :
hideFragment(transaction);
f2 = TestFragment.newInstance("SECOND_FRAGMENT");
transaction.replace(R.id.fl_main, f2);
transaction.commit();
break;
case R.id.tv_tab3 :
hideFragment(transaction);
f3 = TestFragment.newInstance("THIRD_FRAGMENT");
transaction.replace(R.id.fl_main, f3);
transaction.commit();
break;
default :
break;
}
}
/*
* 所有的Fragment
*/
private void hideFragment(FragmentTransaction transaction) {
if (f1 != null) {
transaction.remove(f1);
}
if (f2 != null) {
transaction.remove(f2);
}
if (f3 != null) {
transaction.remove(f3);
}
}
}
代码分析:
我们通过这两行代码开启了Fragment事务管理器,并将其开启
manager = getSupportFragmentManager();
transaction = manager.beginTransaction();
接着我们通过Fragment 中的newInstance 方法创建Fragment,然后通过如下两行代码用该Fragment 的实例替换FrameLayout,并且提交这个事件,从而,我们达到了在首页显示第一个Fragment的内容了
transaction.replace(R.id.fl_main, f1);
transaction.commit();
我们接着就要进行Fragment 之间的切换:
在触发点击事件后,我们将要进行如下进步操作:(敲黑板)
1、隐藏所有的Fragment,调用hideFragment()方法,原理是先判断Fragment对象是否为空,如果为空就将其移除,这可以有效避免Fragment的重叠
2、重复之前的步骤,替换Framelayout ,提交事务
现在打开Demo,切换底部的Tab,通过Activity给每一个Fragment赋值,使其每一个Fragment中的TextView内容都不同
相比于Activity 给Fragment传输数据一步到位,Fragment给Activity 传送数据就稍微有些复杂了,我在工作中常用三种方案
1、通过回调接口
2、通过public 公开方法,在fragment中调用即可
先通过 getContext()instanceof MainActivity 将getContext()置为fragment所在的activity,直接调用其中方法即可
3、通过EventBus 事件总线工具,便于传输结构复杂的数据
Demo下载