首先说明一下,下面的总结都是根据官方的文档来总结的,所以图片、代码段什么的都是官方的,大家不要见外就行了,能学到东西就好。
这个不多说了。
如果因为系统资源紧张而导致Activity被Destory, 用户回到这个Activity时系统会有这个Activity存在过的记录,系统会使用那些保存的记录数据(描述了当Activity被Destory时的状态)来重新创建一个新的Activity实例。那些被系统用来恢复之前状态而保存的数据叫做"instance state" ,它是一些存放在Bundle对象中的键 值对.
例如:
Activity会在每次旋转屏幕时被Destroy与Recreate。当屏幕改变方向时,系统会Destory与Recreate前台的Activity,因为屏幕配置被改变,相应的Activity可能需要加载一些可选的资源(例如layout).
默认情况下, 系统使用Bundle实例来保存每一个视图对象中的信息(例如输入EditText中的文本内容,这个EditText需要有一个id才可以)。因此,如果Activity被Destroy与Recreate, 那么layout的状态信息会自动恢复到之前的状态。然而,Activity也许存在更多需要恢复的状态信息,例如记录用户进程的成员变量。
为了可以保存额外更多的数据到saved instance state,在Activity的声明周期里面需要一个添加的回调函数onSaveInstanceState()。
@Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save the user's current game state savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); // Always call the superclass so it can save the view hierarchy state //必须要调用onSaveInstanceState()方法的父类实现,这样默认的父类实现才能保存视图状态的信息。
super.onSaveInstanceState(savedInstanceState); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Always call the superclass first // Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) { // Restore value of members from saved state mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // Probably initialize members with default values for a new instance } ... }
这个只适合保存少量的状态信息,如果需要保存大量的数据,如bitmap对象,这种方法不适合的,后面我会讲到这种情况(下面第四条),你也可以参考一下官方的文档:
http://developer.android.com/guide/topics/resources/runtime-changes.html
为了允许Fragment与它的activity交互,你可以在fragment类中定义一个接口并且在activity中实现它。fragment可以在onAttach()方法中获取接口的实现并调用接口的方法与activity交互。其实无论是Fragment与它的Activity交互,还是Fragment之间的交互,最好都这样来实现,让Activity来统一管理。
public class HeadlinesFragment extends ListFragment { OnHeadlineSelectedListener mCallback; // Container Activity must implement this interface public interface OnHeadlineSelectedListener { public void onArticleSelected(int position); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { mCallback = (OnHeadlineSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener"); } } ... }
现在fragment可以使用OnHeadlineSelectedListener的实例mCallback调用onArticleSelected()方法(或者其他接口内的方法)提供信息给activity了。 例如,当 用户点击list item(list子项)时就会调用下面在fragment的方法。fragment使用回调接口提供事件到父的activity。
@Override public void onListItemClick(ListView l, View v, int position, long id) { // Send the event to the host activity mCallback.onArticleSelected(position); }
为了接收来自fragment的事件回调,主activity(你需要用来与fragment交互的activity)必须实现定义在fragment类中的接口。
public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(Uri articleUri) { // The user selected the headline of an article from the HeadlinesFragment // Do something here to display that article } }
一些设备配置在运行过程中可能会发生改变(例如屏幕横向布局、键盘可用性和语言)。当这样的变化发生时,Android会重新启动这个正在运行的Activity(onDestroy()方法会被调用,然后调用onCreate()方法)
如果重启你的Activity,你需要恢复大量的数据,重新执行网络连接,或者其他深入的操作,这样由配置改变引起的一次完全启动就会引起不好的用户体验。而且,仅有Activity生命周期中为你保存的的Bundle对象,你是不可能完全维护你的Activity的状态的—不能传递很大的对象(如bitmap对象),并且这些对象里面的数据必须序列化,然后解序列化,这些都需要消耗很多内存从而使配置改变得很慢。在这样的情境下,当你的Activity由于配置发生改变而重启时,你可以通过重新预置一个有状态的对象来减缓你程序的负担。
在运行期间配置改变时维护一个对象:
public class RetainedFragment extends Fragment { // data object we want to retain private MyDataObject data; // this method is only called once for this fragment @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // retain this fragment setRetainInstance(true); } public void setData(MyDataObject data) { this.data = data; } public MyDataObject getData() { return data; } }
然后使用FragmentManager向活动添加片段。运行配置更改时活动重启,就可以从片段获取数据对象。例如按照如下方式定义活动:
public class MyActivity extends Activity { private RetainedFragment dataFragment; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // find the retained fragment on activity restarts FragmentManager fm = getFragmentManager(); dataFragment = (DataFragment) fm.findFragmentByTag(“data”); // create the fragment and data the first time if (dataFragment == null) { // add the fragment dataFragment = new DataFragment(); fm.beginTransaction().add(dataFragment, “data”).commit(); // load the data from the web dataFragment.setData(loadMyData()); } // the data is available in dataFragment.getData() ... } @Override public void onDestroy() { super.onDestroy(); // store the data in the fragment dataFragment.setData(collectMyLoadedData()); } }
此例中onCreate()添加片段或者恢复引用。onCreate()也在片段示例中存储了状态对象。onDestroy()更新了保留的片段示例中的状态对象。
创建一个隐式的Intent并不声明要启动的组件的类名,而是声明要执行的一个动作(action),这个action详述了你想要做的事,比如观看,编辑,发送或是获取一些数据。Intent也经常在action里附加相关的数据,比如你想访问的地址,或是你发送邮件的内容。根据你想创建的intent,数据可能是一个Uri或是其它数据类型,也可能不包含任何数据。
尽管Android平台确保特定的intent会被解析到一个内建的应用程序(比如电话,短信,日历),你仍然需要在使用intent前进行一下确认。如果你发起一个在设备上无法被任何应用程序处理的intent,那么你的程序就会崩溃。
为了确认有一个activity能响应该intent,可以使用queryIntentActivities()来获取一个能处理该intent的activity列表,如果返回的列表非空,那么你就可以安全的使用这个intent了。例如:
PackageManager packageManager = getPackageManager(); List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0); boolean isIntentSafe = activities.size() > 0;
如果 isIntentSafe为真,那么至少有一个程序会响应该intent,反之,则没有。
以下是一个完整的例子,它向你展示了如何创建一个可以访问地图的的intent。先确定有一个可以处理该intent的程序,再启动它。
//创建intent Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"); Intent mapIntent = new Intent(Intent.ACTION_VIEW, location); // 确定它可以被处理 PackageManager packageManager = getPackageManager(); List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0); boolean isIntentSafe = activities.size() > 0; // 如果安全的话,启动一个activity if (isIntentSafe) { startActivity(mapIntent); }