Android片段生命周期

时间:2020-02-23 14:28:56  来源:igfitidea点击:

今天,我们将学习Android Fragment Lifecycle,并在android应用程序中实现由两个片段组成的单个活动类。

Android片段

Android中的Fragment类用于构建动态用户界面。
片段应在活动内使用。
片段的最大优点是,它简化了为多种屏幕尺寸创建UI的任务。
一个活动可以包含任意数量的片段。

Android片段本身并不是大多数其他UI组件都是View的子类。
相反,片段内部有一个视图。
该视图最终显示在片段所在的活动中。

由于android片段不是视图,因此将其添加到活动中看起来与添加视图(例如TextView)有所不同。
片段被添加到活动内部的ViewGroup中。
片段的视图显示在此ViewGroup中。

下图显示了将片段添加到活动时发生的情况:

首先,活动获得对该片段的引用。
然后,它获取对ViewGroup的引用,该片段的视图将其中呈现。
然后,活动添加片段。
然后,该片段创建其视图并将其返回到活动。
然后将视图插入到ViewGroup父级中,并且该片段处于活动状态。

片段生命周期

下图说明了Android片段的生命周期。

以下是片段生命周期的方法。

  • onAttach():即使在onCreate()之前,也会首先调用此方法,让我们知道您的片段已附加到活动中。
    您通过了将托管您的片段的活动

  • onCreateView():当片段第一次绘制其UI时,系统调用此回调。
    要绘制片段的UI,必须从此方法返回View组件,该组件是片段布局的根。
    如果片段不提供UI,我们可以返回null

  • onViewCreated():将在onCreateView()之后调用。
    这在继承onCreateView()实现时特别有用,但是我们需要配置结果视图,例如使用ListFragment以及何时设置适配器

  • onActivityCreated():将在onCreate()和onCreateView()之后调用,以指示活动的onCreate()已完成。
    如果片段中需要初始化的内容取决于活动的onCreate()完成工作,则可以使用onActivityCreated()进行初始化工作

  • onStart():一旦可见片段,就会调用onStart()方法

  • onPause():系统调用此方法作为用户离开该片段的第一个指示。
    通常,您应该在此处提交应保留在当前用户会话之后的所有更改。

  • onStop():通过调用onStop()将片段停止

  • onDestroyView():在onDestroy()之前调用。
    这与设置UI的onCreateView()相对。
    如果需要针对UI进行清理,则可以将该逻辑放在onDestroyView()中。

  • onDestroy():onDestroy()被调用以对片段的状态进行最终清理,但不能保证由Android平台调用。

  • onDetach():在onDestroy()之后调用,以通知该片段已从其托管活动中取消关联

Android片段类

片段已添加到Honeycomb(API 11)中的Android API中。

  • android.app.Fragment:所有片段定义的基类
  • android.app.FragmentManager:用于与活动内的片段对象进行交互的类
  • android.app.FragmentTransaction:用于执行片段操作的原子集的类

使用Google提供的兼容性软件包库时,以下类用于实现。

  • android.support.v4.app.FragmentActivity:使用基于兼容性的片段(和加载程序)功能进行的所有活动的基类
  • android.support.v4.app.Fragment
  • android.support.v4.app.FragmentManager
  • android.support.v4.app.FragmentTransaction

Android片段onCreateView()

这是使用onCreateView()实现的示例片段:

public class SampleFragment extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup parentViewGroup,
                           Bundle savedInstanceState) {

      View rootView = inflater.inflate(R.layout.fragment_sample, parentViewGroup, false);
      return rootView;
  }
}

onCreateView()方法获取LayoutInflater,ViewGroup和Bundle作为参数。

LayoutInflater是一个可以基于布局XML文件创建View实例的组件。
如您所见,该示例实际上通过调用layout.inflate()来实现。

inflate()方法采用三个参数:布局XML文件的ID(在R.layout内部),要插入片段的View的父ViewGroup,以及第三个布尔值,用于告知片段的View是否从布局XML文件应插入父级ViewGroup中。
在这种情况下,我们将传递false,因为View将通过我们调用的某些Android代码附加到父ViewGroup的其他位置。
当您将false作为最后一个参数传递给inflate()时,父ViewGroup仍用于膨胀View的布局计算,因此您不能将null作为父ViewGroup传递。

