Activity中片段总结

来源:互联网 发布:苹果手机怎么是2g网络 编辑:程序博客网 时间:2024/05/06 19:23

今天把Activity下的片段、加载器、任务和返回栈总结一下,明天再做个收尾,明天就基本完全搞定Activity部分的全部心得总结。

片段

Fragment表示Activity中的行为或用户界面部分,可以将多个片段组合在一个Activity中来构建多窗格UI,以及在多个Activity中重复使用某个片段,可以将片段视为Activity的模块化组成部分,具有自己的生命周期,能接收自己的输入时间,并且可以在Activity运行时添加或移除片段。

片段必须始终嵌入在Activity中,其生命周期直接受宿主Activity生命周期的影响。当Activity暂停或销毁时,所有片段也相应的暂停或销毁,当Activity正在运行时,可以独立操作每个片段,如添加或移除,当执行此类片段事务时,可以将其添加到由Activity管理的返回栈--Activity中每个返回栈条目都是一条已发生片段事务的记录,返回栈让用户可以通过返回按钮撤销片段事务。

当将片段作为Activity布局的一部分添加时,它存在于Activity视图结构的某个ViewGroup内部,并且片段会定义自己的视图布局,可以通过在Activity的布局文件中声明片段,将其作为<fragment>元素插入Activity布局中,或者通过将其添加到某个现有ViewGroup,利用应用代码插入,不过,片段并非必须成为Activity布局的一部分,还可以将没有自己UI的片段用作Activity的不可见工作线程。

设计原理:

通过将Activity布局分成片段,可以在运行时修改Activity的外观,并在由Activityi管理的返回栈中保留这些更改,应该将每个片段都设计为可重复使用的模块化Activity组件,即,由于每个片段都会通过各自的生命周期回调来定义自己的布局和行为,可以将一个片段加入多个Activity,故应该采用可复用式设计,避免直接从某个片段,直接操作另一个片段。这很重要,模块化片段使你可以通过更改片段的组合方式来适应不同的屏幕尺寸。


创建片段:

要创建片段,必须创建Fragment的子类(或已有子类)。Fragment类的代码与Activity非常相似。


大多数应用都应该至少为每个片段实现onCreate(), onCreateView(), onPause()这三个方法。

Activity生命周期与片段生命周期之间最显著的差异在于它们在返回栈中的存储方式,默认情况下,Activity停止时会被放入油系统管理的Activity返回栈,以便用户通过返回键能退回到Activity,而仅当在移除片段的事务执行期间通过调用addToBackStack()显式请求保存实例时,系统才会将片段放入由宿主Activity管理的返回栈。其他方面,管理片段生命周期与管理Activity生命周期非常相似。

片段与Activity生命周期协调一致:

Activity的每次生命周期的回调都会引发每个片段的类似回调。如,当Activity收到onPause()时,Activity中的每个片段也会收到onPause()。片段的额外生命周期回调的方法有:

onAttach()---在片段已于Activity关联时调用(Activity传递到此方法内)

onCreateView()---创建与片段关联的视图层次结构

onActivityCreated()---在Activity的onCreate()方法已返回时调用

onDestroyView()---在移除与片段关联的视图层次结构时调用

onDetach()---在取消片段与Activity的关联时调用



若想拓展几个子类,而不是Fragment基类:

DialogFragment:显示浮动对话框

ListFragment:显示由配适器管理的一系列项目,类似于ListActivity,提供了几种管理列表视图的方法,用于处理点击事件的onListItemClick()回调

PreferenceFragment:列表形式显示Preference对象的层次结构,类似于PreferenceActivity。为应用创建”设置“Activity时很有用。

添加用户界面:

要想为片段提供布局,必须实现onCreateView()回调方法,(注:若片段是ListFragment的子类,则默认实现会从onCreateView()返回一个ListView,故无需实现它)

若要从onCreateView()返回布局,可以通过XML中定义的布局资源类扩展布局,onCreateView()提供了一个LayoutInflater对象。

