顯示具有 androidProcess 標籤的文章。 顯示所有文章
顯示具有 androidProcess 標籤的文章。 顯示所有文章

2013年1月19日 星期六

[Android] Process has died

Error Message

12-28 11:25:03.191: I/ActivityManager(1614): Process com.package.name (pid 17766) has died.



Testing

  • Register BroadcastReceiver in ServiceA will not active when process is died but except register in manifest.
  • If create ServiceA in another process(android:process) and BroadcastReceiver will be create in this process, too.
    • So that even though process of activity that creates service is died service will not died immediately.


2012年12月1日 星期六

2012年10月21日 星期日

[Android] Avoid Memory leak

  • 當記憶體不足,system 就必須暫停你的 application,執行 garbage collection,通常暫停的時間很短暫讓 user 感覺不到,但若是在移動 scroll 或是遊戲戰鬥中,可以感覺到效能和回應的下降。
  • "leak" meaning you keep a reference to it thus preventing the GC from collecting it.
  • 在 Android 中,一個 Process 只能使用 16M 記憶體(模擬器為 8M?),若是超過變會引發 Out-of-Memory exception(OOM)。


容易占據大量記憶體的行為:
  • view layout
  • drawing method of a view
  • the logic code of a game


Context Leak
keeping a long-lived reference to a Context.

Context 最常用來載入和存取資源,在 app 中一般會有 Activity and Application 兩種 Context
  • setContentView(new TextView(this));
  • 表示 the entire View hierarchy and all its resources reference 到這個 activity,有可能會使得此 Context leak。

可用以下兩種方式避免 Context leak:
  • 不要將 Context 使用在自己的 scope 之外。
  • 使用 Application context。
    • This context will live as long as your application is alive and does not depend on the activities life cycle. 
    • If you plan on keeping long-lived objects that need a context, remember the application object. You can obtain it easily by calling Context.getApplicationContext() orActivity.getApplication().

In summary, to avoid context-related memory leaks, remember the following:
  • Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
  • Try using the context-application instead of a context-activity
  • Avoid non-static inner classes in an activity if you don't control their life cycle, use a static inner class and make a weak reference to the activity inside. 
    • The solution to this issue is to use a static inner class with a WeakReference to the outer class, as done in ViewRoot and its W inner class for instance
  • A garbage collector is not an insurance against memory leaks


Bitmap Leak
  • 避免 Bitmap Leak 就必須使用 recycle 機制,適時的將不需要顯示的 Bitmap 物件回收。
  • 但還有另一種狀況: 產生 Bitmap 的時候,明明還有許多記憶體,卻發生了 OOM。
    • 假設現在產生了一個 13MB 的 Int array 物件,在使用完之後立即 recycle,照理說會空出 13MB 的空間,這時候繼續產生一個 10MB 的 Int array 物件不會有任何問題,反而生成一個 4MB 的 Bitmap 卻跳出OOM。
  • 在 Android 中,一個進程的記憶體可以由 2 個部門組成:Java 使用記憶體,C使用記憶體
    • 這兩個記憶體的和必需小於 16 MB,不然就會出現 OOM。
    • 而分配給 Java 使用的記憶體,縱使這塊記憶體被釋放了,也還是只能給Java的使用,所以就算釋放 Java 佔用的佔用了一個大塊記憶體,C 能使用的記憶體 = 16M - Java 某一瞬間占用的最大記憶體。 
    • 而 Bitmap 的生成是路程經過過程 malloc 進行記憶體分配的,佔用的是 C 的記憶體,這個也就說明了,上面所說的的 4MB Bitmap無法生成的原因,因為在 13MB 被Java用過後,剩下 C 能用的只有 3M 了。

