全栈工程师开发手册 (作者:栾鹏)
安卓教程全解

安卓中Fragment可以没有UI,不需要manifest中注册,只能嵌套在一个activity存在。

在Fragment基础上,系统派生处理另外几种fragment

1、DialogFragment:一个fragment可以在fragment的父activity上显示一个浮动的对话框,而且可以自定义对话框的UI

2、ListFragment:可以通过绑定数据源呈现一个Listview作为它主要的UI展示方式

3、WebViewFragment:封装了WebView,当Fragment被暂停或恢复时,子WebView同样会被暂停和恢复

fragment布局在activity的方式

在activity中设置fragment有2种方式。

1、在xml中设置一个FrameLayout的容器,使用java为其添加一个fragment。

2、在xml中直接引用自定义的fragment。

我们设置activity的UI如下:一个空的fragment容器:FrameLayout,一个自定义Fragment,一个自定义ListFragment。

activity_frament.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <!-- 作为自定义fragment的父容器,在java中去填充这个容器 -->
  <FrameLayout
    android:id="@+id/activity_fragment_container"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_weight="1"
    android:background="@color/red"  /> 
  <!-- 直接引用java中自定义的Fagment,必须为该fragment设置id或tag -->
  <fragment android:name="com.lp.app.Fragment1"
    android:id="@+id/activity_fragment_item"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_weight="3"
    android:background="@color/green"  />
   <!-- 直接引用java中自定义的ListFragment,必须为该fragment设置id或tag  -->
   <fragment android:name="com.lp.app.Fragment_list"
    android:id="@+id/activity_fragment_list"
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"
    android:layout_weight="3"
    android:background="@color/blue"  /> 
</LinearLayout> 

在activity中使用java操作Fragment、ListFragment

对于在UI 的xml文件中设置的fragment容器FrameLayout,和直接引用的自定义Fragment、ListFragment,我们分别进行操作示例。

1、在activity的java中操作Fragment

包括向容器中添加fragment(add),查找fragment(findFragmentById、findFragmentByTag),fragment的隐藏(hide),显示(show)、删除(remove),替换容器中的fragment(replace),fragment入栈(addToBackStack),事务提交动画(setTransition),事务提交(commit),事务立即执行(executePendingTransactions)。

 public void fragmentmanagerfun(){
 		 
 		 FragmentManager fragmentmanager=getFragmentManager();  //每个activity都包含一个Fragment Manager来管理它所包含的Fragment
 		 FragmentTransaction fragmentTransaction =fragmentmanager.beginTransaction();  //
 		 //添加fragment
 		 fragmentTransaction.add(R.id.activity_fragment_container, Fragment1.newInstance("这是第1个fragment"),"tag1");  //将fragment的实例添加到容器view中(若fragment没有UI,则不需要容器),同时可以为fragment添加tag名称
 		 fragmentTransaction.add(R.id.activity_fragment_container, new Fragment1(),"tag2");  //一个FrameLayout可以添加多层fragment
 		 fragmentTransaction.add(new Fragment1(),"tag3");  //可以添加没有ui的fragment
 		 fragmentTransaction.commit();   //保存修改,一个fragmentTransaction只能使用一次commit,方法并不会立即执行事务
 		 fragmentmanager.executePendingTransactions();  //立即执行上面的事务。
 		
 		
 		 FragmentTransaction fragmentTransaction1 =fragmentmanager.beginTransaction();   //使用保存后,需要重新创建一个才能再次使用保存
 		 
 		 //查询fragment,获取引用
 		 Fragment fragment1=fragmentmanager.findFragmentById(R.id.activity_fragment_item);  //只能查找布局文件中的fragment
 		 Fragment fragment2=fragmentmanager.findFragmentByTag("tag2");  //通过tag查找java文件中添加的fragment,没保存前无法找到
 		
 		 //判断是否被添加到了容器中
 		 if(fragment2.isAdded())
 		 {
 			 //隐藏当前的Fragment,仅仅是设为不可见,并不会销毁
 			 fragmentTransaction1.hide(fragment2);
 	 		 //显示之前隐藏的Fragment
 	 		 fragmentTransaction1.show(fragment2);
 			 //删除fragment
 	 		 fragmentTransaction1.remove(fragment2);  //去除fragment,跟add是相反操作(无法移除在xml中添加的)
 		 }
 			 
 		 //替换fragment
 		 fragmentTransaction1.replace(R.id.activity_fragment_container, Fragment1.newInstance("这是第2个fragment"),"tag3");  //替换fragment,先remove容器下层的一个fragment,再加入一个fragment,同时可以为fragment添加tag名称
 		 

 		 String tag=null;
 		 fragmentTransaction1.addToBackStack(tag);  //在提交前将当前fragment视图保存到由宿主 Activity管辖的后退栈中(通过点击back按钮更换的视图)
 		 //调用 addOnBackStackChangedListener() 方法注册监听器,用于监听后退栈的变化。


 		 fragmentTransaction1.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);  //使事务变化动起来,使用系统过渡动画
 		 fragmentTransaction1.setCustomAnimations(R.animator.anim1, R.animator.anim1);  //使用自定义动画,前者应用到添加的fragment中,后者应用到删除的fragment中

 		 fragmentTransaction1.commit();   //保存修改,只能使用一次commit
 	 }