public static class ExampleFragment extends Fragment {    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        // Inflate the layout for this fragment        return inflater.inflate(R.layout.example_fragment, container, false);    }}
传递至onCreateView()的container参数是片段布局将插入到父ViewGroup。saveInstanceState参数是在恢复片段时,提供上一片段实例相关数据的Bundle。

向Activity添加片段:

1.在Activity的布局文件中声明片段:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="match_parent"    android:layout_height="match_parent">    <fragment android:name="com.example.news.ArticleListFragment"            android:id="@+id/list"            android:layout_weight="1"            android:layout_width="0dp"            android:layout_height="match_parent" />    <fragment android:name="com.example.news.ArticleReaderFragment"            android:id="@+id/viewer"            android:layout_weight="2"            android:layout_width="0dp"            android:layout_height="match_parent" /></LinearLayout>
系统创建Activity布局时,会实例化在布局中指定的每个片段,并为每个片段调用onCreateView(),系统会直接插入片段返回View来替代<fragment>元素。

注:每个片段都需要唯一标识符,重启Activity时,系统可以使用该标识符来恢复片段。可以通过三种方式为片段提供ID:

*为android:id提供唯一的ID

*为android:tag提供唯一字符串

*若未给上述两个属性提供值,系统会使用容器视图的ID

2.通过编程方式将片段添加到某个现有ViewGroup

可以在Activity运行期间随时将片段添加到Activity布局中,只需指定要将片段放入哪个ViewGroup。

若想在Activity中添加、移除或替换片段,必须使用FragmentTransaction中的API:

FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();ExampleFragment fragment = new ExampleFragment();fragmentTransaction.add(R.id.fragment_container, fragment);fragmentTransaction.commit();
添加没有UI的片段:

若要添加没有UI的片段,使用add(Fragment, String)从Activity添加片段(为片段提供一个唯一的字符串标记,而不是视图ID),不需要实现onCreateView()方法。由于灭有UI,故字符串标记是标识它的唯一方式。若想从Activity中获取片段,使用findFragmentByTag()。

管理片段:

使用FragmentManager管理Activity中的片段,从Activity调用getFragmentManager()。

*通过findFragmentById()或findFragmentByTag()获取Activity中存在的片段、

*通过popBackStack()将片段从返回栈中弹出。

*通过addOnBackStackChangedListener()注册一个侦听返回栈变化的侦听器。

执行片段事务:

Activity中使用片段的优点是可以根据用户行为通过它们执行添加、移除以及其他操作。

从FragmentManager获取一个FragmentTransaction实例:

FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
以下实力是将一个片段替换另一个片段,且在返回栈中保留先前状态:

Fragment newFragment = new ExampleFragment();FragmentTransaction transaction = getFragmentManager().beginTransaction();transaction.replace(R.id.fragment_container, newFragment);transaction.addToBackStack(null);transaction.commit();
通过调用addToBackStack()可将替换事务保存到返回栈,以便用户能过通过按返回按钮撤销事务并回退到上一片段。

对于每个片段事务,可以通过在提交前调用setTransaction()来应用过渡动画。
注:只能在Activity保存其状态(用户离开Activity)之前使用commit()提交事务,若试图在该时间点后提交,则会引发异常。若丢失也没关系的话,使用commitAllowingStateLoss()。

与Activity通信:

片段可以通过getActivity()访问Activity实例,并执行在Activity布局中查找视图等任务

View listView = getActivity().findViewById(R.id.list);

Activity可以使用findFragmentByID()或findFragmentByTag(),通过从FragmentManager获取对Fragment的引用来调用片段中的方法

ExampleFragment fragment = (ExampleFragment) getFragmentManager().findFragmentById(R.id.example_fragment);
创建对Activity事件回调:

若片段与Activity共享事件,在片段内定义一个回调接口,宿主Activity实现它,当Activity通过接口收到回调时,可以与布局中的其他片段共享信息。
例如,若一个新闻应用的Activity有两个片段,一个用于显示文章列表(片段A),一个用于显示文章(片段B),则片段A是在列表项被选定后告知Activity,以便它告知片段B显示该文章,在本例中,OnArticleSelectedListener接口在片段A中声明:

public static class FragmentA extends ListFragment {    ...    // Container Activity must implement this interface    public interface OnArticleSelectedListener {        public void onArticleSelected(Uri articleUri);    }    ...}

然后,该片段宿主Activity实现OnArticleSelectedListener接口并替代onArticleSelected(),将来自片段A的事件通知片段B。为确保宿主Activity实现此接口,片段A的onAttach()回调方法会通过转换传递到onAttach()中的Activity来实例化onArticleSelectedListener的实例:

public static class FragmentA extends ListFragment {    OnArticleSelectedListener mListener;    ...    @Override    public void onAttach(Activity activity) {        super.onAttach(activity);        try {            mListener = (OnArticleSelectedListener) activity;        } catch (ClassCastException e) {            throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener");        }    }    ...}

若Activity未实现接口,则片段会引发ClassCastException ,实现时,mListener成员会保留对Activity的OnArticleSelectedListener实现的引用,以便片段A可以通过调用OnArticleSelectedListener接口定义的方法与Activity共享事件。例如,若片段A是ListFragment的一个扩展,则用户每次点击列表时,系统都会调用片段中的onListItemClick(),然后该方法会调用onArticleSelected()与Activity共享事件:

public static class FragmentA extends ListFragment {    OnArticleSelectedListener mListener;    ...    @Override    public void onListItemClick(ListView l, View v, int position, long id) {        // Append the clicked item's row ID with the content provider Uri        Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id);        // Send the event and Uri to the host activity        mListener.onArticleSelected(noteUri);    }    ...}
传递到onListItemClick()的id参数是被点击项的行ID,即Activity用来从应用的ContentProvider获取文章的ID。

向应用栏添加项目:

片段可以通过实现onCreateOptionMenu()向Activity的选项菜单贡献菜单项,必须在onCreate()期间调用setHasOptionMenu(),以指示片段想要向选项菜单添加菜单项。

选定菜单项时,片段会收到onOptionsItemSelected()的回调。可以通过调用registerForContextMenu(),在片段布局中注册一个视图来提供上下文菜单,用户打开上下文菜单时,片段会收到对onCreateContextMenu()的调用,用户选择某个菜单项时,片段会收到对onContextItemSelected()的调用。







0 0