fragment的介绍与使用
稍稍摘录一段Fragment.java中的说明文档。
/**
* A Fragment is a piece of an application's user interface or behavior
* that can be placed in an {@link Activity}. Interaction with fragments
* is done through {@link FragmentManager}, which can be obtained via
* {@link Activity#getFragmentManager() Activity.getFragmentManager()} and
* {@link Fragment#getFragmentManager() Fragment.getFragmentManager()}.
*
* <p>The Fragment class can be used many ways to achieve a wide variety of
* results. In its core, it represents a particular operation or interface
* that is running within a larger {@link Activity}. A Fragment is closely
* tied to the Activity it is in, and can not be used apart from one. Though
* Fragment defines its own lifecycle, that lifecycle is dependent on its
* activity: if the activity is stopped, no fragments inside of it can be
* started; when the activity is destroyed, all fragments will be destroyed.
*
* <p>All subclasses of Fragment must include a public empty constructor.
* The framework will often re-instantiate a fragment class when needed,
* in particular during state restore, and needs to be able to find this
* constructor to instantiate it. If the empty constructor is not available,
* a runtime exception will occur in some cases during state restore.
*/
其中有一点以前不知道,就是Fragment的子类必须包括一个public的空构造方法,否则可能会发生运行时异常。因为framework经常会在需要的时候(比如状态恢复时),重新实例化Fragment类,这个时候它就会查找这个构造方法来进行实例化。
本文主要是参考官方文档(https://developer.android.com/guide/components/fragments.html),记录下Fragment的使用用法。
Design Philosophy(设计理念)
为了在大小屏间更好的利用空间,更好的动态地设计UI
Figure 1. An example of how two UI modules defined by fragments can be combined into one activity for a tablet design, but separated for a handset design.
Creating a Fragment(创建Fragment对象)
方法:创建子类继承自Fragment(或者已存在的子类)
那接下来不得不讨论的就是Fragment的生命周期了。
方法 | 说明 |
onAttach() | called once the fragment is associated with its activity. |
onCreate() | called to do initial creation of the fragment. |
onCreateView() |
creates and returns the view hierarchy associated with the fragment. |
onActivityCreated() |
tells the fragment that its activity has completed its own {@link Activity#onCreate Activity.onCreate()}. |
onStart() |
makes the fragment visible to the user (based on its containing activity being started). |
onResume() |
makes the fragment interacting with the user (based on its containing activity being resumed). |
onPause() |
fragment is no longer interacting with the user either because its activity is being paused or a fragment operation is modifying it in the activity. |
onStop() |
fragment is no longer visible to the user either because its activity is being stopped or a fragment operation is modifying it in the activity. |
onDestroyView() |
allows the fragment to clean up resources associated with its View. |
onDestroy() | called to do final cleanup of the fragment's state. |
onDetach() |
called immediately prior to the fragment no longer being associated with its activity. |
Adding a user interface(为Fragment添加用户界面)
Fragment一般都是将自己作为Activity的一部分,并在Activity上显示自己的界面。而Fragment中实例化UI界面的操作是在onCreateView方法中。下面这个例子,在onCreateView方法中加载了xml布局文件:
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方法参数解析:
1.inflater
调用其inflate方法,最终会返回一个View对象。inflate方法参数说明:
(1)想要扩展的布局文件的资源id
(2)ViewGroup对象,加载参数1的布局
(3)boolean变量,表明是否将参数1的布局添加到参数2的ViewGroup中(这里为false,是因为系统已经将该布局添加到container了)
2.container
container是存放fragment的layout的ViewGroup对象。抽象么?换种说法:Activity的布局,暂称为A;Fragment的布局,暂称为F。因为Fragment会嵌套到Activity中,布局F自然需要加入到布局A里面。所以这里的container就是指布局A中用来加载布局F的ViewGroup(比如LinearLayout)。
3.savedInstanceState
Bundle对象,保存先前的fragment的实例等数据,用来恢复。
OK,为Fragment添加界面就结束了,总结:在onCreateView方法中,加入layout布局文件。接下来就是添加Fragment到Activity了。
Adding a fragment to an activity(添加Fragment到Activity)
two methods:
* Declare the fragment inside the activity's layout file. (在Activity的布局文件中添加Fragment,通过<fragment ...>标签)
<?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>
说明:
1.<fragment>中的android:name指明了具体的Fragment类。当系统创建Activity的布局时,它会检查每个<fragment>,并调用指明的Fragment类的onCreateView方法。当onCreateView返回一个View对象后,系统会用该View替换<fragment ...>标签指代的内容。
Note:每个Fragment都需要一个唯一标识符ID,用来在Activity restart 的时候恢复Fragment。有三种方法可以提供ID:
(1)android:id a unique ID
(2)android:tag a unique string
(3)container view的ID 当(1)(2)都没有设置的话
* Or, programmatically add the fragment to an existing ViewGroup
.(在代码中,动态添加fragment到一个已存在的ViewGroup中)
想要在Activity中动态添加(替换/删除)Fragment,需要FragmentTransaction
类的实例。该类的实例可通过下面方法获得:
FragmentManager fragmentManager = getFragmentManager()
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
添加Fragment:通过add()方法 (当然还有replace/remove等方法,具体参考官方文档)
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
Note:add方法的第一个参数是ViewGroup对象的ID,用来添加fragment。 当操作完成后,还需要调用FragmentTransaction::commit方法,才能奏效。
Adding a fragment without a UI(添加一个无UI的fragment,这个情况我没用过,官方文档说 比如进行后台操作的时候,就不用界面了)
通过 add(Fragment, String)方法添加此Fragment对象。第二个参数是一个字符串,作为tag,唯一识别该Fragment。因为没有UI,就无法设置android:id这类的属性了,就只能通过这里的tag来获取该Fragment了(使用方法
findFragmentByTag (String tag) 来获取Fragment)。
上面讲完了”创建Fragment“ / ”加载Fragment到Activity“后,接下来说说如何管理Fragment
Managing Fragments(管理Fragment)
最开始需要先获取 FragmentManager
类对象,通过getFragmentManager()
方法。FragmentManager对象可以做以下几件事情:
- Get fragments that exist in the activity, with
findFragmentById()
(for fragments that provide a UI in the activity layout) orfindFragmentByTag()
(for fragments that do or don't provide a UI). - Pop fragments off the back stack, with
popBackStack()
(simulating a Back command by the user). - Register a listener for changes to the back stack, with
addOnBackStackChangedListener()
.
Performing Fragment Transactions(操作Fragment)
在Activity中使用Fragment很大的特征就是添加/删除/替换。每次把对Fragment所作的操作被称为一个transaction。当commit 这个 transaction 到Activity里时,需要另一个类 FragmentTransaction。该类对象的获取方法如下:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
然后进行add()
, remove()
, and replace() 等方法。然后通过commit() 提交transaction到Activity中。
Note:当调用commit()方法前,可以调用addToBackStack()方法将transaction添加到 back stack 中(这个back stack是由Activity管理的)。当用户按返回键后,就可以返回到Fragment执行transaction之前的状态了。
// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null); // Commit the transaction
transaction.commit();
当提交”删除Fragment“的transaction时,如果不调用addToBackStack方法,那么这个Fragment就destroyed了,用户就回不到之前的Fragment了。但反之,调用了addToBackStack方法后再调用commit方法,那么 这个Fragment只是处于stopped状态,按返回键后,就可以resume该Fragment。
当然,如果你一次性对Fragment进行很多操作,然后调用一次commit()方法,系统还是会将这一系列操作作为一次transaction的。
Communicating with the Activity(与Activity交互)
Activity中:通过调用getFragmentManager方法,获得FragmentManager实例。然后通过 findFragmentById()
or findFragmentByTag()方法获得Fragment。
Fragment中:通过getActivity方法获得Activity的Context,然后通过findViewById方法获得Activity布局中的控件。
Creating event callbacks to the activity(让Activity响应Fragment的事件)
一个很好的方法就是:
1.在Fragment中实现一个接口,包含一些回调方法。
2.让Activity实现这个接口。
public static class FragmentA extends ListFragment {
...
// Container Activity must implement this interface
public interface OnArticleSelectedListener {
public void onArticleSelected(Uri articleUri);
}
...
}
这样,当Activity接受到回调方法时,就能够获得Fragment的信息,并且能将信息传递给其他Fragment了。
那怎么在Fragment中怎么调用Activity的实例,为它设置回调方法呢?可以通过getActivity方法,但是更好的是在onAttach方法中,因为onAttach方法的参数就是Fragment所在的Activity的实例。那么,就可以在onAttach方法中将Activity实例强制转换成接口对象了。
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");
}
}
...
}
--------------------------------------------------------------------------------------------------
OK,就讲到这里了,下面给出一个小例子,先上图:
代码结构截图:
代码如下:
package com.cb.fragmenttest; import com.cb.listener.OnTitleItemClickListener; import android.os.Bundle;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.util.Log; public class MainActivity extends Activity implements OnTitleItemClickListener {
private static final String TAG = "MainActivity"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate");
} @Override
public void onItemClick(int position) {
Log.d(TAG, "onItemClick: position is "+position);
ContentFragment contentFragment = (ContentFragment) getFragmentManager().findFragmentById(R.id.content_fragment);
contentFragment.updateContent(position);
}
}
主Activity::MainActivity.java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" > <fragment
android:id="@+id/title_fragment"
android:name="com.cb.fragmenttest.TitleFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" /> <fragment
android:id="@+id/content_fragment"
android:name="com.cb.fragmenttest.ContentFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" /> </LinearLayout>
MainActivity::activity_main.xml
两个Fragment:TitleFragment、ContentFragment
package com.cb.fragmenttest; import com.cb.listener.OnTitleItemClickListener;
import com.cb.utils.Constants; import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView; public class TitleFragment extends Fragment implements OnItemClickListener {
private static final String TAG = "TitleFragment";
private ListView mListView;
private OnTitleItemClickListener mCallback; @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated");
} @Override
public void onAttach(Activity activity) {
super.onAttach(activity);
Log.d(TAG, "onAttach: " + activity);
try {
mCallback = (OnTitleItemClickListener) activity;
} catch (ClassCastException e) {
e.printStackTrace();
}
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
View view = inflater.inflate(R.layout.title_fragment, container, false);
mListView = (ListView) view.findViewById(R.id.list);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, Constants.mTitle);
mListView.setAdapter(adapter);
mListView.setOnItemClickListener(this);
return view;
} @Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Log.d(TAG, "onItemClick: arg2 is "+arg2);
mCallback.onItemClick(arg2);
} }
TitleFragment.java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Titles"
android:textColor="#0000ff" /> <ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> </LinearLayout>
TitleFragment::title_fragment.xml
package com.cb.fragmenttest; import com.cb.utils.Constants; import android.app.Activity;
import android.app.Fragment;
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 ContentFragment extends Fragment{
private static final String TAG = "ContentFragment"; private TextView mTextView; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
View view = inflater.inflate(R.layout.content_fragment, container, false);
mTextView = (TextView)view.findViewById(R.id.text);
return view;
} public void updateContent(int position) {
Log.d(TAG, "updateContent, mContent["+position+"] is "+Constants.mContent[position]);
mTextView.setText(Constants.mContent[position]);
} }
ContentFragment.java
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linear2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Contents"
android:textColor="#0000ff"
android:textIsSelectable="true" /> <ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp" />
</ScrollView> </LinearLayout>
ContentFragment::content_fragment.xml
接口文件
package com.cb.listener; public interface OnTitleItemClickListener {
void onItemClick(int position);
}
MainActivity需要实现的接口
常量类
package com.cb.utils; public class Constants { public static final String[] mTitle = { "Monday", "Tuesday", "Wednesday" }; public static final String[] mContent = {
"Monday (Listeni/ˈmʌndeɪ/ or /ˈmʌndi/) is the day of the week between Sunday and Tuesday. According to the traditional Christian, Islamic and Hebrew calendars, it is the second day of the week. But according to international standard ISO 8601 it is the first day of the week. The name of Monday is derived from Old English Mōnandæg and Middle English Monenday, which means \"moon day\".",
"Tuesday (Listeni/ˈtjuːzdeɪ/, /ˈtjuːzdi/, /ˈtuːzdeɪ/ or /ˈtuːzdi/) is a day of the week occurring after Monday and before Wednesday. According to some commonly used calendars (esp. in the US), it is the third day of the week, but according to international standard ISO 8601, it is the second day of the week. The English name is derived from Old English Tiwesdæg and Middle English Tewesday, meaning \"Tīw's Day\", the day of Tiw or Týr, the god of single combat, victory and heroic glory in Norse mythology. Tiw was equated with Mars in the interpretatio romana, and the name of the day is a translation of Latin dies Martis.",
"Wednesday (Listeni/ˈwɛdənzdeɪ/, Listeni/ˈwɛnzdeɪ/[1] or /ˈwɛnzdi/[2]) is the day of the week between Tuesday and Thursday. According to international standard ISO 8601 adopted in most western countries it is the third day of the week. In countries that use the Sunday-first convention Wednesday is defined as the fourth day of the week. It is the fourth day of the week in the Judeo-Christian calendar as well, and was defined so in the ancient Mesopotamian and biblical calendars. The name is derived from Old English Wōdnesdæg and Middle English Wednesdei, \"day of Wodanaz\", ultimately a calque of dies Mercurii \"day of Mercury\"." +
"Wednesday is in the middle of the common Western five-day workweek that starts on Monday and finishes on Friday." };
}
用到的一些常量
fragment的介绍与使用的更多相关文章
- Android开发之Fragment的介绍、使用及生命周期
Fragment官网介绍-http://developer.android.com/guide/components/fragments.html 郭大神的使用实例文章:http://blog.csd ...
- Android Fragment的介绍与使用(案例Demo)
应用场景: 众所了解Android上的界面展示都是通过Activity实现的,可是Activity也有它的局限性,相同的界面在手机上显示可能非常好看,在平板上就未必了.为了让界面能够在平板上更好地展示 ...
- Fragment之介绍(转)
http://www.cnblogs.com/plokmju/p/3239265.html 前言 开门见山开篇名义,本篇博客将讲解一下Android中Fragment的内容,必要的地方会提供相应的演示 ...
- Android Fragment 基本介绍
Fragment 源码:http://www.jinhusns.com/Products/Download/?type=xcj Android是在Android 3.0 (API level 11)开 ...
- Android Fragment 基本介绍[转]
Fragment Android是在Android 3.0 (API level 11)开始引入Fragment的. 可以把Fragment想成Activity中的模块,这个模块有自己的布局,有自己的 ...
- 【转】Android Fragment 基本介绍--不错
原文网址:http://www.cnblogs.com/mengdd/archive/2013/01/08/2851368.html Fragment Android是在Android 3.0 (AP ...
- android的fragment基本介绍
可以分为下面的几部分: 使用支持库 创建一个Fragment 创建一个动态UI 多个Fragment之间的通信 1.使用支持库 如果您的应用需要运行在3.0及以上的版本,可以忽略这部分内容. 如果您的 ...
- [原]Android Fragment 入门介绍
Fragment Fragment 产生,优点,用途,使用方法简介 1 Fragmeng简介 自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片.片段.其上的是为 ...
- Fragment基本介绍
1.生命周期 onCreateView() :创建视图 onActivityCreate():activity创建完成的时候调用 onDestoryView():销毁视图 onDetach():与ac ...
随机推荐
- dmesg功能介绍
dmesg 命令的使用范例 ‘dmesg’命令设备故障的诊断是非常重要的.在‘dmesg’命令的帮助下进行硬件的连接或断开连接操作时,我们可以看到硬件的检测或者断开连接的信息.‘dmesg’命令在多数 ...
- Shell中的${}、##和%%使用范例
假设定义了一个变量为,代码如下: file=/dir1/dir2/dir3/my.file.txt 可以用${ }分别替换得到不同的值: ${file#*/}: 删掉第一个 / 及其左边的字符串:di ...
- hadoop生态搭建(3节点)-08.kafka配置
如果之前没有安装jdk和zookeeper,安装了的请直接跳过 # https://www.oracle.com/technetwork/java/javase/downloads/java-arch ...
- 使用bison和yacc制作脚本语言(2)
我们先来想一下语法 一般脚本语言不需要定义类型直接在赋值的时候确定 我们主要考虑一下变量的类型 a = 1; b = 1.1; c = "str"; 一般来讲,我们使用这三种类型, ...
- C语言判断字符串是否旋转过
//方法一 //每次左旋一次,判断旋转之后字符串是否与目标字符串是否一致 //旋转一圈 没有找到返回0 #define _CRT_SECURE_NO_WARNINGS #include<stdi ...
- NUCLEO-L053R8 RCC时钟树 MCO输出
RCC时钟配置实验 最近玩了一下Nucleo-L053R8板子,即STM32L053R8T6.浏览了RCC章节后,顺便做了个小实验,现在给大伙分享一下. 实验非常简单,配置一下系统时钟,可以通过肉眼观 ...
- 一个java新手配置IIS服务器的血泪史
接到一个二次开发项目,听说是asp页面,带着不要怂的态度于是接下了. 好嘛按照步骤来 1.了解需求:一个公司内部积分排名类型项目,已经被多次开发,我所需要的就是新增两个页面,一个是分店赛一个是分部赛. ...
- 面向切面编程(AOP)
一.引言: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中 ...
- 单节锂电池充电(电路)芯片TP4056
- 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1
原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1 事件聚合器EventAggregator [7.1updated]除了app部分,没 ...