AT-Fragment
关于Fragment的粗略翻译
英文版api地址:Fragment(自备梯子)
Fragment
类概述(Class Overview):
Fragment是一种可以替换Activity的用户界面。与Fragment进行交互的话,得通过Fragmentmanager来实现,而要获得FragmentManager有两种方法:Activity.getFragmentManager()和Fragment.getFragmentManager().
你可以通过多种方式来使用Fragment,从而实现许多效果。Fragment的主要核心是:它代表的是一系列的运行在Activity中的特殊操作或接口。Fragment被紧紧绑定在Activity上,不可分开。尽管Fragment定义了自己的一套生命周期,但是它的生命周期还得要依赖于它绑定的那个Activity的生命周期:当一个Activity停止了(stopped),这个Activity里面不会有Fragment是启动(started)状态的;当一个Activity被销毁了(destroyed),它里面的所有Fragment都应该是被销毁(destroyed)的状态。
而对于所有的Fragment的子类来说,它们都必须包括一个公有的无参构造函数(public no-argument constructor)。因为Framework层会经常重新初始化一些有需要的Fragment,尤其是在Fragment实例状态恢复(restore)时,它需要去找到那个对应的无参构造函数去初始化构造实例。所以说在当没有找到那个无参构造函数时,有时候会在实例状态恢复时报一个运行时异常(a runtime exception) 开发引导(Developer Guides)
如果你想获得更多的关于怎样使用Fragment的话,请阅读Fragment的开发引导
老版本平台(Older Platforms)
因为Fragment的API是在 HONEYCOMB 版本开始被引进的,但是在跟老的版本上面,我们可以通过 FragmentActivity 来使用它的API。
生命周期(Lifecycle)
尽管Fragment的声明周期是绑定在它的Activity上的,但是在一个标准的Actvity生命周期上,里面的Fragment生命周期仍然是有规律可循的。Fragment的生命周期中包括了一些Activity生命周期已有的方法,比如:onResume(),这些方法与Activity、UI层的交互有着联系,所以显得十分重要。
下面是一系列方法,用来将fragment恢复状态
- onAttach(Activity) 当Fragment要绑定在Activity时调用
- onCreate(Bundle) 当初始化创建Fragment时会调用
- onCreateView(LayoutInflater,ViewGroup,Bundle) 创建并且返回和对应的Fragment有关的视图
- onActivityCreated(Bundle) 告诉Fragment,和它绑定的那个Activity已经执行完对应的Activity.onCreate()方法了。
- onViewStateRestored(Bundle) 告诉Fragment,它的视图里面的所有数据状态都得到恢复了,前提是先前储存了状态信息哦。
- onStart() 使Fragment对于用户变得可见(前提是和它绑定的Activity已经是被启动了的)
- onResume() 使Fragment开始变得可以处理用户的交互了(前提是和它绑定的Activity已经是处于恢复状态了的,即onResume())
当Fragment不再被使用时,它会执行相反的一系列回调
- onPause() Fragment不再接受用户交互,因为可能此时Activity已经被停止了(onPause()) ,或者的话就是在Activity里面执行一些Fragment操作。
- onStop() Fragment不再可见,因为可能此时Activity已经被停止了(onStop()),或者的话就是在Acytivity里面执行了一些Fragment操作。
- onDestroyView() 允许Fragment去清除那些和它的视图有关的的资源
- onDestroy() 最终清除Fragment的状态信息
- onDetach() 当Fragment不再和Activity有联系时,即解除了绑定时,会快速调用本方法。
该属性可以被用在<fragment>中来为一个Fragment提供特殊的标签名字该属性可以被用在<fragment>中来为一个Fragment提供特殊的标签名字
Fragment可以被用来作为你的应用布局的一部分,它可以让你模块化你的代码,并且可以在应用运行时更加容易的调整你的界面布局。下面举一个简单例子,这个简单的例子中会包括一个ListView用来展示一系列的内容,并且可以在你点击了其中一个时展示所选选项的具体内容。
你可以在一个Activity的布局文件中来嵌入一个Fragment实例,方法是通过使用<fragment>标签。比如,下面就是一个例子,展示了怎样在布局文件中嵌入Fragment实例
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="@+id/titles"
android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>
接下来你可以通过常规的方法来将该布局设置到指定的Activity上面去
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setContentView(R.layout.fragment_layout);
}
接下来我们会创建一个TitleFragment,用来展示一系列标题,我们实现它的话非常简单,因为我们继承的是ListFragment,ListFragment为我们做了大部分的工作。并且实现点击事件的方法:关于点击后产生的效果,我们会针对不同的布局产生不同的点击效果,其中包括在原视图布局中来显示点击后对应的详细内容,也可以启动一个新的Activity来显示点击后对应的详细内容。
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0; @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); // Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES)); // Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE; if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
} if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
} @Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
} @Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
} /**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index; if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true); // Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index); // Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (index == 0) {
ft.replace(R.id.details, details);
} else {
ft.replace(R.id.a_item, details);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
} } else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
还有另一个DetailsFragment来显示对应点击项后对应的内容,显示的内容会因为点击项的不同而显示不同的内容
public static class DetailsFragment extends Fragment {
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static DetailsFragment newInstance(int index) {
DetailsFragment f = new DetailsFragment(); // Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args); return f;
} public int getShownIndex() {
return getArguments().getInt("index", 0);
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
} ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());
int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
4, getActivity().getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);
text.setText(Shakespeare.DIALOGUE[getShownIndex()]);
return scroller;
}
}
考虑一下当这种情况时:当用户点击了TitleFragment中的其中一个选项时,此时在当前布局中装不下DetailsFragment时,我们该怎么办?所以此时我们应该启动一个新的Activity来显示点击项对应的内容
public static class DetailsActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); if (getResources().getConfiguration().orientation
== Configuration.ORIENTATION_LANDSCAPE) {
// If the screen is now in landscape mode, we can show the
// dialog in-line with the list so we don't need this activity.
finish();
return;
} if (savedInstanceState == null) {
// During initial setup, plug in the details fragment.
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content, details).commit();
}
}
}
然而,当我们写的应用运行在屏幕特别大的设备上面时,此时屏幕大到可以同时显示TitleFragment和DetailsFragment时,我们就要考虑将这两个Fragment同时放在同一个视图中,而不是点击后弹出另一个新的视图来显示内容。所以我们此时可以提供另一个可供选择的布局文件,需要注意的是:你应该把它命名为和上面的布局相同的名称,并且放在layout-land文件夹下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent" android:layout_height="match_parent"> <fragment class="com.example.android.apis.app.FragmentLayout$TitlesFragment"
android:id="@+id/titles" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent" /> <FrameLayout android:id="@+id/details" android:layout_weight="1"
android:layout_width="0px" android:layout_height="match_parent"
android:background="?android:attr/detailsElementBackground" /> </LinearLayout>
此时,现有的代码会调整可选择的UI布局:当应用在运行时,对应指定的参数变化时,对应的DetailsActivity会终止(finish()),而去显示嵌入了DetailsFragment的TitleFragment。
当指定参数发生变化时,会导致Activity中的Fragment重新启动,此时重新启动后的新实例也许会使用一个不同于先前布局的新布局。在这种情况下时,先前所有的Fragment将会重新实例初始化,并且以新的实例来运行。然而此时,它将和原先的<fragment>不再有联系,也不会再创建内容视图,并且会在 isInLayout() 方法中返回 false (这里的代码也就展示了当一个Fragment 不再运行在布局中时,你怎样避免创建视图层级结构 )。PS:下划线部分我也理解不了,暂时这样翻译吧,有理解的大神在底下请指出来,谢谢。
当Fragment视图被绑定到父容器布局中时,<fragment>属性标签将会被用来操控提供的LayoutParams。他们也可以作为 onInflate(Activity,AttributeSet,Bundle) 方法的参数而被解析。
当与指定Fragment绑定的父Activity需要销毁或者重新创建时,对应的Fragment将被重新初始化创建,此时就要求有一些唯一的标示来将原先的实例和新创建的实例来联系起来。而这些唯一的标示可以这样来提供:
- 当没有任何明确的使用时,放置这些Fragment的容器(父布局)的id将会被拿来使用
- android:tag 该属性可以被用在<fragment>中来为一个Fragment提供特殊的标签名字
- android:id 该属性可以被用在<fragment>中来为一个Fragment提供特殊的标签名字sds
上面的例子Google官网只是提供了片段,具体的完整代码请戳 这儿
后退栈(Back Stack)
Fragment的事务操作可以被放在对应的Activity的后退栈中,当用户在Activity中点击返回键时,只要对应的Activity没有被结束(finished),则可以一直从栈里面弹出对应的事务操作。
举个例子,考虑现在有一个简单的Fragment(CountFragment),它可以通过一个整数数字作为参数(Integer)来初始化,并且可以将对应的整数展示在Fragment创建好的视图中。
public static class CountingFragment extends Fragment {
int mNum; /**
* Create a new instance of CountingFragment, providing "num"
* as an argument.
*/
static CountingFragment newInstance(int num) {
CountingFragment f = new CountingFragment(); // Supply num input as an argument.
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args); return f;
} /**
* When creating, retrieve this instance's number from its arguments.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : ;
} /**
* The Fragment's UI is just a simple text view showing its
* instance number.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.hello_world, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Fragment #" + mNum);
tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
return v;
}
}
现在我们可以写一个方法,这个方法可以创建一个新的Fragment实例,可以替换任何现在正在展示给用户的、可见的Fragment实例,并且可以将这些替换变化压到对应的后退栈中去。具体怎样实现这个方法,如下所示:
void addFragmentToStack() {
mStackLevel++; // Instantiate a new fragment.
Fragment newFragment = CountingFragment.newInstance(mStackLevel); // Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.simple_fragment, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
在每次调用上面的方法后,一个新的条目会加到对应的栈里面,当用户点击返回的时候,会从栈里面弹出上一次保存的视图
AT-Fragment的更多相关文章
- 浅谈 Fragment 生命周期
版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Fragment 文中如有纰漏,欢迎大家留言指出. Fragment 是在 Android 3.0 中 ...
- 札记:Fragment基础
Fragment概述 在Fragment出现之前,Activity是app中界面的基本组成单位,值得一提的是,作为四大组件之一,它是需要"注册"的.组件的特性使得一个Activit ...
- EventBus实现activity跟fragment交互数据
最近老是听到技术群里面有人提出需求,activity跟fragment交互数据,或者从一个activity跳转到另外一个activity的fragment,所以我给大家介绍一个开源项目,EventBu ...
- Android:Activity+Fragment及它们之间的数据交换.
Android:Activity+Fragment及它们之间的数据交换 关于Fragment与Fragment.Activity通信的四种方式 比较好一点的Activity+Fragment及它们之间 ...
- Android中Fragment和ViewPager那点事儿(仿微信APP)
在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...
- Android开发学习—— Fragment
#Fragment* 用途:在一个Activity里切换界面,切换界面时只切换Fragment里面的内容* 生命周期方法跟Activity一致,可以理解把其为就是一个Activity* 定义布局文件作 ...
- Android中Fragment与Activity之间的交互(两种实现方式)
(未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...
- Android中Fragment的两种创建方式
fragment是Activity中用户界面的一个行为或者是一部分.你可以在一个单独的Activity上把多个Fragment组合成为一个多区域的UI,并且可以在多个Activity中再使用.你可以认 ...
- Android Fragment 剖析
1.Fragment如何产生?2.什么是Fragment Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视.针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后 ...
- ILJMALL project过程中遇到Fragment嵌套问题:IllegalArgumentException: Binary XML file line #23: Duplicate id
出现场景:当点击"分类"再返回"首页"时,发生error退出 BUG描述:Caused by: java.lang.IllegalArgumentExcep ...
随机推荐
- [Bhatia.Matrix Analysis.Solutions to Exercises and Problems]ExI.4.1
Let $x,y,z$ be linearly independent vectors in $\scrH$. Find a necessary and sufficient condition th ...
- opencv 在工业中的应用:圆孔定位
在工业中产品或者夹具上经常有圆形孔,我们可以利用这些孔来对产品或者夹具进行定位.我用OPENCV写了个DEMO 程序,介绍如下: (1)首先点击打开图像按钮打开一幅图像 (2)进行一些参数设置 (3) ...
- Pyhton 一行代码求Fibonacci第N项
递归定义很简单,效率当然很低下,且极易超出栈空间大小. 这样做纯粹是为了体现python的语言表现力而已, 并没有任何实际意义. def fib(x): return fib(x-1) + fib(x ...
- android NDK 实用学习(三)- java端类对象的构造及使用
1,读此文章前我假设你已经读过: android NDK 实用学习-获取java端类及其类变量 android NDK 实用学习-java端对象成员赋值和获取对象成员值 2,java端类对象的构造: ...
- 深入prototype源码之--Class
由于工作需要项目中要用prototype框架,所以这几天捣鼓了一下,研究了一下prototype 创建对象和类以及继承的一些源码,其实早在很久以前就接触prototype,然后直接看源码, 看着太蛋疼 ...
- Hadoop概念学习系列之谈谈RPC(三十三)
RPC-------->远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数 ...
- nyoj 16 矩形嵌套
矩形嵌套 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a& ...
- Google maps library的使用
公司的项目中用到了google地图API, 使用Google API开发就会用到Marker, 用来在google 地图上标注位置 但是google marker使用过程中也有个问题,就是如果在goo ...
- 表单,css
- .NET 基础 一步步 一幕幕[面向对象之静态、非静态]
静态.非静态 先来看一段代码来区分静态与非静态: using System; using System.Collections.Generic; using System.Linq; using Sy ...