Categories
程式開發

第一行代碼——Android(三):活動的實踐技巧


編者按:本文節選自郭霖著《第一行代碼——Android》一書中的部分章節。

活動的最佳實踐

你已經掌握了關於活動非常多的知識,不過恐怕離能夠完全靈活運用還有一段距離。雖然知識點只有這麼多,但運用的技巧卻是多種多樣的。所以,在這裡我準備教你幾種關於活動的最佳實踐技巧,這些技巧在你以後的開發工作當中將會非常有用。

活動的最佳實踐:知曉當前是在哪一個活動

這個技巧將教會你如何根據程序當前的界面就能判斷出這是哪一個活動。可能你會覺得挺納悶的,我自己寫的代碼怎麼會不知道這是哪一個活動呢?很不幸的是,在你真正進入到企業之後,更有可能的是接手一份別人寫的代碼,因為你剛進公司就正好有一個新項目啟動的概率並不高。閱讀別人的代碼時有一個很頭疼的問題,就是當你需要在某個界面上修改一些非常簡單的東西時,卻半天找不到這個界面對應的活動是哪一個。學會了本節的技巧之後,這對你來說就再也不是難題了。

我們還是在ActivityTest項目的基礎上修改,首先需要新建一個BaseActivity類。右擊com.example.activitytest包→New→Java Class,在彈出的窗口出輸入BaseActivity,如圖1所示。

第一行代碼——Android(三):活動的實踐技巧 1

圖 1 創建BaseActivity

注意這裡BaseActivity和普通活動的創建方式並不一樣,因為我們不需要讓BaseActivity在AndroidManifest.xml中註冊,所以選擇創建一個普通的Java類就可以了。然後讓BaseActivity繼承自AppCompatActivity,並重寫onCreate()方法,如下所示:

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
    }
}

我們在onCreate()方法中獲取了當前實例的類名,並通過Log打印了出來。

接下來我們需要讓BaseActivity成為ActivityTest項目中所有活動的父類。修改FirstActivity、SecondActivity和ThirdActivity的繼承結構,讓它們不再繼承自AppCompatActivity,而是繼承自BaseActivity。而由於BaseActivity又是繼承自AppCompatActivity的,所以項目中所有活動的現有功能並不受影響,它們仍然完全繼承了Activity中的所有特性。

現在重新運行程序,然後通過點擊按鈕分別進入到FirstActivity、SecondActivity和ThirdActivity的界面,這時觀察logcat中的打印信息,如圖2所示。

第一行代碼——Android(三):活動的實踐技巧 2

圖 2 BaseActivity中的打印日誌

現在每當我們進入到一個活動的界面,該活動的類名就會被打印出來,這樣我們就可以時時刻刻知曉當前界面對應的是哪一個活動了。

活動的最佳實踐:隨時隨地退出程序

如果目前你手機的界面還停留在ThirdActivity,你會發現當前想退出程序是非常不方便的,需要連按3次Back鍵才行。按Home鍵只是把程序掛起,並沒有退出程序。其實這個問題就足以引起你的思考,如果我們的程序需要一個註銷或者退出的功能該怎麼辦呢?必須要有一個隨時隨地都能退出程序的方案才行。

其實解決思路也很簡單,只需要用一個專門的集合類對所有的活動進行管理就可以了,下面我們就來實現一下。

新建一個ActivityCollector類作為活動管理器,代碼如下所示:

public class ActivityCollector {

    public static List activities = new ArrayList();

    public static void addActivity(Activity activity) {
        activities.add(activity);
    }

    public static void removeActivity(Activity activity) {
        activities.remove(activity);
    }

    public static void finishAll() {
        for (Activity activity : activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
        activities.clear();
    }

}

在活動管理器中,我們通過一個List來暫存活動,然後提供了一個addActivity()方法用於向List中添加一個活動,提供了一個removeActivity()方法用於從List中移除活動,最後提供了一個finishAll()方法用於將List中存儲的活動全部銷毀掉。

接下來修改BaseActivity中的代碼,如下所示:

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }

}