onCreateView()的ViewGroup参数是要插入片段的View的父ViewGroup。
这是活动内部的ViewGroup,将"托管"片段。

onCreateView()的Bundle参数是一个Bundle,片段可以其中保存数据,就像在Activity中一样。

Android片段示例

Android片段示例项目包含一个包含两个片段的单独活动:分别为TextFragment和MenuFragment。

Android片段示例代码

MainActivity包含两个片段TextFragment和MenuFragment。
因此,让我们开始在xml布局中定义片段

activity_main.xml

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="horizontal"
  android:weightSum="1.0">

  <fragment
      android:layout_height="match_parent"
      android:layout_width="match_parent"
      class="theitroad.local.fragments.fragments.MenuFragment"
      android:id="@+id/fragment"
      android:layout_weight="0.5"
  <fragment
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      class="theitroad.local.fragments.fragments.TextFragment"
      android:id="@+id/fragment2"
      android:layout_weight="0.5"
</LinearLayout>

我们可以看到,作为该活动一部分的片段的类文件被定义为class =" theitroad.local.fragments.fragments.TextFragment"

片段类及其布局的定义如下面的代码片段所示。

package theitroad.local.fragments.fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import theitroad.local.fragments.R;
public class TextFragment extends Fragment {
  TextView text,vers;

  @Override

  public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {

      View view = inflater.inflate(R.layout.text_fragment, container, false);
      text= (TextView) view.findViewById(R.id.AndroidOs);
      vers= (TextView)view.findViewById(R.id.Version);

      return view;

  }
  public void change(String txt, String txt1){
      text.setText(txt);
      vers.setText(txt1);

  }
}

text_fragment.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:gravity="center"
  android:background="#5ba4e5"
  android:layout_height="match_parent">

  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:textSize="40px"
      android:textColor="#ffffff"
      android:layout_gravity="center"
      android:id="@+id/AndroidOs"
  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:textColor="#ffffff"
      android:textSize="30px"
      android:id="@+id/Version"

</LinearLayout>

TextFragment由保存Android版本名称和编号的文本视图组成。

package theitroad.local.fragments.fragments;

import android.app.ListFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import theitroad.local.fragments.R;
public class MenuFragment extends ListFragment {
  String[] AndroidOS = new String[] { "Cupcake","Donut","Eclair","Froyo","Gingerbread","Honeycomb","Ice Cream SandWich","Jelly Bean","KitKat" };
  String[] Version = new String[]{"1.5","1.6","2.0-2.1","2.2","2.3","3.0-3.2","4.0","4.1-4.3","4.4"};
  @Override

  public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {
      View view =inflater.inflate(R.layout.list_fragment, container, false);
      ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
              android.R.layout.simple_list_item_1, AndroidOS);
      setListAdapter(adapter);

      return view;

  }
  @Override
  public void onListItemClick(ListView l, View v, int position, long id) {
      TextFragment txt = (TextFragment)getFragmentManager().findFragmentById(R.id.fragment2);
      txt.change(AndroidOS[position],"Version : "+Version[position]);
      getListView().setSelector(android.R.color.holo_blue_dark);
  }
}

list_fragment.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <ListView
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:id="@android:id/list" 
</LinearLayout>

MenuFragment显示一个ListView。
正如我们在这里看到的,ListView的布局是默认的simple_list_item_1,与我们在上一篇文章中为ListView创建的自定义布局相反。

MainActivity从onCreate方法调用setContentView就是这样。
这些片段是从xml文件中调用的。

或者,我们可以使用" FragmentManager"从活动类中添加片段,如下面的代码片段所示:

getFragmentManager()
                .beginTransaction()
                .add(R.id.fragmentParentViewGroup, new MyFragment())
                .commit();

此处idfragmentParentViewGroup属于以下所示的FrameLayout:

<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
           xmlns:tools="https://schemas.android.com/tools"
           android:id="@+id/fragmentParentViewGroup"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           tools:context=".MyActivity"
           tools:ignore="MergeRootFrame"