1. 程式人生 > >Android產品研發(三)-->基類Activity

Android產品研發(三)-->基類Activity

在上一篇文章中我們介紹了在Android產品研發過程中,啟動頁的優化工作,比如啟動頁效能優化,啟動頁漸進動畫效果,啟動頁遮蔽返回按鍵等等,而在本文中我們將要介紹一下在App產品研發中都會複寫的基類Activity,具體可參考:Android產品研發(二)–>啟動頁優化

在實際的Android產品研發中,一般的我們在寫Activity的時候都會繼承於一個基類Activity,該Activity是所有的Activity的基類。在該基類中我們主要用於重寫一些共有的邏輯。好處是顯而易見的對於一些Activity的共有邏輯我們不必要在每個Activity中都重新寫一遍,只需要在基類Activity中寫一遍就好了。

下面我就講解一下在產品研發過程中我對基類Activity的設計。

(一)基類Activity是如何使用的?
定義一個BaseActivity,讓App中所有的Activity都繼承於BaseActivity;

(二)基本Activity包含的內容

  • 在BaseActivity的生命週期中複寫友盟資料統計方法。
    用過友盟資料統計的同學應該知道,為了統計每個頁面的點選事件,頁面訪問路徑,異常資訊等我們需要在Activity的生命週期方法中新增友盟的API,這些都是一些相同的邏輯,難道我們需要在每個Activity中都重寫這些友盟API麼?答案當然是否定的,友盟官方也不建議我們這麼做,我們可以在一個基類Activity的生命週期方法中重寫這些友盟API,並讓我們需要統計的頁面繼承於該基類Activity。
@Override
protected void onResume() {
    MobclickAgent.onResume(this);
}

@Override
protected void onPause() {
    MobclickAgent.onPause(this);
}

(其他生命週期方法暫略)
...

由於我們需要統計不同的Activity頁面的資料,所以我們需要在各個Activity的生命週期中都要重寫友盟的API,那麼這裡我們就完全可以將這種重複性的動作下發到BaseActivity中,而讓所有的Activity都繼承於BaseActivity,進而我們的Activity就在生命週期方法中重寫了友盟的API。

  • 在生命週期方法中儲存Context物件,儲存Activity棧
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        Config.setActivityState(this);
        ...
    }

public static void setActivityState(Activity activity) {
        currentContext = activity;
        // 設定App只能豎屏顯示
        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        // 向自身維護的Acitivty棧(資料型別為List)中新增Activity
        UUApp.getInstance().addActivity(activity);
    }

@Override
    protected void onDestroy() {
        super.onDestroy();
        // 在BaseActivity中的Activity棧中移除Activity
        UUApp.getInstance().removeActivity(this);
    }

因為我們在Activity頁面中經常需要使用“this”,但是到處都是用this顯得不太好,這時候我們可以在BaseActivity中定義一個Actiivty型別的mContext成員變數並在BaseActivity中的onCreate方法中賦值為this,這樣我們在子Activity中需要使用this的地方直接使用mContext成員變數就好了。

並且我們在記憶體中儲存了一個Activity的自定義棧,正常的做法是在Activity的onCreate方法中執行入棧操作,在Activity的onDestory方法中執行出棧操作,由於這些都是共有的邏輯因此我們把這兩個操作放到BaseActivity中。

  • 在生命週期方法中對事件匯流排框架EventBus進行註冊和反註冊

使用過EventBus的同學應該知道其能夠實現事件傳遞的核心機制就是將Activity物件“註冊”到EventBus中,但是有註冊也必須要有反註冊的機制,因為Activity不是常駐記憶體的,Activity也有銷燬的時候,這時候就需要從EventBus中“反註冊”,一個比較好的方式就是在Activity

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        EventBus.getDefault().register(this);
        ...
    }

@Override
    protected void onDestroy() {
        super.onDestroy();
        ...
        EventBus.getDefault().unregister(this);
        ...
    }

/**
     * event 更改顯示登陸狀態
     */
    public void onEventMainThread(BaseEvent event) {
        ...doSomething...
    }

這樣我們就不必要單獨在Activity中重寫EventBus的註冊和反註冊邏輯了。

  • 在onResume方法中執行更新登入使用者票據更新的操作

在App端儲存了使用者的token資訊,但是這裡的token資訊不是一直有效的,有效期為30天,所以這裡就需要有一個更新token的操作,App現在的更新操作是判斷token的有效期是否過了一半,即15天,若過了一半了,則在新開啟的Activity時執行更新票據操作,所以這也是共有的邏輯,即在BaseActivity的onResume中執行更新票據的操作。

@Override
    protected void onResume() {
        super.onResume();
        /**
         * 驗證使用者票據是否失效,失效的話則預設執行更換票據操作
         *     startActivity中不需要更新票據,否則起始頁有可能會彈出登陸提示框
         */
        if (UserConfig.isNeedUpdateTicket() && (!(this instanceof StartActivity) || !this.getClass().getName().equals(StartActivity.class.getName()))) {
            if (!UserConfig.isUpdateTicketing) {
                L.d("onResume 中更新使用者票據");
                UserConfig.requestUpdateTicket();
            }
        }
        ...
    }
  • 在setContentView方法中,重寫載入佈局檔案的邏輯,統一App頁面佈局
@Override
    public void setContentView(int layoutResID) {
        View view = getLayoutInflater().inflate(R.layout.activity_base_layout, null);
        super.setContentView(view);

        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
            view.setFitsSystemWindows(true);
            setTranslucentStatus(true);
            SystemBarTintManager tintManager = new SystemBarTintManager(this);
            tintManager.setStatusBarTintEnabled(true);
            tintManager.setStatusBarTintResource(R.color.colorPrimaryDark);

        }

        initDefaultView(layoutResID);
        initDefaultToolBar();

    }

/**
     * 初始化預設的佈局元件
     *
     * @param layoutResID
     */
    private void initDefaultView(int layoutResID) {
        mProgressLayout = (ProgressLayout) findViewById(R.id.progress_layout);
        mProgressLayout.setAttachActivity(this);
        mProgressLayout.setUseSlideBack(false);
        mToolbarContainer = (FrameLayout) findViewById(R.id.toolbar_container);
        mDefaultToolBar = (Toolbar) findViewById(R.id.default_toolbar);
        mToolbarTitle = (TextView) findViewById(R.id.toolbar_title);
        mRvRight = (RippleView) findViewById(R.id.rv_right);
        mRightOptButton = (TextView) findViewById(R.id.right_opt_button);
        mContentContainer = (FrameLayout) findViewById(R.id.fl_content_container);

        View childView = layoutInflater.inflate(layoutResID, null);
        mContentContainer.addView(childView, 0);
    }

/**
     * 初始化預設的ToolBar
     */
    private void initDefaultToolBar() {
        if (mDefaultToolBar != null) {
            String label = getTitle().toString();
            setTitle(label);
            setSupportActionBar(mDefaultToolBar);
            mDefaultToolBar.setNavigationIcon(R.mipmap.toolbar_back_icn_transparent);
        }
    }

在BaseActivity中重寫了setContentView方法,然後統一佈局檔案,即讓我們呼叫setContentView傳遞的layoutId載入到我們自定義的ViewContain中,這樣我們就統一了Activity的佈局檔案,當然了這也是共有的邏輯,我們可以寫在BaseActivity中。

  • 執行共有的UI操作,比如顯示Toast,顯示SnakeBar,顯示Progress,顯示Dialog等
public void showToast(String text) {
        if (text != null && !text.trim().equals("")) {
            Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
        }
    }

public void showProgress(boolean canCancled, final Config.ProgressCancelListener listener) {
        Config.showProgressDialog(mContext, canCancled, listener);
    }

    public void dismissProgress() {
        Config.dismissProgress();
    }

public void showResponseCommonMsg(HeaderCommon.ResponseCommonMsg msg) {
        if (msg.getMsg() != null && msg.getMsg().length() > 0) {
            if (msg.hasShowType()) {
                if (msg.getShowType().equals(HeaderCommon.ResponseCommonMsgShowType.TOAST)) {
                    showSnackBarMsg(msg.getMsg());
                } else if (msg.getShowType().equals(HeaderCommon.ResponseCommonMsgShowType.WINDOW)) {
                    showResponseCommonMsg(msg, null);
                }
            } else {
                showSnackBarMsg(msg.getMsg());
            }
        }
    }

我們可以在BaseActivity中重寫了一些顯示Toast,Dialog,SnakeBar的操作,這樣我們在Activity中顯示這些UI的時候可以統一呼叫方法與UI風格。

從上面我們分析的基類內容可以知道一般在涉及Activity的時候都需要重寫一個基類Activity,用於重寫Activity中的共有邏輯,避免我們在每個Activity中都重寫相關的重複邏輯。

相關推薦

Android產品研發-->Activity

在上一篇文章中我們介紹了在Android產品研發過程中,啟動頁的優化工作,比如啟動頁效能優化,啟動頁漸進動畫效果,啟動頁遮蔽返回按鍵等等,而在本文中我們將要介紹一下在App產品研發中都會複寫的基類Activity,具體可參考:Android產品研發(二)–&

單目跟蹤位姿產品研發----如何在linux下發布免安裝的QT程式

       專案中,雖然是對方公司負責開發介面,但導師讓我也用qt開發一個介面。下圖是我測試時用的簡易介面……的部分截圖(沒辦法,簽了保密協議。。。) 為了將我的測試介面程式放在對方公司上面沒有opencv相關開發環境的硬體上使用,需要釋出免安

Android產品研發-->減小Apk大小

隨著移動技術的深入發展,各種炫酷效果的更新,在我們追求UI與UE的同時一個不如忽視的問題逐漸暴露出來,那就是apk檔案越來越大,可能有的童鞋會說現在都是wifi環境,apk檔案增大幾M不是什麼大不了的問題,這其實也是有一定道理的,但是作為開發人員的我們這絕不

Android產品研發-->App資料統計

上一篇文章中我們介紹了Android社群中比較火的熱修復功能,並介紹了目前的幾個比較流行的熱修復框架,以及各自的優缺點,同時也介紹了一下自身專案中對熱修復功能的實踐。目前主流的熱修復原理上其實分為兩種,一種是通過利用dex的載入順序實現熱修復功能,一種是通過

Android產品研發-->多渠道打包

國內的Android開發者還是很苦逼的,由於眾所周知的原因,google play無法在國內開啟(翻牆的就不在考慮之內了),所以Android系的應用市場,群雄爭霸。後果就是國記憶體在著有眾多的應用市場,產品在不同的渠道可能有這不同的統計需求,為此Andro

Android產品研發-->App網路傳輸協議

上一篇文章中我們講解了如何在App中統計資料,其實現主要分為兩種:使用第三方服務統計和自身實現資料統計。一般而言我們使用第三方統計服務已經可以很好的滿足我們的也無需求了,只有部分資料敏感型的App,由於其資料敏感性在app中實現資料統計服務是一個更好的選擇,

Android產品研發十五-->記憶體物件序列化

上一篇文章中我們講解了Android app中的升級更新操作,app的升級更新操作算是App的標配了,升級操作就是獲取App的升級資訊,更新操作是下載,安裝,更新app,其中我們既可以使用app store獲取應用的升級資訊,也可以在應用內通過請求本地伺服器

Android產品研發十九-->Android studio中的單元測試

上一篇文章中我們講解了webview中問題集錦,講解了webview的效能優化、webview種入Cookie資訊、activity退出的時候清除webview資訊報錯、如何通過java程式碼和js程式碼相互互動、webview如何下載檔案以及騰訊的X5瀏覽

Android產品研發二十四-->記憶體洩露場景與檢測

上一篇文章中本文我們講解了一個Android產品研發中可能會碰到的一個問題:如何在App中儲存靜態祕鑰以及保證其安全性。許多的移動app需要在app端儲存一些靜態字串常量,其可能是靜態祕鑰、第三方appId等。在儲存這些字串常量的時候就涉及到了如何保證祕鑰的

[日更-2019.5.20] Android 系統內的守護程序--core中的服務 : lmkd

宣告 其實很好奇Android系統中的一些關鍵守護程序服務的作用; 暫且大概分析下它們的作用,這樣有助於理解整個系統的工作過程;

淺談Kotlin

ide pos 中一 androi 文件 rri object 淺談 spa 淺談Kotlin(一):簡介及Android Studio中配置 淺談Kotlin(二):基本類型、基本語法、代碼風格 前言:   已經學習了前兩篇文章,對Kotlin有了一個基本的認識,往後

MVC系列博客之排球計分模型的實現

layers 自動生成 ext alt 感覺 名稱 數據 string 後來 最初我使用的是連接數據庫的方法來建立數據連接的,後來聽了同學用EF框架來生成數據庫自動連接,感覺很好用,然後我就重新用EF框架生成數據庫 使用EF框架生成數據庫,要有相應的模型類,模型類如下:

MVC之排球比賽計分程序 ——model的設計與實現

比賽 用戶 count class 包括 result 控制 類的設計 可能 實體類是現實實體在計算機中的表示。它貫穿於整個架構,負擔著在各層次及模塊間傳遞數據的職責。一般來說,實體類可以分為“貧血實體類”和“充血實體類”,前者僅僅保存實體的屬性,而後者還包含一些實體間的關

面向對象 抽象和接口

trac bstr 報錯 clas abstract nbsp 繼承 默認 定義 一、抽象類 抽象類相當於一個提綱,用於表明對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象,然後對繼承抽象類的子類做出限制。 抽象類用關鍵詞 ab

JavaScript的進階之路引用型之Object型和Array

reverse 代碼 -1 替換 fine 設置 sha unshift sum 引用類型 Object類型 function a(num){ if(num>3){ a(--num); } console.log(num);

Android Camera2 拍照——切換攝像頭,延時拍攝和閃光模式

openca any The visible surface else 提示 再次 .cn 原文:Android Camera2 拍照(三)——切換攝像頭,延時拍攝和閃光模式

對象——屬性型,get/set方法

表示 method table enume 函數 tab value num 不能 屬性類型 1. 數據類型 Configurable: true|false,表示能否通過delete將屬性刪除,默認為true。當把屬性的Configurable設置為false後,該屬性

Android Studio 學習 廣播

else set local activity .... order ... void test 動態註冊監聽網絡變化 創建intentFilter 並addAction 代表了監聽哪個廣播 然後使用registerReceiver()方法 將intentFilter 與

Android 開發:安卓常用控制元件以及仿《微門戶》登入介面實現

一、常用控制元件: 1、文字類控制元件 TextView 負責展示文字,非編輯 EditText 可編輯文字控制元件 2、按鈕類控制元件 Button 按鈕 ImageButton 圖片按鈕 RadioButton與RadioGroup 單

[演算法天天見]排序

另類排序 一、概述 一、概述 這裡主要介紹 桶排序,比如有一個實時排名系統,要對一萬個玩家的分數進行排序,分數為 0-9999分,應該怎麼排序呢?我們的方法是 建立 10000個桶 分別對應分數 0-9999的玩家,初始先遍歷一遍玩家分數放到對應桶