【Android 应用开发】 Application 使用分析
博客地址 :?http://blog.csdn.net/shulianghan/article/details/40737419?
代碼下載 : Android 應(yīng)用 Application 經(jīng)典用法;?
-- Github :?https://github.com/han1202012/ApplicationDemo?
-- CSDN :?http://download.csdn.net/detail/han1202012/8127247
一. Application 分析
1. Application 簡介
(1) Application 概念
Application 概念 : Application 屬于組件范疇;
-- 本質(zhì) : Application 與 四大組件 一樣也屬于 Android 中的組件;?
-- 作用 : 用于存儲系統(tǒng) 和 用戶定義的全局信息;?
-- Application 創(chuàng)建 : 應(yīng)用開始運行時創(chuàng)建 Application 對象, 可以自定義, 也可以讓系統(tǒng)自動創(chuàng)建;?
-- Application 單例性 : 每個應(yīng)用只創(chuàng)建一個 Application 對象, 該類屬于單例模式;?
-- Application 生命周期 : Application 生命周期 從應(yīng)用啟動開始 到 應(yīng)用退出結(jié)束, 與應(yīng)用的生命周期是相同的;
-- Application 作用 : 在任何組件中調(diào)用 getApplication() 或者通過 Context 對象調(diào)用 getApplicationContext() 方法獲取的 Application 對象都是相同的, 因此可以使用 Application 進行數(shù)據(jù)共享, 數(shù)據(jù)緩存操作;?
(2) Application 與 全局變量?
Application 與 全局變量 :?
-- 基本作用 : Application 在 Android 中是為了 保存全局變量 而設(shè)計的類;?
-- Android 全局變量定義 : 在 Android 中可以不使用 public static 定義全局變量, 定義在 Application 中的普通變量 在Android應(yīng)用中可以當(dāng)作全局變量使用;
(3) Application 使用方法
Application 使用方法 :?
-- 自定義 Application : 自定義一個 class 類, 繼承 android.app.Application 類;
-- 配置 Application : 在 AndroidManifest.xml 中配置 Application;
--?獲取 Application : 在組件類(Activity, Service 等)中直接調(diào)用 getApplication() 方法即可, 在普通類中調(diào)用 Context 的 getApplicationContext() 方法;
2. Application 生命周期 及 對應(yīng)方法
(1) onCreate()
onCreate() 方法簡介 : 該方法是 Android 程序的入口;
-- 執(zhí)行時機 : 該方法在應(yīng)用創(chuàng)建時自動回調(diào);
-- 注意 : 在父類 Application 中, onCreate() 方法方法體是空的, 這里可以不用執(zhí)行 super.onCreate()方法;
關(guān)于程序入口 :?
-- Android 程序入口 : Android 程序入口是 Application, 并不是 Activity, 因為有的 應(yīng)用是沒有 Activity 的;
-- Java 和 C 程序入口 : 這兩種語言的程序入口是工程中的 main() 函數(shù);
(2) onLowMemory()?
onLowMemory() 方法簡介 :?
-- 調(diào)用時機 : 在內(nèi)存不足時會回調(diào)該方法;
-- 重寫方法 : 重寫時需要執(zhí)行父類方法 super.onLowMemory(), 同時根據(jù)本應(yīng)用特點, 釋放掉一些不必要的數(shù)據(jù);
(3) onTerminate()?
onTerminate() 方法簡介 :?
-- 調(diào)用時機 : 只有在模擬器中終止程序時才會回調(diào)該方法, 在 Android 真機中是不會回調(diào)該方法的;
-- 注意 : Application 的 onTerminate() 方法體是空的, 這里不許要執(zhí)行父類的方法 super.onTerminate();
(4)?onConfigurationChanged()
onConfigurationChanged() 方法簡介 :?
-- 調(diào)用時機 : 配置改變時回調(diào)這個方法;
(5) Application 代碼分析
Application 相關(guān)代碼 :?
/*** Called when the application is starting, before any other application* objects have been created. Implementations should be as quick as* possible (for example using lazy initialization of state) since the time* spent in this function directly impacts the performance of starting the* first activity, service, or receiver in a process.* If you override this method, be sure to call super.onCreate().*/public void onCreate() {}/*** This method is for use in emulated process environments. It will* never be called on a production Android device, where processes are* removed by simply killing them; no user code (including this callback)* is executed when doing so.*/public void onTerminate() {}public void onConfigurationChanged(Configuration newConfig) {Object[] callbacks = collectComponentCallbacks();if (callbacks != null) {for (int i=0; i<callbacks.length; i++) {((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);}}}public void onLowMemory() {Object[] callbacks = collectComponentCallbacks();if (callbacks != null) {for (int i=0; i<callbacks.length; i++) {((ComponentCallbacks)callbacks[i]).onLowMemory();}}}
3. Application 使用場景 1 --> 組件間的數(shù)據(jù)傳遞
(1) 使用 Application 傳遞數(shù)據(jù)
Application 媒介傳遞數(shù)據(jù)方式 :?
-- Appliction 集合 : 在 Application 中維護一個集合, 創(chuàng)建一個 HashMap 成員變量, 鍵是字符串, 值是 Object 對象, 這樣 這個 HashMap 可以存儲任何類型的對象;
-- 共享過程 : Activity A 將數(shù)據(jù)存儲到 HashMap 中, 將 鍵 通過 Intent 的 Bundle 傳遞給 Activity B, 之后在 Activity B 中取出對象, 并將 HashMap 中的對象刪除;
-- 適用范圍 : 如果跳轉(zhuǎn)的兩個 Activity 在同一個 應(yīng)用 中, 可以使用這種方法;
(2) 傳統(tǒng)傳遞數(shù)據(jù)方式
傳統(tǒng)數(shù)據(jù)傳遞 :?Activity A 跳轉(zhuǎn)到 Activity B;
-- 實體類 Bean 處理 : bean 實體類必須實現(xiàn)?Serializable或者Parcellable接口, 才可以將實體類 bean 對象放入 Intent 的 Bundle 中;
-- 數(shù)據(jù)傳遞過程 : 在 Activity A 中將 實現(xiàn)了 Serializable 或者 Parcellable 接口的實體類對象放入 Intent 的 Bundle 中, 跳轉(zhuǎn)到 Activity B;
4. Application 使用場景 2 --> 應(yīng)用中的數(shù)據(jù)緩存
Application 緩存數(shù)據(jù) :?
-- 緩存少量數(shù)據(jù) : 從互聯(lián)網(wǎng)獲取的少量數(shù)據(jù)可以直接存放在 Application 中用于數(shù)據(jù)緩存的 HashMap 中;
-- 緩存大量數(shù)據(jù) : 如果緩存 數(shù)據(jù) 或者 文件, 可以將文件緩存到本地, 然后在 Application 中緩存一個 文件路徑字符串即可;
-- 釋放緩存 : 在 onLowMemory() 方法中可以釋放這些緩存, 因為這些緩存可有可無, 這里為了性能犧牲訪問速度;
數(shù)據(jù)傳遞, 緩存 Application 示例 :?
package cn.org.octopus.application;import java.util.HashMap; import java.util.Map;import android.app.Application;public class MyApplication extends Application {/** 用于數(shù)據(jù)傳遞的 Map 集合 */private Map<String, Object> transferMap;/** 用于緩存數(shù)據(jù)的 Map 集合 */private Map<String, Object> cacheMap; @Overridepublic void onCreate() {super.onCreate();//初始化用于數(shù)據(jù)傳遞的 Map 集合transferMap = new HashMap<String, Object>();//初始化用于數(shù)據(jù)緩存的 Map 集合cacheMap = new HashMap<String, Object>();}/*** 獲取數(shù)據(jù)傳遞 Map 集合* @return* 數(shù)據(jù)傳遞 Map 集合*/public Map<String, Object> getTransferMap() {return transferMap;}/*** 獲取數(shù)據(jù)緩存 Map 集合* @return* 數(shù)據(jù)緩存 Map 集合*/public Map<String, Object> getCacheMap() {return cacheMap;}}
5. Application 與 內(nèi)存泄漏
(1) Application 內(nèi)存泄漏
Application 內(nèi)存分析 :?
-- 注意存放對象 : Application 中如果保存了一些大的對象, 例如 Activity 等組件, 如果沒有釋放, 將會引起很多內(nèi)存泄漏;
-- 內(nèi)存釋放 : 在 Application 中要經(jīng)常注意釋放不許要的對象, 使用完畢后能釋放掉的就釋放, 在 onLowMemory() 方法中將所有的緩存數(shù)據(jù)都清空;
(2) Application 盡量不要持有 組件引用
組件持有 Context 對象 :?
-- 創(chuàng)建組件 : TextView tv = new TextView(Activity activity), 這樣一來 組件持有了 Activity 或者 Context 對象;
-- 組件持久化 : 當(dāng)將持有 Context的 tv 組件設(shè)置為靜態(tài) 或者 將 tv 組件設(shè)置到 Application 中時, tv 的聲明周期就變成了整個應(yīng)用的聲明周期了;
-- Context 無法釋放 : 此時 當(dāng) Activity 退出后, 組件仍然存在, Conetxt 無法釋放, 一旦多次訪問這個 Activity, 每次都會泄漏 Context 大小的內(nèi)存;
防止內(nèi)存泄漏方法 :?
-- 組件 : Activity 中的組件的聲明周期不要超出 Activity 生命周期;
-- 圖片 : 組件使用的 Drawable 對象不要超出 Actiity 聲明周期;
-- 線程持有對象 : 不要在線程中持有 Context, 否則在線程執(zhí)行完畢之前都處于內(nèi)存泄漏狀態(tài);
-- 內(nèi)部類作用域不要超出 Activity : 如果在 Activity A 中定義了內(nèi)部類, 不要將這個內(nèi)部類傳遞給其它 Activity 等組件, 否則該 Activity A 不能釋放, 建議將內(nèi)部類設(shè)置成 static 或者 單獨寫成一個類;
二. Application 應(yīng)用層源碼分析
1. Application 類結(jié)構(gòu)分析
(1) ?Application 繼承關(guān)系
Application 類繼承結(jié)構(gòu)?:?
-- Application 類 :?public class Application extends ContextWrapper implements ComponentCallbacks2 ;
-- ContextWrapper 類 :?public class ContextWrapper extends Context ;
-- Context 類 :?public abstract class Context;
-- ComponentCallbacks2 接口 :?public interface ComponentCallbacks2 extends ComponentCallbacks ;
-- ComponentCallbacks 接口 :?public interface ComponentCallbacks ;
-- UML 圖 :?
(2) 相關(guān)類介紹
Application 相關(guān)類介紹 :?
-- Application 類 : 用于存儲應(yīng)用的全局變量;
-- ContextWrapper 類 : 該類是 Context 簡單的代理實現(xiàn), 代表了對另一個 Context 的調(diào)用, 在該類的子類中可以重寫對應(yīng)方法改變指定的操作行為;
-- Context 類 : 該 抽象類 是 應(yīng)用環(huán)境的全局信息接口, Android 提供了該抽象類的實現(xiàn)類, 該類用于訪問 應(yīng)用的 資源 和 類 (作用一), 返回 應(yīng)用的 Actiity, 廣播, Intent 等操作的執(zhí)行結(jié)果(作用二);
-- ComponentCallbacks2 接口 : 該接口繼承了 ComponentCallbacks, 用于?更細粒度的內(nèi)存管理;?
-- ComponentCallbacks 接口 :?應(yīng)用組件的回調(diào)接口, 所有的組件都要實現(xiàn)這個接口;?
2. CompnentCallbacks 接口?
部分源碼 : 省略了注釋部分, 代碼完整;
package android.content;import android.content.res.Configuration;public interface ComponentCallbacks {void onConfigurationChanged(Configuration newConfig);void onLowMemory(); }(1)?onConfigurationChanged() 方法介紹
方法介紹 : 該方法回調(diào)后需要重新加載新配置對應(yīng)的資源, 如果 Activity 對應(yīng)配置改變需要 重啟組件, 其它組件不用重啟;
-- 方法全稱 :?void onConfigurationChanged(Configuration newConfig);
-- 回調(diào)時機?: 在組件運行時, 如果發(fā)生了設(shè)備的配置改變, 就會回調(diào)該接口的方法;
-- 重新加載資源 : 當(dāng)配置改變, 該方法回調(diào)后, 需要更新資源, 以找到與新配置匹配的資源, 例如屏幕方向改變了, 需要找 drawable-land (橫屏) 或者 drawable-port (豎屏資源);
-- Activity 組件配置改變 : 當(dāng) Activity 運行的時候, 如果配置發(fā)生改變, 需要進行重新啟動, 例如 橫屏 切換 豎屏;
-- 其它組件配置改變 : 在 Service 等組件運行時, 配置發(fā)生改變, 不需要重新啟動;
(2)?onLowMemory() 方法介紹
方法介紹 :?
-- 方法全稱 :?void onLowMemory();
-- 回調(diào)時機 : 當(dāng)系統(tǒng)剩余內(nèi)存比較低的時候, 并且系統(tǒng)想要 清理內(nèi)存以獲取更多內(nèi)存時 回調(diào)該方法;
-- 時間點不確定 : 不能確定方法回調(diào)準(zhǔn)確的時間點, 大概在所有的后臺進行被殺死的時間點 左右 回調(diào)該方法, 這個時間點在 服務(wù)進程被殺死之前;
-- 避免殺死前臺進程 : UI 進程在清理內(nèi)存時, 是應(yīng)該避免被殺死的, 這類進程盡量保存;
-- 方法中的建議操作 : 組件實現(xiàn)該方法, 在該方法中建議進行 釋放緩存 或者 釋放不需要持有的資源, 執(zhí)行該方法后, 系統(tǒng)會執(zhí)行 GC 垃圾回收;
3. ComponentCallbacks2 接口?
源碼示例 : 一部份源碼, 省略了注釋 和 一部份的 常量;
package android.content;public interface ComponentCallbacks2 extends ComponentCallbacks {static final int TRIM_MEMORY_COMPLETE = 80;static final int TRIM_MEMORY_MODERATE = 60;... ...void onTrimMemory(int level); }
(1) onTrimMemory() 方法介紹
方法介紹 :?
-- 方法全稱 :?void onTrimMemory(int level) ;
-- 回調(diào)時機 : 當(dāng) 系統(tǒng)決定要清理一個進程不必要的內(nèi)存時 回調(diào)該方法;
-- 清理內(nèi)存時機 : 后臺進程運行時, 當(dāng)沒有足夠的內(nèi)存去保持這些后臺進程運行時, 就會進行內(nèi)存清理;
-- 內(nèi)存等級 : 每個等級都有一個對應(yīng)的內(nèi)存值, 但是這個內(nèi)存等級的精確值是無法獲取的, 因為隨時都有新的中間值會累加上去;
(2) 內(nèi)存等級常量介紹
LRU list 概念 : 全稱 Least Recently Used, 即最近最少使用算法, 用于內(nèi)存管理;
常量?TRIM_MEMORY_COMPLETE :?
-- 全稱 :?static final int TRIM_MEMORY_COMPLETE = 80;
-- 作用 : 表示 后臺進程中的 LRU (最近最少使用) 隊列的尾部, 如果需要更多內(nèi)存, 這些進程將被殺死;
常量?TRIM_MEMORY_MODERATE :?
-- 全稱 :?static final int TRIM_MEMORY_MODERATE = 60 ;
-- 作用 : 表示 LRU 進程隊列的 中間部分, 釋放隊列中間及后面進程的內(nèi)存, 會提高手機性能;
常量用法 : 其中定義了很多類似的常量, 代表一部份進程, 將該常量傳入?onTrimMemory(int level) 可以殺死指定集合的進程;
4. Application 類分析
(1)?ComponentCallbacks 集合列表
列表定義 :?
-- 定義方式 :?private ArrayList<ComponentCallbacks> mComponentCallbacks =?new ArrayList<ComponentCallbacks>();
-- 使用位置 : 在?onConfigurationChanged(),?onLowMemory(),?onTrimMemory() 方法中使用了 該列表;
-- 執(zhí)行內(nèi)容 : ComponentCallbacks 子類 即組件, 都實現(xiàn)了上面的三種方法, 在 Application 中的對應(yīng)方法中分別遍歷組件調(diào)用組件本身的對應(yīng)方法;
注冊 和 刪除組件 : 每創(chuàng)建一個組件都將這個組件注冊, 組件銷毀時 從列表中刪除組件;
public void registerComponentCallbacks(ComponentCallbacks callback) {synchronized (mComponentCallbacks) {mComponentCallbacks.add(callback);}}public void unregisterComponentCallbacks(ComponentCallbacks callback) {synchronized (mComponentCallbacks) {mComponentCallbacks.remove(callback);}}
(2)?ActivityLifecycleCallbacks 接口介紹
ActivityLifecycleCallbacks 接口介紹 :?
-- 接口作用 : 該接口提供了一套監(jiān)測 Activity 聲明周期的回調(diào)方法;
-- 注冊 Activity 聲明周期監(jiān)聽方法 :?
public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {synchronized (mActivityLifecycleCallbacks) {mActivityLifecycleCallbacks.add(callback);}}-- 取消監(jiān)聽方法 :?
public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {synchronized (mActivityLifecycleCallbacks) {mActivityLifecycleCallbacks.remove(callback);}}-- 接口代碼 :?
public interface ActivityLifecycleCallbacks {void onActivityCreated(Activity activity, Bundle savedInstanceState);void onActivityStarted(Activity activity);void onActivityResumed(Activity activity);void onActivityPaused(Activity activity);void onActivityStopped(Activity activity);void onActivitySaveInstanceState(Activity activity, Bundle outState);void onActivityDestroyed(Activity activity);}
三. Application 相關(guān)示例
1. 自定義 Application 基本使用
(1) 創(chuàng)建 自定義 Application
創(chuàng)建 Application : 創(chuàng)建一個類, 繼承?android.app.Application 類, 實現(xiàn)最基本的 onCreate() 方法即可;
-- 示例 :?
package cn.org.octopus.application;import android.app.Application;public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();}}
(2) 注冊 Application?
在 Manifest.xml 中注冊 Application : 在 <application> 標(biāo)簽中添加 android:name 屬性, 屬性值就是 自定義 MyApplication 路徑;
-- 示例 :?
<application android:name="cn.org.octopus.application.MyApplication" >
2. 保存崩潰日志到文件
(1)?UncaughtExceptionHandler 簡介
UncaughtExceptionHandler 未捕獲異常處理類簡介 :?
-- 線程相關(guān) : 每個線程都有一個未捕獲異常處理類;?
使用自定義?UncaughtExceptionHandler 類代替 線程默認的?UncaughtExceptionHandler 類 :?
/** Android 中每個線程都有其指定的 未捕獲異常處理類 UncaughtExceptionHandler* 這里我們將該線程的異常處理類獲取, 將其賦予本類中的成員變量, 將本類設(shè)置為線程默認的 未捕獲異常處理類* 這樣就相當(dāng)與在 UncaughtExceptionHandler 的外層包裝了一層, 我們可以對未捕獲的異常信息進行任何操作*///獲取系統(tǒng)默認的UncaughtException處理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();//設(shè)置該CrashHandler為程序的默認處理器Thread.setDefaultUncaughtExceptionHandler(this);函數(shù)驅(qū)動動力 :?
-- 回調(diào)方法 : 當(dāng)出現(xiàn)了未捕獲異常時, 在崩潰前會回調(diào)?uncaughtException() 方法, 該方法驅(qū)動其它方法運行;
-- 詳細方法 :?public void uncaughtException(Thread thread, Throwable ex);
-- 重寫方法 : 在方法中使用 用戶自行處理 Throwable ex 拋出的異常, 如果用戶沒有處理, 使用默認的異常處理器;
if (!handleException(ex) && mDefaultHandler != null) {//如果用戶沒有處理則讓系統(tǒng)默認的異常處理器來處理mDefaultHandler.uncaughtException(thread, ex);}
(2) 收集相關(guān)參數(shù)信息
獲取設(shè)備信息, 異常信息 :?Field[] fields = Build.class.getDeclaredFields();
-- 將獲取的信息轉(zhuǎn)為字符串 :?
/** 該字段封裝了很多信息* 包括 : 設(shè)備信息 異常信息等*/Field[] fields = Build.class.getDeclaredFields();for (Field field : fields) {try {field.setAccessible(true);infos.put(field.getName(), field.get(null).toString());Log.d(TAG, field.getName() + " : " + field.get(null));} catch (Exception e) {Log.e(TAG, "an error occured when collect crash info", e);}}
(3) 在 Application 中注冊該類
Application 中注冊 : 具體內(nèi)容請詳看代碼;
//注冊異常日志處理類CrashHandler crashHandler = CrashHandler.getInstance();//初始化異常日志處理類crashHandler.init(getApplicationContext());
3. 監(jiān)聽 Activity 生命周期
(1) 自定義?ActivityLifecycleCallbacks 接口實現(xiàn)類
自定義?ActivityLifecycleCallbacks?類 :?
/*** Activity 生命周期監(jiān)聽* @author octopus**/class MyActivityLifecycleCallbacks implements ActivityLifecycleCallbacks{@Overridepublic void onActivityCreated(Activity activity,Bundle savedInstanceState) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivityCreated");}@Overridepublic void onActivityStarted(Activity activity) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivityStarted");}@Overridepublic void onActivityResumed(Activity activity) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivityResumed");}@Overridepublic void onActivityPaused(Activity activity) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivityPaused");}@Overridepublic void onActivityStopped(Activity activity) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivityStopped");}@Overridepublic void onActivitySaveInstanceState(Activity activity,Bundle outState) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivitySaveInstanceState");}@Overridepublic void onActivityDestroyed(Activity activity) {Log.i(TAG_ACTIVITY_LIFE, activity.getClass().getName() + " : onActivityDestroyed");}}
在 onCreate() 方法中注冊該類 :?
//注冊 Activity 聲明周期監(jiān)聽器registerActivityLifecycleCallbacks(new MyActivityLifecycleCallbacks());(2) 執(zhí)行效果
執(zhí)行效果 :?
octopus@octopus:~$ adb logcat | grep cn.org.octopus.application.activity.life I/cn.org.octopus.application.activity.life(12217): cn.org.octopus.application.MainActivity : onActivityCreated I/cn.org.octopus.application.activity.life(12217): cn.org.octopus.application.MainActivity : onActivityStarted I/cn.org.octopus.application.activity.life(12217): cn.org.octopus.application.MainActivity : onActivityResumed I/cn.org.octopus.application.activity.life(12217): cn.org.octopus.application.MainActivity : onActivityPaused I/cn.org.octopus.application.activity.life(12217): cn.org.octopus.application.MainActivity : onActivityStopped I/cn.org.octopus.application.activity.life(12217): cn.org.octopus.application.MainActivity : onActivityDestroyed
博客地址?:?http://blog.csdn.net/shulianghan/article/details/40737419?
代碼下載?:?Android 應(yīng)用 Application 經(jīng)典用法;?
--?Github?:?https://github.com/han1202012/ApplicationDemo?
--?CSDN?:?http://download.csdn.net/detail/han1202012/8127247
總結(jié)
以上是生活随笔為你收集整理的【Android 应用开发】 Application 使用分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 应用开发】 自定义 圆
- 下一篇: 【Android 应用开发】 FastJ