2、在父activity的java中操作ListFragment(设置更改ListFragment的绑定数据)

 private ArrayAdapter<String> aa=null;
 private ArrayList<String> items = new ArrayList<String>();
 //在activity中设置listfragment的数据
 public void listfragmentfun() 
 {
		FragmentManager fragmentmanager=getFragmentManager(); 
		Fragment_list fragment_list=(Fragment_list)fragmentmanager.findFragmentById(R.id.activity_fragment_list);
	
		items.clear();
		for (int i = 0; i < 5; i++) {
			items.add("新选项" + i);
	    }
		aa=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,items);
		fragment_list.setListAdapter(aa);
}

Fragment的生命周期

这里写图片描述

可以看到Fragment比Activity多了几个额外的生命周期回调方法:

onAttach(Activity)
当Fragment与Activity发生关联时调用。

onCreateView(LayoutInflater, ViewGroup,Bundle)
创建该Fragment的视图

onActivityCreated(Bundle)
当Activity的onCreate方法返回时调用

onDestoryView()
与onCreateView想对应,当该Fragment的视图被移除时调用

onDetach()
与onAttach相对应,当Fragment与Activity关联被取消时调用

注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现,

通过自定义fragment文件Fragment1 .java来实现fragment的全部生命周期函数

import com.lp.app.R;  
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


public class Fragment1 extends Fragment{ 
 
	  Context context;   //指向父activity
	  //activity在构造时向fragment传递参数。不使用构造函数,使用为activity重新创建,下属fragment的字段会丢失,bundle会保留
	  private static final String ARG = "arg";
	  public static Fragment1 newInstance(String arg)
	  {
		  Fragment1 fragment = new Fragment1();
	      Bundle bundle = new Bundle();
	      bundle.putString(ARG, arg);
	      fragment.setArguments(bundle);  //在fragment内通过getArguments读取参数
	      return fragment;
       }
	  //在fragment内部调用获取参数
	  public String getArg()
	  {
		  String arg = "这是一个fragment";  //默认参数值
		  if(getArguments()!=null)
			  arg = getArguments().getString(ARG);
		  return arg;
	  }

	  //调用该方法时Fragment会被连接到它的父activity上
	  @Override
	  public void onAttach(Activity activity) {
	    super.onAttach(activity);
	    Log.v("frament生命周期", "fragment连接到activity");
	  }
	  