補救方式
  • 使用 BitmapFactory.decodeStream() 產生Bitmap。
    • 儘量不要使用 setImageBitmap,setImageResource 或 BitmapFactory.decodeResource 來設置一張大圖,因為這些函數在完成 decode 後,最終都是通過 java 層的 createBitmap 來完成的,需要消耗更多記憶體。
    • 因此,改用先通過 BitmapFactory.decodeStream 方法,創建出一個 bitmap,再將其設為 ImageView 的 source,decodeStream 最大的秘密在於其直接調用 JNI >> nativeDecodeAsset() 來完成 decode,
    • 無需再使用 java 層的 createBitmap,從而節省了 java 層的空間。
    • decodeStream 直接拿的圖片來讀取位元組碼了,不會根據機器的各種解析度來自動適應,使用了 decodeStream 之後,需要在 hdpi 和 mdpi,ldpi 中配置相應的圖片資源,否則在不同解析度機器上都是同樣大小(圖元點數量),顯示出來的大小就不對了。
  • 設定圖片的 Config 參數,可以跟有效減少載入的記憶體。
    • BitmapFactory.Options inSampleSize:值越大解析度越小,佔用memory也越小。
  • 在 onPause/onStop/onDestory 時, 將沒用到的 Bitmap release(用recyle())
BitmapFactory.Options opts = new BitmapFactory.Options();
// Options 只保存图片尺寸大小,不保存图片到内存
// 缩放的比例,缩放是很难按准备的比例进行缩放的,其值表明缩放的倍数
// SDK 中建议其值是2的指数值,值越大会导致图片不清晰
opts.inSampleSize = 4;
Bitmap bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts);                              
 ...               
//回收
bmp.recycle();


* Reference
- Tracking Memory Allocations | Android Developers
- Avoiding memory leaks | Android Developers Blog
- (转)内存溢出的解决办法 Android - 攀升·Uranus - C++博客
- Android開發——解決載入大圖片時記憶體溢出的問題 @ 資訊園 :: 痞客邦 PIXNET ::
- GiveMePasS’s Android惡補筆記: 如何改善Bitmap所帶來的Out of Memory(OOM)問題
- Re: [問題] Bitmap OutOfMemory 永遠的痛 - 看板 AndroidDev - 批踢踢實業坊
- Andorid , Object-C and Java Programming Learning: [Android]Android Out Of Memory(OOM) 的詳細研究

2012年6月2日 星期六

[AndroidProcess] Background works

Main thread 負責處理 UI event,所以也稱為 UI thread,Activity、Service、Receiver、Provider,都是由 main thread 負責執行。因此不能在此 thread 中執行耗時的動作,android 會發出 ANR,這時候就得在 background thread 中執行,讓 main thread 同時仍能回應或執行 UI event,以避免 ANR 狀況。

sendBroadcast() 與 startService() 都一樣會被丟到 main message queue 裡,等待 main thread 的執行,只有呼叫 local content provider 不會進到 main message queue 裡,而是由 main thread 直接執行。但如果是 remote content provider 則是由 thread pool 中取得 thread 來執行,外部 client 呼叫 service 也是如此。

每個 Thread 中都有 Looper 和 Message Queue,Message Queue 中儲存著要被處理的 events (UI event and System event),Looper 負責 Thread 和 Message Queue 間的連繫。

另外,因為是 main thread 負責更新 UI,所以若是試圖在 worker thread 中更新 UI,是會得到 exception 的,必須把更新 UI 的動作再丟給 main thread 處理。


可選擇以下方式:

* Simple Worker Thread and runOnUiThread()/View.post()
View.post()
Each View object has a message queue which is processed sequentially on the UI thread. post() allows us to add a new message to the message queue.
new Thread(new Runnable() {
    @Override
    public void run() {
        // TODO works here.
        
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // UI event
            }
        });

        // or
        final TextView textView =
            (TextView) findViewById( R.id.textview );
        textView.post(new Runnable() {
            @Override
            public void run() {
                // UI event
                textView.setText( "Hello World" );
            }
        });
    }
}).start();

* new Thread + Handler
Handler: 負責處理 thread 的訊息(message)。
private Handler handler = new Handler() {
    @Override
    public void handleMessage(android.os.Message msg) {
        // UI event
        progressDialog.dismiss();
    };
}

new Thread() {new Runnable() {
    @Override
    public void run() {
        // TODO works here.

        // 把 message 送給 handler 處理。
        handler.sendEmptyMessage(0);

        // or 將 Runnable post 到 handler。
        handler.post(new Runnable() {
            @Override
            public void run() {
                textView.setText( "Hello World" );
            }
        });
    }
}.start();

* AsyncTask
  • 如果只會 Override doInBackground 則可考慮使用 Thread 即可。
  • AsyncTask 會 hold Activity context 直到工作結束,所以可能會有 context leak 問題。
new AsyncTask() {
    // onPreExecute(), onProgressUpdate()

    @Override
    protected Void doInBackground(Void... params) {
        // TODO works here.
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        // UI event
    };
}.execute();


** AsyncTask and Handler
  • AsyncTask 內部實做機制為較新且較強的 java.util.concurrent,但較佔資源,而 Handler Thread 則為基本的 Java Thread。
  • 由於 Handler Thread 依靠 Message Queue 與 Main Thread 互動,相對於 AsyncTask,Handler Thread 比較可能發生塞車情況。
  • 但 Handler Thread 在即時互動上優於 AsyncTask,因為 Main Thread 可以隨時傳送 Message 給 Handler Thread,而 AsyncTask 不行,只能依照事先定義 Callback 進行。
  • 基於輕量環境資源的有限,當執行單一的工作時建議使用 AsyncTask,如下載一個大檔案,但是當執行大量重複性的工作時,建議使用 Handler Thread,如下載多個小圖。

* Loader
  • Introduced in Android 3.0 and also included in the Support Library.
  • Used to asynchronously load data in an activity or fragment.
  • Quite effectively to perform these tasks:
    • Loading content either from a SQLite database or file storage, or from a network resource as a background task.
  • There are essentially three components that we need:
  • How to use:
    • Obtain LoaderManager instance from Activity/Fragment/FragmentActivity.
    • Implement LoaderManager.LoaderCallbacks.
      • Will create a loader.
      • Get called when the loader either finishes, or is reset.
      • These will all be executed on the UI thread, and we will typically implement them within our Activity / FragmentActivity.
      • 也就是在 Loader 中處理 UI event。(?)

* Service
  • Services is a means of performing some task which is not attached to a specific Activity.
  • Run in the main thread of their hosting process. (並不會在另一個 thread 中執行,所以不適做耗費 CPU 的工作 會有 ANR 的可能,或者是必須 new a thread。)
  • There are two types of Service:
    • A background Service
      • The default type of Service and can be killed by the OS (or Task Killer apps, more of them later) to free up system resources.
    • A foreground service
      • Not be killed by the OS, but requires an ongoing Notification to be displayed in the Notification bar while it is running so that the user is aware that the foreground Service is active and will not be killed automatically by the OS.
      • ex: music player.

* IntentService extends Service
  • Service + Handler + HandlerThread。
  • Will receive a single Intent and then shut down automatically once we have processed it.
  • 和 Service 不同,此 api 會執行在自己的 worker thread,陸續執行交給它的 request,但只會有一個 worker thread 同時也只會執行一個 request,當執行完後會自行停止。
  • 實做其 onHandleIntent(Intent intent),在這裡處理 request。
  • 是設計用來可以在一個 Service 中服務多項工作,因此在 onHandleIntent(),不可以呼叫 stopSelf(),全部工作結束,它會自行停止。
  • start service -> send message to handler that has non-UI thread looper -> handlerMessage() -> onHandleIntent()
    • Looper 就是訊息迴圈 (message loop),這是 Android UI 在處理各式訊息時,最重要的元件之一。
  • One word of warning:
    • Performing long tasks in an IntentService does have the inherent risk that it will stop if the device goes to sleep. You can prevent this from happening by holding a WakeLock while onHandleIntent() is executing. Just make sure you release it before onHandleIntent() returns. Alternatively use Mark Murphy’s WakefulIntentServicepattern.

* Pending
  • StrictMode
    • API level 9。
    • 可用於發現潛在問題,ex: 你該使用 background thread 的動作。
  • Loader
    • API level 11。


* Reference
- Background Tasks – Part 1 (Introduction)
- Background Tasks – Part 2 (Worker thread, Handler)
- Background Tasks – Part 3 (AsyncTask)
- Background Tasks – Part 4 (Loader)
- Background Tasks – Part 5 (Service)
- Background Tasks – Part 6 (IntentService)
- Android之Service与IntentService的比较 - HiPhoneZhu的专栏 - 博客频道 - CSDN.NET **
- 深入研究 IntentService 原始碼 ***
- IntentService的功用
- Android Handler 筆記 **
- Java Artisan: Android AsyncTask 與 Handler Thread 的差異 **
- Java Artisan: 在 Android 裡使用 Local Service