基礎篇-在非UI線程中更新UI元素,基礎篇ui

來源:互聯網
上載者:User

基礎篇-在非UI線程中更新UI元素,基礎篇ui

個人原創,轉載請註明出處: http://blog.csdn.net/supluo/article/details/


先瞭解兩個概念

1、UI:User Interface的縮寫,使用者介面的意思。你可以不恰當的理解為我們能夠看到的,操作的東西;在Android中什麼才稱為UI呢,可以簡單的理解為View及其子類等元素。這是一個不夠正確的概念,只是對新手做一個簡單的拋磚引玉。

2、ANR:Application Not Responding,意思是程式沒有響應。

在如下情況下,Android會報出ANR錯誤:

– 主線程 (“事件處理線程” / “UI線程”) 在5秒內沒有響應輸入事件

– BroadcastReceiver 沒有在10秒內完成返回

因此耗時的操作通常會放在其他線程中去執行,以防導致程式卡頓甚至出現ANR錯誤,線程執行完成之後再操作UI元素。

下面舉例導致卡頓的例子,在一個按鈕中執行以下代碼:

            proDialog.Show();//顯示進度對話方塊            System.Threading.Thread.Sleep(10 * 1000);//線程休眠10秒,類比耗時操作,觸發ANR            HandleResult("資料更新成功:" + new Random().Next(10));更新其他UI元素
上面的代碼就會阻塞主UI線程,其實對話方塊也不會顯示出來,調用對話方塊show方法後,對話方塊並不會立即出現,待讀者自行討論,因此上面的效果特別糟糕,只會顯示按鈕被按下的效果,十秒之後更新UI,對話方塊不會顯示出來,因此正確的做法是顯示一個對話方塊之後,將耗時的操作放在其他線程中去執行,執行完成之後再更新ui,但是我們並不能在其他線程中直接更新UI元素,因此這篇文章的主題就是講解如何在非UI線程中更新UI元素。

下面進入正題

在正常開發過程中,我們通常需要將程式中遇到的比較耗時的操作新開其他線程去執行,以防阻塞主UI線程導致ANR錯誤,但是在實際開發過程中可能會遇到如下兩個異常資訊

1、Only the original thread that created a view hierarchy can touch its views;

2、Can't create handler inside thread that has not called Looper.prepare();

第一種在非UI線程中更新UI元素就會導致這種錯誤,第二種是在非UI線程中視圖顯示某些UI提示資訊;其實可以笼統的歸納為都是在非UI線程中更新UI導致的。我們先看下面兩個錯誤的例子:

一、非UI線程更新UI元素,(在一個按鈕事件中執行以下操作,事件綁定代碼就不貼了)

new Thread(() =>            {                try                {                    mText.Text = "資料更新成功:" + new Random().Next(10);                }                catch (Exception ex)                {                }            }).Start();

執行結果拋出android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.即上面說的第一種錯誤資訊出現的情況。

二、非UI線程進行UI提示。(在一個按鈕事件中執行以下操作,事件綁定代碼就不貼了)

new Thread(() =>            {                try                {                    proDialog.Show();//proDialog是一個dialog                }                catch (Exception ex)                {                }            }).Start();
執行結果拋出java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(),即上面說的第二種錯誤資訊出現的情況。

解決辦法:

這種錯誤對於才接觸這行的開發人員來講,經常出現這樣的問題,其實這種問題也相當簡單比較容易解決,但是最主要的是找到一個最為合適的解決辦法,下面說幾種比較簡單的解決方案。

1、委託式

將非UI元素中執行UI操作的部分委託給主UI線程執行,見以下代碼:

        proDialog.Show();            new Thread(() =>            {                System.Threading.Thread.Sleep(10 * 1000);                this.RunOnUiThread(() => //this 指代的是Activity對象,RunOnUiThread 是Activity的一個成員方法                {                    HandleResult("資料更新成功:" + new Random().Next(10));                });            }).Start();

2、View.Post形式

使用UI元素的Post或者PostDelay方法

官方文檔注釋:Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.

Parameters: action The Runnable that will be executed.

Returns:Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.

樣本見以下代碼:

proDialog.Show();            new Thread(() =>            {                try                {                    System.Threading.Thread.Sleep(10 * 1000);                    mText.Post(() =>                    {                        HandleResult("資料更新成功:" + new Random().Next(10));                    });                }                catch (Exception ex)                {                    this.RunOnUiThread(                        () =>                        {                            Toast.MakeText(this, "線程執行過程中出現了錯誤!", ToastLength.Long).Show();                        }                    );                }            }).Start();
這種方法包括PostDelay方法其實跟第一種方法是極其類似的,底層實現的本質是一樣。


3、Handler形式

1)、初始化一個Handler對象

      Handler mHandler;//定義變數

     mHandler = new Handler(HandleMessage);//初始化,此處可以使用匿名函數等方式

  //方法定義,此方法中主要是更新UI操作

private void HandleMessage(Message msg)          {            switch (msg.What) {                 case 1:                    HandleResult("資料更新成功:" + new Random().Next(10));                    break;            }        }

2)、在恰當的時候,使用handler發送訊息進行UI更新

            proDialog.Show();            new Thread(() =>            {                System.Threading.Thread.Sleep(10 * 1000);                mHandler.SendEmptyMessage(1);            }).Start();
Handler的具體使用可以查閱相關資料再進一步瞭解。

上面的方法大多都是使用了Handler來進行訊息的處理,下面給出一張handler的工作圖,


4、AsyncTask形式

AsyncTask,是android提供的輕量級的非同步類,可以直接繼承AsyncTask,在類中實現非同步作業,並提供介面反饋當前非同步執行的程度(可以通過介面實現UI進度更新),最後反饋執行的結果給UI主線程.

這個代碼有點多,可以自行百度查閱,有相當多的不錯的文章可以借閱。

提醒一點,在Xamarin.Android中,如果傳遞給AsyncTask的執行參數是字串,則需要使用Java.Lang.String進行封裝,早些的版本我測試是需要這樣做的,最近的版本還沒來得及進行測試,稍後我補全這一部分,或者有知道的也可以交流下。

以上就是比較常用的方式。

Demo


個人搞了個部落格App,平時上個廁所,睡覺前等隨便看兩篇文章,總能有些收穫,希望大家支援!http://blog.csdn.net/supluo/article/details/43489475

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.