Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 學習整理 — 從安卓源碼上看Activity

學習整理 — 從安卓源碼上看Activity

編輯:關於Android編程

安卓開發的四大組件是Activity, service, broadcast receiver, 和content provider。作為業余的開發者,可能不需要太深入理解這些組件的內部實現,以及運行機制。但是如果想要在這方面有所進階的話,這些實現的源碼還是要啃的。本文將從官方源碼上講一下對Activity的理解。

 

概述

定義

官方對Activity的開頭描述為:

 

/**
An activity is a single, focused thing that the user can do. 
Almost all activities interact with the user, 
so the Activity class takes care of creating a window for you in which you can place your UI with setContentView(int). 
While activities are often presented to the user as full-screen windows, 
they can also be used in other ways: as floating windows (via a theme with android.R.attr set) 
or embedded inside of another activity (using ActivityGroup). 
There are two methods almost all subclasses of Activity will implement:
    onCreate(android.os.Bundle) is where you initialize your activity. 
    Most importantly, here you will usually call setContentView(int) with a layout resource defining your UI, 
    and using findViewById(int) to retrieve the widgets in that UI that you need to interact with programmatically.
    
    onPause() is where you deal with the user leaving your activity. 
    Most importantly, any changes made by the user should at this point be 
    committed (usually to the android.content.ContentProvider holding the data). 
**/

從安卓四大組件來看,Activity是唯一的可以與用戶進行交互的組件,所以activity可以創建一個窗口並通過調用setContentView(int)來設定窗口的UI。

而且,Activity的表現形式不限於占據整個屏幕,還可以是一個懸浮窗口或者被嵌入到其他的Activity中。

Activity狀態

接著再來看一個Acitivity的生命周期,雖然網上有很多對Activity生命周期的解釋,但還是貼上源碼上的注釋:

 

/**
Activities in the system are managed as an activity stack. When a new activity is started, 
it is placed on the top of the stack and becomes the running activity -- the previous activity 
always remains below it in the stack, and will not come to the foreground again until the new activity exits.

An activity has essentially four states:
    1.If an activity in the foreground of the screen (at the top of the stack), it is active or running.
    2.If an activity has lost focus but is still visible (that is, a new non-full-sized or transparent activity
      has focus on top of your activity), it is paused. A paused activity is completely alive 
      (it maintains all state and member information and remains attached to the window manager), 
      but can be killed by the system in extreme low memory situations.
    3.If an activity is completely obscured by another activity, it is stopped. 
      It still retains all state and member information, however, 
      it is no longer visible to the user so its window is hidden and it will often be killed by the system 
      when memory is needed elsewhere.
    4.If an activity is paused or stopped, the system can drop the activity from memory by either asking it to finish, 
      or simply killing its process. When it is displayed again to the user, 
      it must be completely restarted and restored to its previous state.
**/
從解釋中可以知道,系統是以stack的形式來管理Activity,當一個新的Activity開始時,它將處於該stack的頂部(棧頂)並成為running activity。

 

一個Activity的有四種狀態,分別是:

1.Active或者running,當Activity處在前台,即屏幕的最前面時。

2.Paused,當Activity失去焦點但依然可見時,典型的情況是有個警告框彈出到屏幕的最前面。在這個狀態下,Activity失去焦點不可接受用戶的交互。當系統極端缺乏內存時,該Activity依然有可能被系統殺死。

3.Stopped,當Activity完全不可見後。

4.killed或者恢復,一個Activity處在paused或者stopped狀態下,系統可以選擇回收這個Activity的內存,進而殺死該Activity,或者在系統回收之前,用戶重新將該Activity帶到前台,進而恢復了它。要注意,系統的這種選擇不受人為干預,所以開發要時刻注意Activity被殺死的情況。

 

生命周期類型

注釋上還將Activity的生命周期按照特征分成了幾種類型:

 

/**

    1.The entire lifetime of an activity happens between the first call to onCreate(android.os.Bundle) through 
      to a single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(), 
      and release all remaining resources in onDestroy(). 
      For example, if it has a thread running in the background to download data from the network, 
      it may create that thread in onCreate() and then stop the thread in onDestroy().
    2.The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). 
      During this time the user can see the activity on-screen, though it may not be in the foreground and interacting 
      with the user. Between these two methods you can maintain resources that are needed to show the activity to the user. 
      For example, you can register a android.content.BroadcastReceiver in onStart() to monitor for changes that 
      impact your UI, and unregister it in onStop() when the user no longer sees what you are displaying. 
      The onStart() and onStop() methods can be called multiple times, as the activity becomes visible and hidden to the user.
    3.The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause(). 
      During this time the activity is in front of all other activities and interacting with the user. 
      An activity can frequently go between the resumed and paused states -- for example when the device goes to sleep, 
      when an activity result is delivered, when a new intent is delivered -- 
      so the code in these methods should be fairly lightweight. 
**/

1.完整生命周期(entire lifetime),從一個Activity被創建分配內存到內存被系統回收。

2.可視生命周期(visible lifetime),成對出現的onStart()與onStop()之間的時間,能夠為用戶所見。

3.前台生命周期(foregroud lifetime),成對出現的onResume()與onPause()之間的時間,能夠為用戶所見並交互

通過上面的解釋,不難得出網上隨處可見Activity生命周期圖表。

\

看著生命周期圖,對照著官方注釋,來看各個回調函數的源碼

 

回調函數

onCreate

 

/**
Called when the activity is starting. 
This is where most initialization should go: calling setContentView(int) to inflate the activity's UI, 
using findViewById(int) to programmatically interact with widgets in the UI, 
calling managedQuery(android.net.Uri,java.lang.String[],java.lang.String,java.lang.String[],java.lang.String) to 
retrieve cursors for data being displayed, etc.
You can call finish() from within this function, 
in which case onDestroy() will be immediately called without any of the rest of the activity 
lifecycle (onStart(), onResume(), onPause(), etc) executing.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.

Parameters:
    savedInstanceState If the activity is being re-initialized after previously 
    being shut down then this Bundle contains the data it most recently supplied in onSaveInstanceState(android.os.Bundle). 
    Note: Otherwise it is null.

**/
    protected void onCreate(@Nullable Bundle savedInstanceState) {

         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);

         if (mLastNonConfigurationInstances != null) {

             mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
         }
         if (mActivityInfo.parentActivityName != null) {
             if (mActionBar == null) {
                 mEnableDefaultActionBarUp = true;
             } else {
                 mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
             }
         }
         if (savedInstanceState != null) {
             Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
             mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                     ? mLastNonConfigurationInstances.fragments : null);
         }
         mFragments.dispatchCreate();
         getApplication().dispatchActivityCreated(this, savedInstanceState);
         if (mVoiceInteractor != null) {
             mVoiceInteractor.attachActivity(this);
         }
         mCalled = true;
     }
當一個Activity被創建的時候,系統將回調該activity的onCreate()方法,但分清楚該方法並不是創建一個Activity。從源碼上看,系統調用該方法,主要做了一些關於Activity的狀態變量的修改。為了保存系統管理Acitivity的一致性,開發者重寫該方法時,要求調用該父類方法。當一個Activity實例被創建後,系統只會僅此一次地調用該方法,所以該方法裡適合做一些create views, bind data to lists等等的工作。要注意該方法的可空Bundle類參數savedInstanceState,只有在系統配置被修改後,系統需要快速殺死Activity並重新創建以適應系統環境時,系統才會自動加入該參數調用,裡面保存的是Activity被銷毀前的用戶交互情況。典型的情況的設備設置了橫屏,如果用戶在一個輸入框輸入了一些字符,然後發生轉屏事件,由於當前Activity是在豎屏時建立的,它並不適合橫屏,所以系統需要將當前Activity銷毀並重新按照橫屏標准創建一個新的Activity。但由於考慮用戶輸入情況,系統不應該將用戶在轉屏前的輸入狀態在銷毀——重建的過程中丟失掉,所以系統在銷毀Activity前將信息傳入該bundle,再在重建時加入該bundle以還原輸入狀態。

 

onStart

 

