Android Application是單例,正確嗎?

Android 中Application是單例,這個問題可能大家會毫不猶豫的回答正確
但是,如果APP中如果有集成一些第三方SDK的
并且在Application中加了打印的可能就會發現,APP啟動的時候
怎么onCreate中的打印走了多次
不是說Application只會實例化一次的嗎?

因為onCreate走了多次,說明創建了多個
那這個問題答案應該明朗了,在某種情況下,Application不唯一了

那這種情況是什么情況呢?
答案是:多進程
一般我們開發可能極少,除非一些特別的APP,可能我們都不會指定多進程
那為啥集成了第三方SDK會出現這種情況呢
是因為有些SDK指定了組件運行在特別的進程

那為啥第三方SDK會使用多進程?多進程帶來的好處是什么?又有什么壞處呢?

進程

Android系統是底層是由Linux改造而來的
進程系統也是一致的,進程,就是程序的具體實現
當程序第一次啟動,Android會啟動一個Linux進程(具體由Zygote fork出來)和一個主線程
默認的情況下,所有組件都將運行在該進程內
同一個應用由系統分配一個獨立的Linux賬戶,應用的產生的所有進程,都會是這同一個Linux賬戶

多進程Application會創建多個

很明顯帶來的問題就是Application的onCreate方法會執行多次
如果在onCreate方法中,做了初始化的操作,將會導致多次初始化操作
如果是啟動的時候就執行的,將會導致啟動時間延長

將組件指定在單獨的進程

指定多進程是在AndroidManifest.xml里面配置
Android四大組件activity,service,provider, receiver
可以通過android:process屬性來指定運行所在的進程
不指定默認就是運行在系統分配的進程
也可以修改默認進程 設置Application的android:process屬性,來設置所有組件的默認進程
進程名分兩種:

  • 如果以冒號開頭,比如":com.gaode.map"
    這種情況下,是該APP私有的,進程名是APP包名+冒號+后面的名字
<activity android:name=".TestActivity"
            android:process=":com.gaode.map"/>
  • 如果小寫字母以:開頭 比如"com.baidu.map"
    該組件將運行在以這個名字命名的進程中
    這種方式就可以讓不同應用中的組件可以共享一個進程
<activity android:name=".TestActivity"
            android:process="com.baidu.map"/>

示例:

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

        <activity android:name=".TestActivity"
            android:process="com.baidu.map"/>

Application 完整代碼

public class BaseApplication extends Application {

    private static final String APP_NAME = "com.qingguoguo.baseapp";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("BaseApplication", "onCreate");
        Log.e("BaseApplication", getProcessNameByPID(getApplicationContext(), android.os.Process.myPid()));
        DBConfig.initGreenDao(this);
    }

    /**
     * 判斷是否是主進程
     * @return
     */
    public boolean isAppMainProcess() {
        try {
            int pid = android.os.Process.myPid();
            String process = getProcessNameByPID(getApplicationContext(), pid);
            return TextUtils.isEmpty(process) || APP_NAME.equalsIgnoreCase(process);
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * 根據 pid 獲取進程名
     * @param context
     * @param pid
     * @return
     */
    public String getProcessNameByPID(Context context, int pid) {
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        if (manager == null) {
            return "";
        }
        for (android.app.ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
            if (processInfo == null) {
                continue;
            }
            if (processInfo.pid == pid) {
                return processInfo.processName;
            }
        }
        return "";
    }
}

在ManinActivity中的點擊 事件跳轉到TestActivity,將會導致Application再次初始化

onCreate執行多次

底層原理參考:http://gityuan.com/2016/03/26/app-process-create/

如何避免Application多次初始化

上面的代碼已經給出了解決方法,就是判斷當前進程是不是主進程
若不是可以跳過主進程的初始化
可以參考文章:https://blog.csdn.net/sz_chrome/article/details/72911392

多進程的好處

常駐后臺任務應用

核心后臺服務模塊和其他UI模塊進行分離,保證應用能更穩定的提供服務
從而提升用戶體驗

解決OOM問題

吃內存的大圖,WebView等另開進程,避免主進程OOM

多模塊開發

諸如下載服務,監控服務等等另開進程

多進程帶來的問題

靜態變量和單例模式完全失效

因為進程之間,內存是相互獨立的,所以VM方法區的靜態變量
也都是獨立的,單例模式基于靜態變量,所以單例也會失效
在兩個不同進程訪問一個相同類的靜態變量,值未必相同

線程同步機制完全失效

Java的同步機制是VM來進行調度的,兩個進程擁有兩個不同的VM
所以,同步也會在多進程環境下失效,Synchronized,volatile關鍵字
等都是基于VM級別的同步,所以不要跨進程去使用線程同步,比如
主進程有個生產者,子進程的消費者是無法正常使用消費功能的,
只能通過跨進程通信,讓主進程的消費者去消費,然后再回調

Application會多次創建

每個新進程在創建的時候,都會新建一個Application,所以多進程還
會導致Application多次創建的問題,onCreate方法會多次調用,一般
我們都會在onCreate里初始化操作,那么會多次初始化,最好也不要在
Application中設置過多的靜態變量,導致內存增加

文件讀寫并發訪問的問題

文件指的泛指所有需要并發訪問的文件,例如:本地文件,數據庫文件,
sharepreference等。由于Java中,文件鎖、隊列機制都是VM級別的,
所以不同進程訪問同一個文件鎖是不管用的。(通過C++可以實現多進程
文件鎖機制,不過不在文本討論范圍內。)所以在實際開發過程中,還是
避免多進程同時訪問統一文件,多利用Android中IPC的C/S思想,提供服務,
接口調用,避免直接去訪問對方進程的文件或者數據庫,提升設計美感,
同時也能提升代碼的穩定性

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,142評論 25 708
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,887評論 2 59
  • 面試必背 會舍棄、總結概括——根據我這些年面試和看面試題搜集過來的知識點匯總而來 建議根據我的寫的面試應對思路中的...
    luoyangzk閱讀 6,805評論 6 173
  • 1 邂逅“貓掌柜” 秋日的午后,陽光暖暖的。 在公司吃了午飯,小小習慣到樓下的“貓掌柜”坐一坐。找一個靠窗的角...
    簡_豆媽閱讀 902評論 4 2
  • 時光靜靜的想念,我在頓河邊等待,也許是真的你不會來,但是我會一直一直一個人默守,許多事情不要說,一個眼神交流就夠了...
    不留心閱讀 526評論 2 6