Android Studio教程03-Activtiy生命周期的理解

来源:https://www.cnblogs.com/haochen273/archive/2019/01/16/10279185.html
-Advertisement-
Play Games

[TOC] 1. Activity 1.1. 安卓中的Activity定義和特性: 一個Activity就是一個屏幕頁面 一個APP中有很多個Activity(打開郵件app,打開具體郵件) APP一般從MainActivity中啟動的,當然了,這個也可以修改的 APP內的Activity可以通過一 ...


目錄

1. Activity

1.1. 安卓中的Activity定義和特性:

  • 一個Activity就是一個屏幕頁面
  • 一個APP中有很多個Activity(打開郵件app,打開具體郵件)
  • APP一般從MainActivity中啟動的,當然了,這個也可以修改的
  • APP內的Activity可以通過一些方法(Intent...)進行切換(打開郵件app -> 打開具體郵件)
  • APP之間的Activity也可以互相切換(從瀏覽器頁面 -> facebook頁面)

1.2. 註冊Activity

進入AndroidManifest.xmlapplication下添加一個activity元素

1. Intent filters:設置預設開啟的activity

Intent filters可以顯示或者隱式的啟動activity,我們可以利用這個屬性來擴展activity功能

<activity 
  android:name=".MainActivity"
  android:label="FirstPage"
  android:icon="@drawable/app_icon">
  <!--intent-filter放在哪個activity,這個actiivty就是預設啟動的activity-->
    <intent-filter>
        <!--action:這個activity可以發送數據-->
        <action android:name="android.intent.action.SEND" />
        <!--category:這個activity可以接收請求-->
        <category android:name="android.intent.category.DEFAULT" />
        <!--data:這個activity可以接收數據類型-->
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

<activity
  android:name=".SecondActivity"
  android:label="SecondPage"
  ></activity>

程式調用過程

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
// Start the activity
startActivity(sendIntent);

1.3. Activity的啟動流程

插入activity01.md
插入activity02.md

1.4. 如何控制activity中的內容

通過代表控制項的對象來更改控制項內容

2. Android的生命周期

首先我們來看一下谷歌官網發佈的圖

聲明周期函數 調用時機 所處狀態 應該執行的操作
onCreate 在Activity對象第一次創建時調用 Created 初始化操作(只執行一次的操作)
調用setContentView()設置界面佈局
onStart 當Activity變得可見時調用該函數 Started 組件的初始化操作,建議放再onResume中
onResume 當Activity開始準備與用戶交互時調用該方法 Resumed 最常見的操作都需要放在這裡(最重要的部分)
onPause 當系統即將開啟另外一個Activity之前調用 Paused 停止一些可能影響電池的操作,清除一些輕度的占用CPU任務(關閉相機)
onStop 當前Activity變得不可見時調用 Stopped 當屏幕不可見的時候,清除或者調整一些操作
保存資料庫的最好位置
onDestroy 當前Activity被銷毀之前將會調用 清除所有占用記憶體的任務
onRestart 當一個Activity再起啟動之前會調用 -> Resumed

onCreate()

  • 作用: 初始化 + 進入啟動階段
  • 在Activity對象第一次被創建時調用,必須重寫
  • 那麼在onCreate() 應該執行一些什麼操作呢?
    • 在整個生命周期只需要執行一次的操作
    • 初始化 Activity 的必需組件
    • 調用setContentView()來定義用戶界面的佈局
  • 接收的參數為savedInstanceState:表示活動前所保存的狀態,如果這個活動之前沒有啟動過,那麼Bundle的值為null
  • onCreate() 之後:進入啟動階段
TextView mTextView;

// some transient state for the activity instance
String mGameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // 調用父類的onCreate方法
    super.onCreate(savedInstanceState);

    // recovering the instance state
    if (savedInstanceState != null) {
        mGameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // 設置界面佈局文件(res/layout/main_activity.xml)
    setContentView(R.layout.main_activity);

    // 初始化一些部件,這樣在下麵的方法中可以操作
    mTextView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    mTextView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// invoked when the activity may be temporarily destroyed, save the instance state here
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, mGameState);
    outState.putString(TEXT_VIEW_KEY, mTextView.getText());

    // call superclass to save any view hierarchy
    super.onSaveInstanceState(outState);
}

onStart()

  • 作用: 使Activity可見,可視化頁面會顯示出來 + 進入Resume階段
  • 特性:
    • 完成得特別快
    • 一旦執行完成,直接進入onResume()階段
    • 所有生命周期組件會收到onStart()事件

onResume()

  • 作用: app可以和用戶交互
  • 特性:
    • app會一直停留在這個階段,直到有什麼操作打斷他(來電話啦...)
    • 所有生命周期組件會收到onResume()事件
    • 當有異常時,會進入暫停階段,處罰onPause()方法
    • 當異常結束重新進入Resume階段時,又會重新調用onResume()
    • 你應該在這段代碼中寫一些初始化組件的代碼
  • 建議: 如果在onStart()中初始化一些組件後,記得在onStop()釋放

onPause()

  • 當acitivty不再前端的時候(即使在多視窗模式中,它是visible模式), app進入這個階段
  • 使用onPause()方法來停止或者調整操作,當activity不再主界面的時候
  • acitivity進入這個階段的原因如下:
    • 一些中斷了app運行
    • 多視窗模式下,一個app啟動會自動讓另外的app進入onpause狀態
    • 有些情況下,即使activity是visible模式,它也會進入這個onPause階段
  • 所有生命周期組件會收到onPause()事件,這裡我們可以停止一些操作
  • 這個階段的任務:
    • 可以停止一些你不想運行的操作(關閉camera..)
    • 釋放一些系統資源,處理sensors或者其他會影響電源的組件(但是推薦使用onStop()方法
    • 千萬不要在這裡保存數據,網路操作,或者資料庫操作
    • 註意: 完成這個階段並不意味著activity離開了onPause階段,如果acitivty進入Resume階段,調用onResume,如果actiivty完全不可見,進入onStop()階段,否則一直在onPause階段
public class JavaCameraComponent implements LifecycleObserver {

    ...
    // 一旦收到`onPause`事件。釋放camera
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }

    ...
}

onStop()

  • 什麼時候發生:activity完全不可見
  • 所有生命周期組件會收到onStop()事件,這裡我們可以停止一些操作
  • 在這個階段的任務
    • 釋放一些heavy的任務
    • 關閉一些CPU重的任務
    • 這是保存到資料庫的絕佳位置
    @Override
    protected void onStop() {
    // call the superclass method first
    super.onStop();
    
    // save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());
    
    // do this update in background on an AsyncQueryHandler or equivalent
    mAsyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            mUri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
    }

onDestroy()

  • 進入這個階段的原因:
    • activity完成(用戶取消activity,或者調用了finish()方法)
    • 系統自動刪除activity(手機轉動,或者多視窗模式下)
  • 所有生命周期組件會收到onDestroy()事件,這裡我們可以所有需要停止的東西

3. Activity生命周期被回收的幾率表

被殺的可能性 過程狀態 Activity狀態
最小 前端 Created
Started
Resumed
中等 後端(lost focus) Paused
最高 後端(不可見)
Stopped
destroyed

4. 保存和儲存短暫的UI狀態

考慮如下兩種情況

  • 用戶轉換屏幕或者切換到多視窗模式時,系統會預設摧毀之前的activity,但是用戶希望能夠保持原來的activity不變
  • 用戶有時候可能一不小心從當前app切換到其他app,系統會預設摧毀之前的activity,當然我們希望用戶切換回來的時候還是保持當前的狀態

解決方法: 保存UI狀態:ViewModel + obSaveInstanceState()

4.1. Instance state

  • 系統用於保存之前狀態的過程為Instance state--其實是一些保存在Bundle對象的鍵值對
  • 系統預設使用BundleInstance state來保存每個View的信息(比如EditText中的文本)

4.2.通過onSaveInstanceState()保存一些輕度,簡單的UI狀態

  • 當Activity準備停止的時候,系統就會調用onSaveInstanceState()來保存一些基本的信息,比如edittext中的value..
  • 如果你想要保存更多的內容,需要重寫onSaveInstanceState()方法,添加新的key-value對到Bundle對象中
  • 如果重寫onSaveInstanceState()方法,一定調用super implmenetaion
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@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
    super.onSaveInstanceState(savedInstanceState);
}

4.3. 通過保存的UI狀態恢複活動的UI

  • 我們可以在onCreateonRestoreInstanceState()中調用Bundle對象來恢復UI
    • onCreate:只有當創建一個新的activtiy實例,才會調用這個方法,必須堅持Bundle是否為空,空的話,創建新的實例,不是空的話,恢復之前的UI
    • onRestoreInstanceState():這個方法在onStart()方法之後調用,系統只會在Bundle不為空的時候調用,所以你不用檢查是否為null
// method 1
@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
    }
    // ...
}

// method2
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

5.Activity之間是如何切換的?

5.1 從一個Activity切換到另外一個Activity:

1. startActivity()

  • 如果不需要返回一個結果,就用這個
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

你也可以通過startActivity啟動一些以後的組件來擴展功能(調用Email的app)

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

The EXTRA_EMAIL extra added to the intent is a string array of email addresses to which the email should be sent. When an email application responds to this intent, it reads the string array provided in the extra and places them in the "to" field of the email composition form. In this situation, the email application's activity starts and when the user is done, your activity resumes.

2.startActivityForResult()

  • 當你需要從即將結束的Activity中返回一個值的時候用這個,比如你從當前activity的列表中選中一個水果,你想要保存這個選中的水果
  • 當有一個子類Activity的時候,它可以調用setResult(int)來返回數據給他的父類Activity
  • 父類Activity使用onActivityResult(int, int, Intent) 來獲取信息
public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

6.實例演示Activity的生命周期

創建兩個activity: mainactivity和otheractivity

public class OtherActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        System.out.println("--OtherActivity: OnCreate--");
    }

    @Override
    protected void onStart() {
        super.onStart();
        System.out.println("--OtherActivity: OnStart--");
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("--OtherActivity: OnResume--");
    }

    @Override
    protected void onPause() {
        super.onPause();
        System.out.println("--OtherActivity: OnPause--");
    }

    @Override
    protected void onStop() {
        super.onStop();
        System.out.println("--OtherActivity: OnStop--");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("--OtherActivity: OnDestroy--");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        System.out.println("--MainActivity: OnRestart--");
    }
}

otherActivity也差不多,然後執行程式

當程式呈現第一個頁面的時候,列印的信息是:

當點擊按鈕,進入第二個activity的時候:

當點擊返回按鈕返回主activity的時候:


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 背景:聽說ClassLoader類載入機制是進入BAT的必經之路。 ClassLoader總述: 普通的Java開發其實用到ClassLoader的地方並不多,但是理解透徹ClassLoader類的載入機制,無論是對我們編寫更高效的代碼還是進BAT都大有裨益;而從“黃埔軍校”出來的我對ClassLo ...
  • 近日在虛擬機下的QT5.11.2安裝出現了一個bug,折騰好久才搞定。 環境:vmware + debain 9.5 + qt5.11.2 。 QT_DIR = /Qt5.11.2/5.11.2/gcc_64/mkspecs 找了各大網站、博客,基本都是說直接安裝openGL的,然而我的虛擬機安裝o ...
  • 前面介紹瞭如何從Bird類繼承而來Swallow類,按道理子類應當繼承父類的所有要素,但是對於構造方法來說,Swallow類僅僅繼承了Bird類的預設構造方法,並未自動繼承帶參數的構造方法。如果子類想繼續使用父類的其它構造方法,就得自己重寫心儀的構造方法。例如老鷹屬於鳥類,那麼可以編寫繼承自Bird ...
  • 在前面有篇博客,我寫了一個叫forms組件的東西,可以幫助我們完成校驗數據、渲染標簽功能和在前端頁面局部刷新功能,功能封裝的已經很好了,當時已經很開心了。但萬萬沒想到,還有比它功能更強大的東西。forms組件只能渲染出type=text類型的標簽,而且還要我們寫無數多個欄位,然後跟上校驗條件,用fo ...
  • 1. 有一個已經排好序的列表。現輸入一個數,要求按原來的規律將它插入列表中 分析:已經排好序的列表也可能是升序也可能是降序,需要先確定列表的排序方式以升序為例,需要考慮4主要種情況: Case1:小於列表的第一個值,則插入第一個 如s=[2,3,4],插入1,則結果應該為[1,2,3,4],1插入的 ...
  • 基於終端指令的持久化存儲 保證爬蟲文件的parse方法中有可迭代類型對象(通常為列表or字典)的返回,該返回值可以通過終端指令的形式寫入指定格式的文件中進行持久化操作; 執行輸出指定格式進行存儲:將爬取到的數據寫入不同格式的文件中進行存儲 基於管道的持久化存儲 scrapy框架中已經為我們專門集成好 ...
  • 中介這個詞語在現實生活中很常見,我們買房租房找中介,通過中介完成買賣房屋,買房和賣方直接和中介交流,完成交易合同。 房產中介,第三方平臺,支付寶這些等都屬於中介。他們在中間從當一個中間人的作用,承擔交易雙方的業務流程。 核心:中介者對象,該對象使一些複雜的業務處理簡化,使各業務處理對象直接和中介者打 ...
  • 1 import numpy as np 2 3 # 1、快速排序 4 ''' 5 1、np.sort(),不改變原先值的順序,但是在運行時占記憶體 6 2、ndarry.sort(),改變原先值的順序,不占用記憶體 7 ''' 8 # 不改變n1的順序 9 n1 = np.array([2, 5, 8... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...