/**
Called after onCreate(android.os.Bundle) — or after onRestart() when the activity had been stopped, 
but is now again being displayed to the user. It will be followed by onResume().

Derived classes must call through to the super class's implementation of this method. 
If they do not, an exception will be thrown.
**/

    protected void onStart() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
        mCalled = true;
        if (!mLoadersStarted) {

            mLoadersStarted = true;
            if (mLoaderManager != null) {
                mLoaderManager.doStart();
            } else if (!mCheckedForLoaderManager) {
                mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
            }
            mCheckedForLoaderManager = true;
        }
        getApplication().dispatchActivityStarted(this);
    }
當Activity展現在前台時,換句話說,系統在渲染好UI之後,將調用該方法。內部實現的是一些狀態變量的修改,調用更底層的函數。

 

onResume

 

/**
Called after onRestoreInstanceState(android.os.Bundle), onRestart(), or onPause(), 
for your activity to start interacting with the user. 
This is a good place to begin animations, open exclusive-access devices (such as the camera), etc.

Keep in mind that onResume is not the best indicator that your activity is visible to the user; 
a system window such as the keyguard may be in front. 
Use onWindowFocusChanged(boolean) to know for certain that your activity is visible to the user (for example, to resume a game).

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/

    protected void onResume() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
        getApplication().dispatchActivityResumed(this);
        mActivityTransitionState.onResume();
        mCalled = true;
    }
當Activity可以開始與用戶進行交互時,系統將調用該方法。它與onStart()的調用時機不用在於,UI渲染完後還沒綁定監聽函數,所以用戶是不可交互的,這時調用onStart()。在屏幕各個位置上綁定完監聽監聽函數後,即用戶點擊屏幕將可以得到交互時,系統調用onResume()函數。這就解釋了為什麼一個警告框在Activity上懸浮或消失時,Activity的生命周期只處於onPause()和onResume(),因為懸浮下的Activity是可見的,它只是失去了屏幕與監聽函數的綁定,所以當警告框消失後UI不需要重新繪制,只需要能夠讓屏幕與監聽函數重新綁定即可,故onStart()就沒有被調用。而如果Activity退出前台後,它在重返前台前需要經過UI的繪制渲染,所以此時會調用onStart()。

 

onPause

 

/**
Called as part of the activity lifecycle when an activity is going into the background, 
but has not (yet) been killed. The counterpart to onResume().

When activity B is launched in front of activity A, this callback will be invoked on A. 
B will not be created until A's onPause() returns, so be sure to not do anything lengthy here.

This callback is mostly used for saving any persistent state the activity is editing,
to present a "edit in place" model to the user and making sure nothing is lost 
if there are not enough resources to start the new activity without first killing this one.
This is also a good place to do things like stop animations and other things that consume a noticeable 
amount of CPU in order to make the switch to the next activity as fast as possible, 
or to close resources that are exclusive access such as the camera.

In situations where the system needs more memory it may kill paused processes to reclaim resources. 
Because of this, you should be sure that all of your state is saved by the time you return from this function. 
In general onSaveInstanceState(android.os.Bundle) is used to save per-instance state in the activity and this method 
is used to store global persistent data (in content providers, files, etc.)

After receiving this call you will usually receive a following call to onStop()
 (after the next activity has been resumed and displayed), 
however in some cases there will be a direct call back to onResume() without going through the stopped state.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/
    protected void onPause() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
        getApplication().dispatchActivityPaused(this);
        mCalled = true;
    }
當一個Activity離開前台進入後台前,系統將調用該方法。要注意,Activity進入的後台(background)的意思,可以簡單理解為Activity變得不可交互時。根據系統的定義,一個Activity在系統調用onPause()後隨時有可能被killed掉,所以任何需要保存的狀態、信息需要在這個函數裡保存。不應該在onPause()做耗時的操作,因為onPause()完後之前,其他Activity不能夠顯示出來。

 

 

/**
Called when you are no longer visible to the user. You will next receive either onRestart(), onDestroy(), or nothing, 
depending on later user activity.

Note that this method may never be called, in low memory situations where the system does not have 
enough memory to keep your activity's process running after its onPause() method is called.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/
    protected void onStop() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
        if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
        mActivityTransitionState.onStop();
        getApplication().dispatchActivityStopped(this);
        mTranslucentCallback = null;
        mCalled = true;
    }
當Activity不再可視後,系統將調用該方法。需要注意,系統需要殺死Activity來獲得更多的內存時,並不會調用該方法。

 

onStop

 

/**
Called after onStop() when the current activity is being re-displayed to the user (the user has navigated back to it). 
It will be followed by onStart() and then onResume().

For activities that are using raw android.database.Cursor objects 
(instead of creating them through managedQuery(android.net.Uri,java.lang.String[],java.lang.String,java.lang.String[],java.lang.String),
 this is usually the place where the cursor should be requeried (because you had deactivated it in onStop().

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/

    protected void onRestart() {
        mCalled = true;
    }

當Activity將再次展示在前台時,系統將調用該方法。

onDestroy

 

 

/**
Perform any final cleanup before an activity is destroyed. 
This can happen either because the activity is finishing (someone called finish() on it, 
or because the system is temporarily destroying this instance of the activity to save space. 
You can distinguish between these two scenarios with the isFinishing() method.

Note: do not count on this method being called as a place for saving data! 
For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() 
or onSaveInstanceState(android.os.Bundle), not here. 
This method is usually implemented to free resources like threads that are associated with an activity, 
so that a destroyed activity does not leave such things around while the rest of its application is still running.
There are situations where the system will simply kill the activity's hosting process without calling this method 
(or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.

Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
**/
    protected void onDestroy() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onDestroy " + this);
        mCalled = true;
        // dismiss any dialogs we are managing.

        if (mManagedDialogs != null) {
            final int numDialogs = mManagedDialogs.size();
            for (int i = 0; i < numDialogs; i++) {
                final ManagedDialog md = mManagedDialogs.valueAt(i);
                if (md.mDialog.isShowing()) {
                    md.mDialog.dismiss();
                }
            }
            mManagedDialogs = null;
        }

        // close any cursors we are managing.
        synchronized (mManagedCursors) {
            int numCursors = mManagedCursors.size();
            for (int i = 0; i < numCursors; i++) {
                ManagedCursor c = mManagedCursors.get(i);
                if (c != null) {
                    c.mCursor.close();
                }
            }
            mManagedCursors.clear();
        }
        // Close any open search dialog
        if (mSearchManager != null) {
            mSearchManager.stopSearch();
        }
        getApplication().dispatchActivityDestroyed(this);
    }