BaseActivityonCreate()方法中調用了ActivityCollectoraddActivity()方法,表明將當前正在創建的活動添加到活動管理器裡。然後在BaseActivity中重寫onDestroy()方法,並調用了ActivityCollectorremoveActivity()方法,表明將一個馬上要銷毀的活動從活動管理器裡移除。

從此以後,不管你想在什麼地方退出程序,只需要調用ActivityCollector.finishAll()方法就可以了。例如在ThirdActivity界面想通過點擊按鈕直接退出程序,只需將代碼改成如下所示:

public class ThirdActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("ThirdActivity", "Task id is " + getTaskId());
        setContentView(R.layout.third_layout);
        Button button3 = (Button) findViewById(R.id.button_3);
        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityCollector.finishAll();
            }
        });

    }
}

當然你還可以在銷毀所有活動的代碼後面再加上殺掉當前進程的代碼,以保證程序完全退出,殺掉進程的代碼如下所示:

android.os.Process.killProcess(android.os.Process.myPid());

其中,killProcess()方法用於殺掉一個進程,它接收一個進程id參數,我們可以通過myPid()方法來獲得當前程序的進程id。需要注意的是,killProcess()方法只能用於殺掉當前程序的進程,我們不能使用這個方法去殺掉其他程序。

活動的最佳實踐:啟動活動的最佳寫法

啟動活動的方法相信你已經非常熟悉了,首先通過Intent構建出當前的“意圖”,然後調用startActivity()startActivityForResult()方法將活動啟動起來,如果有數據需要從一個活動傳遞到另一個活動,也可以藉助Intent來完成。

假設SecondActivity中需要用到兩個非常重要的字符串參數,在啟動SecondActivity的時候必須要傳遞過來,那麼我們很容易會寫出如下代碼:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("param1", "data1");
intent.putExtra("param2", "data2");
startActivity(intent);

這樣寫是完全正確的,不管是從語法上還是規範上,只是在真正的項目開發中經常會有對接的問題出現。比如SecondActivity並不是由你開發的,但現在你負責的部分需要有啟動SecondActivity這個功能,而你卻不清楚啟動這個活動需要傳遞哪些數據。這時無非就有兩種辦法,一個是你自己去閱讀SecondActivity中的代碼,二是詢問負責編寫SecondActivity的同事。你會不會覺得很麻煩呢?其實只需要換一種寫法,就可以輕鬆解決掉上面的窘境。

修改SecondActivity中的代碼,如下所示:

public class SecondActivity extends BaseActivity {

    public static void actionStart(Context context, String data1, String data2) {
        Intent intent = new Intent(context, SecondActivity.class);
        intent.putExtra("param1", data1);
        intent.putExtra("param2", data2);
        context.startActivity(intent);
    }
    ...
}

我們在SecondActivity中添加了一個actionStart()方法,在這個方法中完成了Intent的構建,另外所有SecondActivity中需要的數據都是通過actionStart()方法的參數傳遞過來的,然後把它們存儲到Intent中,最後調用startActivity()方法啟動SecondActivity。

這樣寫的好處在哪裡呢?最重要的一點就是一目了然,SecondActivity所需要的數據在方法參數中全部體現出來了,這樣即使不用閱讀SecondActivity中的代碼,不去詢問負責編寫SecondActivity的同事,你也可以非常清晰地知道啟動SecondActivity需要傳遞哪些數據。另外,這樣寫還簡化了啟動活動的代碼,現在只需要一行代碼就可以啟動SecondActivity,如下所示:

button1.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        SecondActivity.actionStart(FirstActivity.this, "data1", "data2");
    }
});

養成一個良好的習慣,給你編寫的每個活動都添加類似的啟動方法,這樣不僅可以讓啟動活動變得非常簡單,還可以節省不少你同事過來詢問你的時間。

圖書簡介https://www.ituring.com.cn/book/1841

第一行代碼——Android(三):活動的實踐技巧 3

相關閱讀

第一行代碼——Android(一):前行必備,如何使用日誌工具

第一行代碼——Android(二):掌握活動的生命週期