1. 程式人生 > >Application具體解釋(一)

Application具體解釋(一)

conf ica his 本地 數據類型 通過 eat pri abstract



1:Application是什麽?

Application和Activity,Service一樣,是android框架的一個系統組件。當android程序啟動時系統會創建一個 application對象。用來存儲系統的一些信息。

通常我們是不須要指定一個Application的,這時系統會自己主動幫我們創建,假設須要創建自己 的Application,也非常easy創建一個類繼承 Application並在manifest的application標簽中進行註冊(僅僅須要給Application標簽添加個name屬性把自己的 Application的名字定入就可以)。


android系統會為每一個程序執行時創建一個Application類的對象且僅創建一個,所以Application能夠說是單例 (singleton)模式的一個類.且application對象的 生命周期是整個程序中最長的,它的生命周期就等於這個程序的生命周期。

由於它是全局 的單例的,所以在不同的Activity,Service中獲得的對象都是同一個對象。所以通過Application來進行一些,數據傳遞,數據共享 等,數據緩存等操作。


2:通過Application傳遞數據

假如有一個Activity A, 跳轉到 Activity B ,並須要推薦一些數據,通常的作法是Intent.putExtra() 讓Intent攜帶。或者有一個Bundle把信息增加Bundle讓Intent推薦Bundle對象,實現傳遞。但這樣作有一個問題在 於。Intent和Bundle所能攜帶的數據類型都是一些主要的數據類型,假設想實現復雜的數據傳遞就比較麻煩了,通常須要實現 Serializable或者Parcellable接口。

這事實上是Android的一種IPC數據傳遞的方法。假設我們的兩個Activity在同一個 進程其中為什麽還要這麽麻煩呢,僅僅要把須要傳遞的對象的引用傳遞過去就能夠了。

基本思路是這種。在Application中創建一個HashMap ,以字符串為索引,Object為value這樣我們的HashMap就能夠存儲不論什麽類型的對象了。在Activity A中把須要傳遞的對象放入這個HashMap,然後通過Intent或者其他途經再把這索引的字符串傳遞給Activity B ,Activity B 就能夠依據這個字符串在HashMap中取出這個對象了。

僅僅要再向下轉個型 。就實現了對象的傳遞。


3:Application數據緩存

我通常會習慣在application中建立兩個HashMap一個用於數據的傳遞,一個用於緩 存一些數據。比方有一個Activity須要從站點獲取一些數據,獲取完之後我們就能夠把這個數據cache到Application 其中。當頁面設置到其他Activity再回來的時候,就能夠直接使用緩存好的數據了。但假設須要cache一些大量的數據。最好是cache一些 (軟引用)SoftReference ,並把這些數據cache到本地rom上或者sd卡上。假設在application中的緩存不存在。從本地緩存查找,假設本地緩存的數據也不存在再從網 絡上獲取。


4:PitFalls(漢語:易犯的錯誤)

使用Application假設保存了一些不該保存的對象非常easy導致內存泄漏。假設在Application的oncreate中執行比較 耗時的操作,將直接影響的程序的啟動時間。

不些清理工作不能依靠onTerminate完畢。由於android會盡量讓你的程序一直執行,所以非常有可能 onTerminate不會被調用。


5:MemoryLeak

在Java中內存泄漏是僅僅,某個(某些)對象已經不在被使用應該被gc所回收。但有一個對象持有這個對象的引用而阻止這個對象被回收。比方我 們一般會這樣創建一個View TextView tv = new TextView(this);這裏的this通常都是Activity。所以這個TextView就持有著這個Activity的引用。以下看張圖 (Google IO 2011 ppt中抄得)
通常情況下,當用戶轉動手機的時候,android會又一次調用OnCreate()方法生成一個新的Activity,原來的 Activity應該被GC所回收。

但假設有個對象比方一個View的作用域超過了這個Activity(比方有一個static對象或者我們把這個 View的引用放到了Application其中)。這時候原來的Activity將不能被GC所回收,Activity本身又持有非常多對象的引用。所以 整個Activity的內存被泄漏了。
備註:常常導致內存泄漏核心原因: keeping a long-lived reference to a Context.持有一個context的對象。從而gc不能回收。 情況例如以下:


1.一個View的作用域超出了所在的Activity的作用域,比方一個static的View或者把一個View cache到了application其中 etc
理解:內存:註意靜態的數據和緩存中的數據;註意釋放;


2.某些與View關聯的Drawable的作用域超出了Activity的作用域。


3.Runnable對象:比方在一個Activity中啟用了一個新線程去運行一個任務,在這期間這個Activity被系統回收了。 但Runnalbe的 任務還沒有運行完成並持有Activity的引用而泄漏,但這樣的泄漏一般來泄漏一段時間,僅僅有Runnalbe的線程運行完閉,這個 Activity又能夠被正常回收了。


4.內存類的對象作用域超出Activity的範圍:比方定義了一個內存類來存儲數據,又把這個內存類的對象傳給了其他Activity 或者Service等。

由於內部類的對象會持有當前類的引用。所以也就持有了Context的引用。解決方法是假設不須要當前的引用把內部類寫成static或者,把內部類抽取出來變成一個單獨的類。或者把避免內部對象作用域超出Activity的作用域。out Of Memery Error 在android中每個程序所分到的內存大小是有限的,假設超過了這個數就會報Out Of Memory Error。 android給程序分配的內存大小與手機硬件有關,下面是一些手機的數據:


G1:16M Droid:24 Nexus One:32M Xoom:48Ms
所以盡量把程序中的一些大的數據cache到本地文件。

以免內存使用量超標。


記得數據傳遞完畢之後。把存放在application的HashMap中的數據remove掉,以免發生內存的泄漏


6:生命周期:

onCreate 在創建應用程序時創建


onTerminate 當終止應用程序對象時調用,不保證一定被調用,當程序是被內核終止以便為其它應用程序釋放資源,那
麽將不會提醒,而且不調用應用程序的對象的onTerminate方法而直接終止進 程


onLowMemory 當後臺程序已經終止資源還匱乏時會調用這種方法。好的應用程序通常會在這種方法裏面釋放一些不必
要的資源來應付當後臺程序已經終止。前臺應用程序內存還不夠時的情況。


onConfigurationChanged 配置改變時觸發這種方法
備註:application 被殺死的情況分析:
為了決定在內存較低的時候殺掉哪個進程, Android會依據執行在這些進程內的組件及他們的狀態把進程劃分成一個”重要程度層次”. 其重要的程度按下面規則排序:


1:前端進程能夠是一個持有執行在屏幕最前端並與用戶交互的Activity的進程(onResume方法被調用時),也能夠是持有一個正在執行的IntentReceiver(也就是說他正在執行自己的onReceiveIntent方法)的進程. 在系統中, 僅僅會有少數這種進程, 而且除非內存已經低到不夠這些進程執行, 否則系統不會主動殺掉這些進程. 這時, 設備通常已經達到了須要內存整理的狀態, 所以殺掉這些進程是為了不讓用戶界面停止響應.


2:可視進程是持有一個被用戶可見, 但沒有顯示在最前端 (onPause方法被調用時) 的Activity的進程. 舉例來說, 這樣的進程通常出如今一個前端Activity以一個對話框出現並保持前一個Activity可見時. 這樣的進程被系統覺得是極其重要的, 而且通常不會被殺掉, 除非為了保持全部前端進程正常執行不得不殺掉這些可見進程.
3:服務進程是持有一個Service的進程, 該Service是由startService()方法啟動的, 雖然這些進程用戶不能直接看到, 可是通常他們做的工作用戶是十分關註的(比如, 在後臺播放mp3或是在後臺下載 上傳文件), 所以, 除非為了保持全部的前端進程和可視進程正常執行外, 系統是不會殺掉服務進程的.


4:後臺進程是持有一個不再被用戶可見的Activity(onStop()方法被調用時)的進程. 這些進程不會直接影響用戶體驗. 增加這些進程已經完整的,正確的完畢了自己的生命周期(訪問Activity查看很多其它細節), 系統會在為前三種進程釋放內存時隨時殺掉這些後臺進程. 一般會有非常多的後臺進程在執行, 所以這些進程被存放在一個LRU列表中, 以保證在低內存的時候, 近期一個被用戶看到的進程會被最後殺掉.


5:空進程是沒有持有不論什麽活動應用組件的進程. 保留這樣的進程的唯一理由是為了提供一種緩存機制, 縮短他的應用下次執行時的啟動時間. 就其本身而言, 系統殺掉這些進程的目的是為了在這些空進程和底層的核心緩存之間平衡整個系統的資源.


當須要給一個進程分類的時候, 系統會在該進程中處於活動狀態的全部組件裏掉選一個重要等級最高作為分類根據. 查看Activity, Service,和IntentReceiver的文檔, 了解每個組件在進程整個生命周期中的貢獻. 每個classes的文檔具體描寫敘述他們在各自應用的生命周期中所起得作用.


7:application 的context

1、它描寫敘述的是一個應用程序環境的信息,即上下文。
2、該類是一個抽象(abstract class)類。Android提供了該抽象類的詳細實現類(後面我們會講到是ContextIml類)。
3、通過它我們能夠獲取應用程序的資源和類,也包含一些應用級別操作,比如:啟動一個Activity,發送廣播,接受Intent
信息 等。

使用方法具體解釋:

MyApp.java

  1. package com.android.test;
  2. import android.app.Application;

  3. public class MyApp extends Application{

  4. private String mylabel ;
  5. public String getLabel(){
  6. return mylabel;
  7. }
  8. public void setLabel(String s){
  9. this.mylabel = s;
  10. }

  11. @Override
  12. public void onCreate() {
  13. // TODO Auto-generated method stub
  14. super.onCreate();
  15. setLabel("Welcome!"); //初始化全局變量
  16. }
  17. }
復制代碼

MainActivity.java

  1. import android.app.Activity;
  2. import android.content.Intent;
  3. import android.os.Bundle;
  4. import android.util.Log;

  5. public class MainActivity extends Activity {

  6. private MyApp myApp;

  7. @Override
  8. public void onCreate(Bundle savedInstanceState) {
  9. super.onCreate(savedInstanceState);
  10. setContentView(R.layout.main);
  11. myApp = (MyApp) getApplication(); //獲得自己定義的應用程序MyApp
  12. Log.i("guoll", "InitLabel:"+myApp.getLabel()); //將我們放到進程中的全局變量拿出來,看是不是我們以前設置的值

  13. myApp.setLabel("Changing!"); //改動一下
  14. Log.i("guoll", "ChangeLabel:"+myApp.getLabel()); //看下,這個值改變了沒有

  15. Intent intent = new Intent(); //再看一下在還有一個Activity中是取到初始化的值,還是取到改動後的值
  16. intent.setClass(this, otherActivity.class);
  17. startActivity(intent);
  18. }
  19. }
復制代碼

OtherActivity.java:

  1. import android.app.Activity;
  2. import android.os.Bundle;
  3. import android.util.Log;

  4. public class OtherActivity extends Activity{

  5. private MyApp myApp;

  6. @Override
  7. protected void onCreate(Bundle savedInstanceState) {

  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.main);

  10. myApp = (MyApp) getApplication(); //獲得自己定義的應用程序MyApp
  11. Log.i("guoll", "OhterActivity receive the Label:"+myApp.getLabel()); //查看變量值是否改動了

  12. }
  13. }
復制代碼

改動配置文件ApplicationManifest.xml。將要執行的應用程序MyApp加進去:

  1. 2<?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.android.test"
  4. android:versionCode="1"
  5. android:versionName="1.0">
  6. <!-- 在這裏,將默認的Application設置成自己做的MyApp-->
  7. <application android:name="MyApp"
  8. android:icon="@drawable/icon"
  9. android:label="@string/app_name"
  10. >
  11. <activity android:name=".mainActivity"
  12. android:label="@string/app_name">
  13. <intent-filter>
  14. <action android:name="android.intent.action.MAIN" />
  15. <category android:name="android.intent.category.LAUNCHER" />
  16. </intent-filter>
  17. </activity>
  18. <activity android:name=".otherActivity">
  19. </activity>
  20. </application>

  21. </manifest>
復制代碼

Application具體解釋(一)