當Activity調用finish()後或者系統需要銷毀該Activity時,系統將調用該方法。要注意,系統依然可以選擇不調用該方法而直接銷毀Activity。

 

總結:

1.Activity生命周期的回調函數是系統在進行下一步操作前後調用的,以供開發者在各個階段前後實現一些操作;

2.某些回調函數的父類實現比較簡單,但都是打通一個Activity生命周期的重要操作。所以為了保持Activity的一致性,避免開發者不理解整一個生命周期原理,Android強制要求在重寫這些回調函數時需要調用父類實現;

3.Activity的生命周期中onCreate()只會調用一次,需要適合一個全局變量的賦值,監聽函數的設定,而onStart()和onResume()可能會被多次調用,所以不適合在方法裡創建對象,因為調用一次,之前的對象就是成了垃圾。垃圾多了,對程序對系統都不是一件好事;

4.某些情況下,系統可以越過onStop()和onDestroy()而直接殺死Activity,所以一些重要信息的保存要放在onPause()裡;

5.Activity的運作原理就是系統對各種回調函數的調用,開發者無法控制一個Activity的生命周期,但可以在其生命周期中定制一些實現,讓其能夠按照定義一般運行下去;

5.在Activity裡可以找到很多函數,最大程序上保證了一個Activity能夠實現的工程,這表示了一個系統多麼精巧而缜密的。比如一個onKeyDown()回調函數,用以監測一個用戶的輸入情況。但按鍵的監測也是一個系統行為,它會按照傳遞等級一層一層地將輸入情況向下傳遞,如果輸入在某一層得到處理,返回true以表示讓系統不再將輸入情況向下傳遞,返回false則表示在這層沒得到處理,系統可以繼續向下傳遞。等等。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved