1. 程式人生 > >記憶體洩漏-非UI執行緒使用View.post()方法

記憶體洩漏-非UI執行緒使用View.post()方法

轉自:


最近開發中,使用 AsyncTask + ProgressDialog 顯示進度資訊,但在AsyncTask停止,Activity finish 後該Activity的例項始終不會被gc,多次執行程式後,會存在多個activity,造成記憶體洩漏。 下面詳細分析一下:

一份顯示進度條的測試程式碼:

  1. publicclass Main extends Activity {  
  2.     @Override
  3.     protectedvoid onCreate(Bundle savedInstanceState) {  
  4.         super
    .onCreate(savedInstanceState);  
  5.         TextView tv = new TextView(this);  
  6.         tv.setText("Init State");  
  7.         setContentView(tv);  
  8.         tv.setOnClickListener(new OnClickListener() {  
  9.             @Override
  10.             publicvoid onClick(View v) {  
  11.                 showProgress(Main.this
    );  
  12.             }  
  13.         });  
  14.     }  
  15.     publicvoid showProgress(final Activity activity) {  
  16.         new AsyncTask<Void, Void, Void>() {  
  17.             ProgressDialog progressDial;  
  18.             protectedvoid onPreExecute() {  
  19.                 progressDial  = new ProgressDialog(activity);  
  20.                 progressDial.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);  
  21.                 progressDial.show();  
  22.             };  
  23.             @Override
  24.             protected Void doInBackground(Void... params) {  
  25.                 doSomeHeavyWork(progressDial);  
  26.                 returnnull;  
  27.             }  
  28.             protectedvoid onPostExecute(Void result) {  
  29.                 progressDial.dismiss();  
  30.             };  
  31.         }.execute();  
  32.     }  
  33.     void doSomeHeavyWork(ProgressDialog progress) {  
  34.         try {  
  35.             for (int i = 1; i <= 10; ++i) {  
  36.                 progress.setProgress(i);  
  37.                 Thread.sleep(1000);  
  38.             }  
  39.         } catch (Exception e) {  
  40.         }  
  41.     }  
  42. }  

上述程式碼發生記憶體洩漏的地方在 doSomeHeavyWork() 的 progress.setProgress(i); 部分;我們看一下setProgress()的實現,最終會呼叫ProgressBar 類的如下方法:

  1. privatesynchronizedvoid refreshProgress(int id, int progress, boolean fromUser) {  
  2.     if (mUiThreadId == Thread.currentThread().getId()) {  
  3.         doRefreshProgress(id, progress, fromUser, true);  
  4.     } else {  
  5.         RefreshProgressRunnable r;  
  6.         if (mRefreshProgressRunnable != null) {  
  7.             // Use cached RefreshProgressRunnable if available
  8.             r = mRefreshProgressRunnable;  
  9.             // Uncache it
  10.             mRefreshProgressRunnable = null;  
  11.             r.setup(id, progress, fromUser);  
  12.         } else {  
  13.             // Make a new one
  14.             r = new RefreshProgressRunnable(id, progress, fromUser);  
  15.         }  
  16.         post(r);  
  17.     }  
  18. }  
  1. privateclass RefreshProgressRunnable implements Runnable {  
  2.         privateint mId;  
  3.         privateint mProgress;  
  4.         privateboolean mFromUser;  
  5.         RefreshProgressRunnable(int id, int progress, boolean fromUser) {  
  6.             mId = id;  
  7.             mProgress = progress;  
  8.             mFromUser = fromUser;  
  9.         }  
  10.         publicvoid run() {  
  11.             doRefreshProgress(mId, mProgress, mFromUser, true);  
  12.             // Put ourselves back in the cache when we are done
  13.             mRefreshProgressRunnable = this;  
  14.         }  
  15.         publicvoid setup(int id, int progress, boolean fromUser) {  
  16.             mId = id;  
  17.             mProgress = progress;  
  18.             mFromUser = fromUser;  
  19.         }  
  20.     }  

if 語句表明當呼叫的該方法的執行緒是UI執行緒時,則直接執行doRefreshProgress() 方法以重新整理介面;否則,建立一個RefreshProgressRunnable,並通過呼叫View.pos()方法將其插入到UI執行緒的訊息佇列中。 View.post()實現如下:

  1. publicboolean post(Runnable action) {  
  2.     Handler handler;  
  3.     AttachInfo attachInfo = mAttachInfo;  
  4.     if (attachInfo != null) {  
  5.         handler = attachInfo.mHandler;  
  6.     } else {  
  7.         // Assume that post will succeed later
  8.         ViewRootImpl.getRunQueue().post(action);  
  9.         returntrue;  
  10.     }  
  11.     return handler.post(action);  
  12. }  

在post() 函式註釋中,明確寫著:This method can be invoked from outside of the UI thread only when this View is attached to a window.

當ProgressDialog還沒有attach到當前window時(ProgressDialog.show() 方法是非同步執行的),mAttachInfo 值為 null,故而執行 else語句,再看一下getRunQueue()和其post() 方法:

  1. staticfinal ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();  
  2. static RunQueue getRunQueue() {  
  3.      RunQueue rq = sRunQueues.get();  
  4.      if (rq != null) {  
  5.          return rq;  
  6.      }  
  7.      rq = new RunQueue();  
  8.      sRunQueues.set(rq);  
  9.      return rq;  
  10.  }  
  11.  ……  
  12.  staticfinalclass RunQueue {  
  13.      private

    相關推薦

    記憶體洩漏-UI執行使用View.post()方法

    轉自: 最近開發中,使用 AsyncTask + ProgressDialog 顯示進度資訊,但在AsyncTask停止,Activity finish 後該Activity的例項始終不會被gc,多次執行程式後,會存在多個activity,造成記

    為什麼我們可以在UI執行中更新UI

                    尊重原創轉載請註明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵權必究!炮兵鎮樓看到這樣的標題……估計N多人會說我是逗比…………因為很多盆友在學習Android(特別是從4.0之後開始入門的)的時

    service怎麼執行UI執行

    我們都知道android中service是執行在UI執行緒中的,怎樣讓service執行到非UI執行緒中?我知道service在註冊的時候可以通過android:process=":remote"指定service到remote的程序中,但是要讓service執行到非UI執

    C#——基於委託與事件的多執行通訊(同樣適用於UI執行間通訊)

    在研究c# 執行緒之間通訊時,發現傳統的方法大概有三種 ①全域性變數,由於同一程序下的多個程序之間共享資料空間,所以使用全域性變數是最簡單的方法,但要記住使用volatile進行限制。 ②執行緒之間傳送訊息(這個隨後文章中會討論到)。 ③CEvent為MFC中的一

    Android UI執行UI執行

    public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork("http://

    關於UI執行UI執行互動,有關Handler機制等(一)

    在Android中,一個activity有一個主執行緒也叫UI執行緒,作用就是用來繪製UI介面,在這個執行緒裡面,你的應用和android的UI元件發生互動。所以當你需要進行某些費時操作的時候,比如訪問網路等,如果放入UI執行緒,就會阻塞介面的繪製,當介面不能繪製的時候,整

    5.UI執行UI執行的互動方式

      一般來說有三種方式:      1.Activity.unOnUiThread(Runnable)      如果當前執行緒是UI Thread,立馬執行action.run方法;否則將Runnable傳送到UI Thread的event 佇列中。    

    執行MainActivity中更新Toast、ImageView等UI控制元件方法

    首先需要明確一點就是UI只能在主執行緒中更新,其他地方想更新UI,我目前學到的有兩種方法: 1.採用handler的方式 public class MainActivity extends Activity{ ...... ImageView image

    使用WinDbg檢視當前執行所在模組的記憶體資料資訊

    在工作中經常需要檢視dump,雖然現在VC2015已經做的非常好了,尤其是對map的解析,非常方便,而且enum可以直接顯示定義字串。但windbg卻有一些vc沒有提供的功能(可能我沒有發現~~),比如檢視非當前執行緒所在模組的記憶體資料資訊。下面對此方法做一下說明,以備遇

    Android 多執行之間的通訊互動(Ui執行與子執行之間的通訊)Handler,Handler.post(Runnable runnable),runUiThread方式

    工作內容: 1.FrameLayout/OnTouchListener(滑動監聽) 2.生命週期 3.UI執行緒 4.Android中的耗時操作/多執行緒 5.多執行緒中的互動:Handler handler.post(Runnable runnable) 6.多執行緒中

    Android使用View.post()方法記憶體洩漏

    最近開發中,使用 AsyncTask + ProgressDialog 顯示進度資訊,但在AsyncTask停止,Activity finish 後該Activity的例項始終不會被gc,多次執行程式後,會存在多個activity,造成記憶體洩漏。 下面詳細分析一下:

    執行、守護執行守護執行

    主執行緒 main,但不是守護執行緒。 守護執行緒 是指在程式執行的時候在後臺提供一種通用服務的執行緒。如gc。 非守護執行緒 也叫使用者執行緒,由使用者建立。 關係: 主執行緒和守護執行緒一起銷燬; 主執行緒和非守護執行緒互不影響。 例如: package

    java獲取JVM的CPU佔用率、記憶體佔用率、執行數及伺服器的網口吞吐率、磁碟讀寫速率

    怎麼說呢,本人菜鳥一枚,費了幾天時間,終於做了一個用java獲取JVM的CPU佔用率、記憶體佔用率、執行緒數及伺服器的網口吞吐率、磁碟讀寫速率的實現。 其中windows環境下獲取jvm 的cpu佔用率這裡是參考網上別人的東西(在此感謝提供參考的網友),其他的都是基於自己的想法做出來的。該工具類

    Android ActivityThread 主執行UI執行 簡介

    分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

    Android 有效地展示圖片(二)Processing Bitmaps Off the UI Thread 在ui執行外處理bitmap

    原文連結http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html 我們在上節課討論了BitmapFactory.decode系列的方法,但是如果原圖的資料需要從硬碟或者網路或者別的途徑而非記憶

    C# Delegate 如何從子執行修改UI執行執行介面

    一、為什麼Control類提供了Invoke和BeginInvoke機制? 關於這個問題的最主要的原因已經是dotnet程式設計師眾所周知的,我在此費點筆墨再次記錄到自己的日誌,以便日後提醒一下自己。 1、windows程式訊息機制 Windows GUI程式是

    Java基礎:由JVM記憶體模型詳解執行安全

    1.前言 最近在研究JVM記憶體模型和Java基礎知識。主要講的是執行緒共享變數與執行緒私有變數以及如何寫出執行緒安全的程式碼。這裡列出一條規則,“類中的成員變數,也叫例項變數,也叫全域性變數,它是非執行緒安全,是所有執行緒共享的變數,定義在方法中的私有變數是執行緒安全的,是每個執行緒私

    C#.網路程式設計 Socket基礎(四) WPF系統Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸,同時解決UI執行與工作執行的卡頓問題

    一、簡介 雖然,本文的前面幾篇文章在WinForm中實現了Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸,詳情見 但是,卻沒有在WPF中實現 Socket TCP協議 伺服器與客戶端 不同型別檔案傳輸。因此,本文將描述如何在WPF中實現該功能。

    併發集合(二)使用阻塞執行安全的列表

    宣告:本文是《 Java 7 Concurrency Cookbook 》的第六章,作者: Javier Fernández González     譯者:許巧輝 使用非阻塞執行緒安全的列表 列表(list)是最基本的集合。一個列表有不確定的元素數量,並且你可以新增、讀取和刪除任意位置上的元

    關於“UI執行

    [msdn] The system maintains a single system message queue and one thread-specific message queue for each GUI thread. To avoid the overhead of creating a me