Android Fragment 详解 2016 干货

来源:互联网 发布:美橙域名 编辑:程序博客网 时间:2024/06/01 15:42

最近看了很多动画和一些效果很好的自定义控件,发现了一件事,就是Android的View层设计思想和古老的JavaSwing是如此的相似。这是在原来的基础上加入了一些输入移动端的生命周期,使其在使用和性能上更好。但是对核心的理解还是可以借鉴一些的。
如果说Activity就是JavaSwing的JFrame那么Fragment 就是在JPanel
一个是容器顶层控件,一个是显示在容器上的中间层控件。
所以这里插一句话,如果感觉自己android写的不溜那么就多看看java的代码。和设计思想吧。android的东西太多都是继承自java或者说就是java的衍生品。无论是顶层容器还是底层容器都是为了放交互容器的。

Fragment的使用
一、布局
大家完全可以把Fragment看成一个轻量级的Activity.为什么轻量,因为他不用在mainfest.xml文件中添加自己.第二他不能直接启动,必须依附(attach)在activity之上。
所以在这布局这一块,Fragment的使用完全可以和activity的布局划等号,设计图怎么画在这里就怎么设计一个 Fragment .

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:background="#00ff00" >      <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:text="This is fragment 1"          android:textColor="#000000"          android:textSize="25sp" />  </LinearLayout> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:background="#ffff00" >      <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:text="This is fragment 2"          android:textColor="#000000"          android:textSize="25sp" />  </LinearLayout>  

简单的画了两个布局背景不同,文字区分1和2
二、在Activity中使用
使用方法一:静态加载一个Fragment
第一步把这个 fragment实例化

public class Fragment1 extends Fragment {      @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          return inflater.inflate(R.layout.fragment1, container, false);      }  }  

二和一 ,一样
在onCreateView() 中实现的是

{    View view=inflater.inflate(R.layout.fragment);//这个View就是父容器在这个布局里的其他控件 好比TextView要依靠他findViewById();    TextView tv=(TextView)view.findViewById(R.id,textview);    return view;}

这样一个 Fragment在View层就创建成功了。
然后打开或新建activity_main.xml作为主Activity的布局文件,在里面加入两个Fragment的引用,使用android:name前缀来引用具体的

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:baselineAligned="false" >      <fragment          android:id="@+id/fragment1"          **android:name="com.example.fragmentdemo.Fragment1"**          android:layout_width="0dip"          android:layout_height="match_parent"          android:layout_weight="1" />      <fragment          android:id="@+id/fragment2"          **android:name="com.example.fragmentdemo.Fragment2"**          android:layout_width="0dip"          android:layout_height="match_parent"          android:layout_weight="1" />  </LinearLayout>  

最后打开或新建MainActivity作为程序的主Activity,里面的代码非常简单,都是自动生成的:

public class MainActivity extends Activity {      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);      }  }  

这里写图片描述
如我们的设计一样,两个Fragment平分了屏幕

使用方法二:动态添加
这回我们直接在Activity中使用Fragment

