第四章 Activity 活動元件

建立Activity元件

開始寫應用程式時, 通常都是先撰寫Activity元件, 用來建立要顯示的視窗. 不過如果是寫Service, BroadcastReceiver時, 那就另當別論了

建立Activity的步驟, 第一是先設計UI, 也就是先安排res/layout裏的xml檔, 再來是宣告Activity類別, 然後覆寫需要的方法(記得, 快速鍵是Ctrl+O), 然後再將Activity登記在設定檔AndroidManifest.xml裏

一支apk, 可能會有n個畫面, 那就需要有n個Activity元件. 當apk被啟動, 第一個出現的畫面, 叫主畫面元件. 主畫面Activity的設定檔中需要有如下藍色字標示的設定

<activity ....>
   <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
   </intent-filter>
</activity>

Android Support Library

Android一直拼命的更新版本, 而且沒有milestone(里程計畫), 這讓很多公司卻步. 因為這些公司不知道何時才會支援他們所期待的功能, 也不知道現有的bug何時才能解決. 而他們存放在倉庫裏的SOC(Single on Chip)動則上千萬新台幣, 如果Google隔天突然發佈新版本, 而且不支援倉庫裏的SOC, 這下就血本無歸了.

Google當然聽到這些廠商的心聲, 但除了無奈又能如何. 2007年初, iOS的出現, 讓Google措手不及. 站在商業立場, 當然要立馬推出可以與之匹敵的產品, 否則慢了一年以上, 就絕無翻身的機會.
所以2007年底出現的第一代Android, 除了爛, 還是爛. 身為神一般的Google為什麼要推出這麼多bug的產品呢!! 因為那時的iOS也是只有一個字~~爛梨子假蘋果(好像不是只有一個字喔). 反正大家都在搶時機, 就先推出再說囉, 到時後再來補丁(patch)一下就好. 這微軟真的是大家的好榜樣啊, sp1, sp2, sp3 推的理所當然似的@_@.

現在的Android 跟以前比起來, 真的改了太多的東西了. 所以新版的API 在以前的機器上是跟本無法執行的, 因為舊型的機器少了太多的函數庫了(Library). 於是Google使用一個賤招, 就是把新的函數庫一併包進apk裏, 讓舊版的機器也能執行. 只是apk會變的很肥就是了. 管他的, 能跑就好, 不是嗎.

這個函數庫, 就叫Android Supoort Library. v4版可以支援到Android 1.6, v7版可以支援到Android 2.1

不過, Android 4.2 己經是骨灰級的產品了, 所以如果需要撰寫能支援這之前的產品, 那~~您的業障就真的蠻深的.

Activity生命周期

Activity的生命周期極為重要, 請先撰寫如下的程式碼, 並進行測試

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toast.makeText(this, "onCreate", Toast.LENGTH_LONG).show();
    }
    @Override
    protected void onStart() {
        super.onStart();
        Toast.makeText(this, "onStart", Toast.LENGTH_LONG).show();
    }
    @Override
    protected void onResume() {
        super.onResume();
        Toast.makeText(this, "onResume", Toast.LENGTH_LONG).show();
    }
    @Override
    protected void onPause() {
        super.onPause();
        Toast.makeText(this, "onPause", Toast.LENGTH_LONG).show();
    }
    @Override
    protected void onStop() {
        super.onStop();
        Toast.makeText(this, "onStop", Toast.LENGTH_LONG).show();
    }
    @Override
    protected void onRestart() {
        super.onRestart();
        Toast.makeText(this, "onRestart", Toast.LENGTH_LONG).show();
    }
    @Override protected void onDestroy() {
        super.onDestroy(); 
        Toast.makeText(this, "onDestory", Toast.LENGTH_LONG).show(); 
    }
}

android_life_cycle

當上述的程式碼編譯完成後, 請依如下順序操作, 並背記執行的結果

啟動執行 : onCreat -> onStart -> onResume
按返回鍵 : onPause -> onStop -> onDestory
此狀況為apk正常的執行流程, 按下返回鍵後,  apk 正式結束, 且不會再消耗CPU資源, 但應用程式並沒有從Ram中清除


啟動執行 : onCreat -> onStart -> onResume
按Home : onPause -> onStop
重新執行 : onRestart –> onStart -> onResume
按下Home鍵, 只是把apk退居背景(background)並退到onStop階段, 此時apk還是會消耗CPU資源. 當重新啟動後, 因為不需再重新載入, 會很快的從onStart開始


按Power鍵關閉螢幕 : onPause –> onStop
按Power鍵開啟螢幕 : onRestart –> onStart() –> onResume();
此狀況同上按Home鍵


螢幕旋轉
onPause –> onStop –>onDestroy –> onCreate –> onStart –> onResume
旋轉螢幕時, 等於是完成後續結束的動作, 然後再重頭重新啟動一次


另一種狀況是當現今的Activity被另一個設為Dialog的Activity蓋住了部份時, 會進入onPause.
當蓋住的Dialog移除後, 直接進入onResume
但是如果使用dialog.Builder時,則都是一直在running中,因為是Activity的行程


各階段函數的行為如下

protected void onCreate() : 僅執行一次
protected void onStart() : 進入前景即執行
protected void onResume() : 啟動或回復元件需要的工作
protected void onRestart() : 只有從onStop進入onStart時, 才會啟動
protected void onPause() : 退居背景, 但還看得到部份畫面
protected void onStop() : 退居背景, 而且看不到畫面
protected void onDestroy() : 準備清除這個元件

Activity元件狀態

Activity分為作用中及非作用中. 從onCreate一直到Running中, 都是作用中. 而從onPause到onDestroy都叫非作用中. 程式就算到了onDestroy結束後, 還是不會從Ram中清除的, 這是為了加速第二次執行的速度, 此時叫空行程. 若想清除空行程, 則必需按下Menu鍵, 然後一個一個移除
android_menu

當資源不足時,系統會自動砍掉行程,依序如下

空行程 : 最先砍
背景行程 : 不可見非service程序
服務行程 : 背景service
可見行程 : 在前景執行的行程,準備被另一個Activity覆蓋時。若砍到此行程,穩要重新開機了
活動行程 : 非重新開機不可了

Android Logcat

logcat可用來查詢裝置目前正在執行的狀況, 方便debug用. 通常會在程式碼中加入如
Log.d(“標簽”, “訊息”), 然後於Android Studio下方的Android Monitor/logcat視窗就可查詢, 若Log.d()有被執行到, 就可看到這個標簽及訊息

另外可以在DOS模式下輸入
adb logcat 標簽:D *:S 或者是
沒有*:s 預設全部列印, 但標簽除外不列印
有*:S  預設全部不列印(silent), 但標簽除外需列印
標簽後面的D為優先順序, 先後順序為 : V/D/I/W/E/F

Toast

像烤麵包機一樣, 土司會自動跳出的意思, Toast裏的方法都是static 方法, 所以使用如下語法
Toast.makeText(Context, “訊息”, 時間長度).show();

時間長度有 Toast.LENGTH_LONG, Toast.LENGTH_SHORT這二種

Context

Context : 一個很神奇的東西, 即代表著Activity本身這個活動元件, 指名這個訊息是要在那個活動元件印出來的意思. 注意, Activity, Service及BroadcastReceiver都有Context, 而整個App也有一個Context.

Context是一個抽像類別, 提供應用程式環境的全域資訊接口, 可以取得應用程式的資源和類別本身. 提供了應用程式級別的操作, 如啟動Activity, 發送廣播, 接收Intent等.

總之, Context提供了一些特別的方法

android_context

如果是在匿名類別裏使用Toast, 則要使用活動元件的類別名稱, 再加上this. 如MainActivity.this

Button b=new Button(this);
b.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Toast.makeText(MainActivity.this,"按鈕被按了", Toast.LENGTH_LONG);
    }
});

若是在非Activity的元件或其他類別中要印出Toast, 通常會把Activity的 this, 傳到要處理的方法中, 使用Context 這個型態來接收

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *