Android开发实战总结--入门篇

首先说明一下,下面的总结都是根据官方的文档来总结的,所以图片、代码段什么的都是官方的,大家不要见外就行了,能学到东西就好。

一、Activity生命周期
Android开发实战总结--入门篇_第1张图片

这个不多说了。

二、onSaveInstanceState

Android开发实战总结--入门篇_第2张图片

如果因为系统资源紧张而导致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);
}
恢复状态在onCreate方法或者onRestoreInstanceState方法中
@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之间交互

为了允许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由于配置发生改变而重启时,你可以通过重新预置一个有状态的对象来减缓你程序的负担。

在运行期间配置改变时维护一个对象:

  1. 扩展片段类,并且声明引用状态对象。
  2. 创建片段时调用setRetainInstance(boolean)。
  3. 向活动添加片段。
  4. 活动重启时使用FragmentManager来检索片段。
    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

创建一个隐式的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);
}

你可能感兴趣的:(Android开发实战总结--入门篇)