	  //调用该方法来进行Fragment的初始创建
	  @Override
	  public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    context = getActivity();   //获得对父activity的引用
	    //初始化fragment
	    Log.v("frament生命周期", "fragment初始化");
	  }
	  
	  //一但Fragment已被创建,要创建它自己的用户界面时调用该方法。填充UI,获取控件引用,设置函数,创建service和timer。没有界面时不需要此函数
	  //可以直接控制fragment中的控件,并可以调用接口函数,实现调用父activity中函数
	  @Override
	  public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		  	//创建或者填充Fragment的UI,并返回它,如果这个Fragment没有UI,那么返回null
	    	View view =	inflater.inflate(R.layout.mylinearlayout, container, false);
	    	final TextView myTextView = (TextView)view.findViewById(R.id.mylinearlayout_text1);
	    	myTextView.setText(getArg());  //设置控件属性,或事件函数,这里读取了存储在fragment中的参数
	    	
	    	Log.v("frament生命周期", "fragment创建UI");
	    	return view;
	  }

	  //一旦父activity和Fragment的UI已被创建,则调用该方法
	  @Override
	  public void onActivityCreated(Bundle savedInstanceState) {
		  super.onActivityCreated(savedInstanceState);
		  //完成Fragment的初始化,尤其是那些父activity被初始化完成后或者Fragment的view被完全填充后才能做的事情
		  Log.v("frament生命周期", "fragment的ui已创建");
	  }

	  // 在可见生命周期的开始时被调用
	  @Override
	  public void onStart(){
		  super.onStart();
		  // 应用所有需要的UI变化,现在Fragment是可见的
		  Log.v("frament生命周期", "fragment可见周期开始");
	  }

	  //在活动生命周期开始时被调用
	  @Override
	  public void onResume(){
		  super.onResume();
		  //恢复所有暂停的Fragment需要的UI更新,线程或进程,但在非活动状态它是暂停的
		  Log.v("frament生命周期", "fragment活动周期恢复");
	  }

	  // 在活动生命周期结束时被调用
	  @Override
	  public void onPause(){
	    // 当activity不是活动的前台activity时,需要暂停UI的更新、挂起线程或者暂停那些不需要更新的CPU的集中处理。由于调用这个方法后,进程可能被终止,所以要保存所有的编辑和状态改变信息
		  super.onPause();
		  Log.v("frament生命周期", "fragment活动周期暂停");
	  }

	  //在活动生命周期结束时,调用该方法保存UI的状态变化
	  @Override
	  public void onSaveInstanceState(Bundle savedInstanceState) {
		  // 将UI的状态改变信息保存在savedInstanceState中
		  //这个Bundle会被传递到oncreate、oncreateview和onactivitycreate(如果它的父activity被终止并且重新启动)方法中
		  super.onSaveInstanceState(savedInstanceState);
		  Log.v("frament生命周期", "fragment保存ui");
	  }

	  //在可见生命周期结束时调用该方法
	  @Override
	  public void onStop(){
	    // 当fragment不可见时,暂停其余的UI更新、挂起线程或暂停不再需要的处理
		  super.onStop();
		  Log.v("frament生命周期", "fragment可见周期结束");
	  }

	  // 当fragment的view被分离时,调用该方法
	  @Override
	  public void onDestroyView() {
	    //清除资源相关view
		  super.onDestroyView();
		  Log.v("frament生命周期", "fragment中view分离");
	  }

	  //在整个生命周期结束时调用该方法
	  @Override
	  public void onDestroy(){
	    // 清除所有的资源,包括结束线程和关闭数据库连接等
		  super.onDestroy();
		  Log.v("frament生命周期", "fragment结束");
	  }

	  // 当fragment从它的父activity上分离时,调用该方法
	  @Override
	  public void onDetach() {
		  super.onDetach();
		  Log.v("frament生命周期", "fragment脱离activity");
	  }
}

自定义fragment的布局文件使用一个简单的ViewGroup文件mylinearlayout.xml来实现。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <TextView
    android:id="@+id/mylinearlayout_text1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="一个linearlayout中的textview" />
</LinearLayout>

ListFragment的生命周期

在自定义的ListFragment中,我们主要需要注意的是onCreate启动函数、onCreateView布局UI函数、onListItemClick选项点击函数。

使用自定义ListFragment文件Fragment_list.java实现基本的函数

import com.lp.app.R; 

import android.app.ListFragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;



public class Fragment_list extends ListFragment{   
 
	 Context context;  //指向父activity
	 Interface1 interface1;   //使用接口实现fragment和activity之间共享事件
	  
	private ArrayAdapter<String> adapter;

	  //可以在ListFragment内绑定数据源(也可以在activity中为ListFragment绑定数据源)
	  @Override
	  public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    context = getActivity();   //获得对父activity的引用
	    //获取对父Activity的引用,进而获取父activity中的函数(接口)和变量,
	    interface1 = (Interface1)context;
	    
	    //定义一个数组
	    List<String> data = new ArrayList<String>();
	    for (int i = 0; i < 30; i++) {
	          data.add("listfragment选项" + i);
	    }
	    //将数组加到ArrayAdapter当中
	    adapter = new ArrayAdapter<String>(context,R.layout.mytextview, data);  //使用一个系统布局,当做list每个项的布局
	    //绑定适配器时,必须通过ListFragment.setListAdapter()接口,而不是ListView.setAdapter()或其它方法
	    setListAdapter(adapter);
	    Log.v("ListFragment", "listfragment启动绑定数据源");
	  }

	  //创建或者填充Fragment的UI,并返回它,如果这个Fragment没有UI,那么返回null
	  @Override
	  public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
		  	
	    	View view =	inflater.inflate(R.layout.fragment_list, container, false);
	    	Log.v("ListFragment", "listfragment布局整体UI");
	    	return view;
	  }


	  //列表每一项的点击事件
	  @Override
	  public void onListItemClick(ListView listview, View v, int position, long id) {
		  super.onListItemClick(listview, v, position, id);
		  interface1.callback("点击了选项"+String.valueOf(position));   //通过接口调用activity中函数
		  Log.v("ListFragment", "点击了选项"+String.valueOf(position));
	  }
	  
}