public class MainActivity extends Activity {      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          Display display = getWindowManager().getDefaultDisplay();          if (display.getWidth() > display.getHeight()) {              Fragment1 fragment1 = new Fragment1(); //新建Fragment            getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment1).commit(); //添加Fragment提交        } else {              Fragment2 fragment2 = new Fragment2();              getFragmentManager().beginTransaction().replace(R.id.main_layout, fragment2).commit();          }      }   }  

首先,我们要获取屏幕的宽度和高度,然后进行判断,如果屏幕宽度大于高度就添加fragment1,如果高度大于宽度就添加fragment2。动态添加Fragment主要分为4步:
1.获取到FragmentManager,在Activity中可以直接通过getFragmentManager得到。
2.开启一个事务,通过调用beginTransaction方法开启。
3.向容器内加入Fragment,一般使用replace方法实现,需要传入容器的id和Fragment的实例。
4.提交事务,调用commit方法提交。
现在运行一下程序,效果如下图所示:
竖屏显示结果
这里写图片描述`
横屏显示结果
这里写图片描述

在实战中主要使用的是第二种方法使用我们的Fragment.
这里写图片描述
即底部是三个activity切换按钮上面是三个Fragment这里的,这里对Fragment的使用方法就是使用动态加载的方法。

三、Fragment的生命周期 Fragment 就是一个轻量的Activity那么他的声明周期就和Activity非常像了。
生命周期如下:
1.onAttach() 在Fragment和Activity建立关联的时候调用
2.onCreate() 初始化Fragment本身为inflate view做准备
3.onCreateView() 对布局中的所有控件进行初始化 绑定
4.onActivityCreated
5.onStart
6onResume
在按下home之后
1.onPause 程序挂起
2.onStop 当前activity 停止
在返回程序之后
1.onStart 开始
2.onResume 恢复

点击back退出程序
1onPause
2onStop
3onDestoryView Fragment 的View被移除了。
4onDestory
5onDetach Fragment和Activiy解除关联的时候调用
注:此处并没有onRestart()方法!

三、Fragment通信
这里的通信主要分为
fragment->fragment 通过getActivity()为桥梁进行通信
Activity->fragment
fragment-activity 最简单 所有activity 之间的通信方法这种时候都可以用

如在之前Fragment2中添加一个button那么我们需要调用其他相关的Fragment是如何实现的那。

public class Fragment2 extends Fragment {      @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {          return inflater.inflate(R.layout.fragment2, container, false);      }      @Override      public void onActivityCreated(Bundle savedInstanceState) {          super.onActivityCreated(savedInstanceState);          Button button = (Button) getActivity().findViewById(R.id.button);          button.setOnClickListener(new OnClickListener() {              @Override              public void onClick(View v) {                  TextView textView = (TextView) getActivity().findViewById(R.id.fragment1_text);                  Toast.makeText(getActivity(), textView.getText(), Toast.LENGTH_LONG).show();              }          });      }    }  

当点击按钮的时候就会在Toast中显示Fragment1中的内容。
当然两个Fragment需要使用一个共同的activity父容器。

最后分享一些使用心得
补充知识点:
1、什么是FragmentTransaction?
使用Fragment时,可以通过用户交互来执行一些动作,比如增加、移除、替换等。
所有这些改变构成一个集合,这个集合被叫做一个transaction。

可以调用FragmentTransaction中的方法来处理这个transaction,并且可以将transaction存进由activity管理的back stack中,这样用户就可以进行fragment变化的回退操作。

可以这样得到FragmentTransaction类的实例:

1.FragmentManager  mFragmentManager = getSupportFragmentManager();2.FragmentTransaction  mFragmentTransaction = mFragmentManager.beginTransaction();

在多个 Fragment 之间进行切换的时候
replace()和hide的区别
首先replace 是代替,之前的Fragment会被清空掉,在再次切换回来的时候会进行重新加载。而hide是将之前的一个fragment 进行隐藏,将新的fragment 叠在上面进行显示.等在次调用的时候进行显示。不需要重新加载。测试这个最简单的方法就是 设计两个fragment 在同一位置上放一个按钮,一个有监听一个没有,但现实没有监听的按钮点击按钮的时候会响应一号按钮的监听事件。

另外一个对于 FragmentTransaction对象在commit之后就会失效。所以建议直接使用fragmentManager.beginTransaction() 这样就不会产生失效的问题了。

commit 于commitAllowingStateLoss();的区别
简单来说就是避免报错。
他们都调用了commitInternal
public int commit() {
return commitInternal(false);
}

public int commitAllowingStateLoss() {
return commitInternal(true);
}
这个两个方法区别就在传参判断后的处理方法checkStateLoss
当使用commit方法时,系统将进行状态判断,如果状态(mStateSaved)已经保存,将发生”Can not perform this action after onSaveInstanceState”错误。
如果mNoTransactionsBecause已经存在,将发生”Can not perform this action inside of ” + mNoTransactionsBecause错误

1 1
原创粉丝点击