自定义ListFragment的布局文件要使用一个包含listview的ViewGroup来实现。

这里使用fragment_list.xml来实现

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical" >
  <ListView  
        android:id="@+id/android:list"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
   />  
</LinearLayout>

自定义ListFragment文件中的listview的每一项的布局文件,可以选用自定义的view或ViewGroup或系统自带的布局文件(android.R.layout.simple_list_item_1)。

这里使用仅有一个textview的布局文件mytextview.xml来实现

<?xml version="1.0" encoding="utf-8"?>
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="一个textview"
   android:id="@+id/mytext1"/>

构建fragment时传递参数。

一般在创建对象时,赋予参数,使用构造函数,但是在fragment创建时,我们一般使用Bundle存储数据。是因为activity重新创建,下属fragment的字段会丢失,但是bundle数据会保留。

所以在自定义fragment中使用以下代码创建构造fragment,并读取fragment绑定的参数

private static final String ARG = "arg";
	  public static Fragment1 newInstance(String arg)
	  {
		  Fragment1 fragment = new Fragment1();
	      Bundle bundle = new Bundle();
	      bundle.putString(ARG, arg);
	      fragment.setArguments(bundle);  //在fragment内通过getArguments读取参数
	      return fragment;
       }
	  //获取fragment绑定的参数
	  public String getArg()
	  {
		  String arg = "这是一个fragment";  //默认参数值
		  if(getArguments()!=null)
			  arg = getArguments().getString(ARG);
		  return arg;
	  }

在activity中可以使用下面两种方式构建自定义的fragment

Fragment1 fragmenttemp1 =Fragment1.newInstance("这是第1个fragment");   //构建一个绑定了参数的fragment
Fragment1 fragmenttemp2 =new Fragment1(); //构建一个没有绑定参数的fragment

activity与fragment的相互引用

在activity中可以使用findFragmentById、findFragmentByTag获取对子fragment的引用

Fragment fragment1=getFragmentManager().findFragmentById(R.id.activity_fragment_item);  //只能查找布局文件中的fragment
Fragment fragment2=getFragmentManager().findFragmentByTag("tag2");  //通过tag查找java文件中添加的fragment,没保存前无法找到

在fragment中可以通过getActivity获得对父activity的引用。

Context context;   //指向父activity
//调用该方法时Fragment会被连接到它的父activity上
 @Override
 public void onAttach(Activity activity) {
	   super.onAttach(activity);
	   context = getActivity();   //获得对父activity的引用
	   Log.v("frament生命周期", "fragment连接到activity");
 }

fragment向activity传递数据

一个activity下往往包含多个fragment,多个fragment以及activity之间需要相互共享数据,一个有效的实现方法,是在fragment定义声明接口,并调用这个接口函数,而在activity中实现这个接口函数。

1、首先你要自定义一个接口文件。这里设置一个简单的接口Interface1.java


//在fragment中声明接口,调用接口函数,在activity中定义接口函数
public interface Interface1{
	public void callback(Object object);   //声明接口函数
}

2、在自定义fragment中定义一个接口变量

Interface1 interface1;   //使用接口实现fragment和activity之间共享事件
@Override
public void onCreate(Bundle savedInstanceState) {
	  super.onCreate(savedInstanceState);
	  context = getActivity();   //获得对父activity的引用
	  //获取对父Activity的引用,进而获取父activity中的函数(接口)和变量,
	  interface1 = (Interface1)context;
}

3、在这个fragment中边可以调用接口函数。也就是向activity传递数据

 public void returndata(Object object) {
	  interface1.callback(object);   //通过接口
 }

4、在activity中实现这个接口,并接受fragment传递的数据

public class Activity_fragment extends Activity implements Interface1{  

 	 
 	 //activity和fragment之间的事件共享,通过接口,activity接收fragment传来的数据,以便在自身或其他fragment中应用
	@Override
	public void callback(Object object) {
		Log.v("fragment的主窗口", object.toString());
		//控制UI或调用其他fragment中的函数
	}
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