Android更新Ui的幾種方法和見解

《代碼里的世界》

用文字札記描繪自己 android學習之路

轉(zhuǎn)載請保留出處 by Qiao http://blog.csdn.net/qiaoidea/article/details/45115047

Android更新Ui進階精解(一) android ui線程檢查機制
Android更新Ui進階精解(二) android 線程更新UI機制


1. 簡述

先貼一個我們剛做Android開發(fā)時候最容易遇到的一個錯誤異常 AndroidRuntimeException“Only the original thread that created a view hierarchy can touch its views”
  具體原因是當我們在對ui做出更改時燥爷,Android檢查我們當前的操作線程是否為UI線程压储,若不是即報該異常忘古。(詳見 ViewRootImpl類的checkThread方法)。

2. 方案

那么我們該如何更新Ui呢疾渴,這里簡要使用和講述的是Handler。先簡述概念:Adroid在運行時會創(chuàng)建一個UiThread的主線程來負責控制UI界面的顯示屯仗、更新和控件交互搞坝。其他線程則通過handler將更新邏輯等消息事件(Message) push到主線程的消息隊列(MessageQueue),最后由主線程有序地處理這些消息事件(handleMessage)魁袜,實現(xiàn)對界面的更新和控制桩撮。
  本文主要講述更新UI的方法和使用技巧,關(guān)于更新過程的原理內(nèi)容請關(guān)注后邊的 Android更新Ui進階峰弹。
  其中店量,常用的幾種方法簡單概括有:

  • handler.sendMessage();
  • handler.post();
  • 在activity中可以 runOnUiThread();
  • 在子view中可以 view.post()

其實后邊幾種方法整個流程處理邏輯基本也是基于第一種,封裝成消息事件對象發(fā)送至隊列并被有序處理而已鞠呈,只是android給我們封裝好了方法融师。

3. 實踐

3.1 handler.senMessage() + handler.dispatchMessage()

在activity中定義主線程的handler(子線程同樣可以定義handler,當然 需要 消息泵looper來輪訓)蚁吝,實現(xiàn)dispatchMessage方法處理message對象旱爆。該對象是在子線程處理邏輯完成之后,將內(nèi)容封裝成消息窘茁,通過handler.senMessage()發(fā)送該消息怀伦。
   示例代碼:
a. 首先定義好更改ui的代碼邏輯 handler和dispatchMessage方法

   /**
     * 通過message攜帶結(jié)果數(shù)據(jù)變更ui
     * 先定義主線程handler和更新數(shù)據(jù)的方法
     */
    private static final int UPDATE_TITLE = 0; //更新標題的標志
    private Handler mainHandler= new Handler()
    {
        public void dispatchMessage(android.os.Message msg) {
            if(msg.what == UPDATE_TITLE){
                String title = msg.getData().getString("Result");
                titleView.setText(title);
            }else{
                //其他消息
            }
        };
    };

b. 需要處理數(shù)據(jù)的部分,比如某些耗時操作山林,放在子線程中執(zhí)行房待,之后調(diào)用handler.senMessage()

new Thread(){
            @Override
            public void run() {
                //你的處理邏輯,這里簡單睡眠一秒
                this.sleep(1000);

                //通知更新UI
                //Message msg = new Message();
                //我們可以使用構(gòu)造方法來創(chuàng)建Message,但出于節(jié)省內(nèi)存資源的考量驼抹,我們應該使用Message.obtain()從消息池中獲得空消息對象
                Message msg = mainHandler.obtainMessage();
                msg.what = UPDATE_TITLE;
                    Bundle bundle = new Bundle();//消息數(shù)據(jù)實體
                    bundle.putString("Result", "sendMsg——Result");
                    msg.setData(bundle);
                    //mainHandler.sendMessage(msg);
                    //如果使用的是Message.obtain()我們可以直接
                    msg.sendToTarget();
            }
        }.start();

這里提下該消息對象Message (更多詳見Android更新Ui進階

可用于傳數(shù)據(jù)的參數(shù):

  • int what;
  • int arg1;
  • int arg2;
  • Object obj;
  • Bundle data;

用于回調(diào)的

  • Runnable callback桑孩;

通常為了使代碼邏輯看起來更清晰易于理解,我更傾向于通過直接傳回調(diào)callback 來更新Ui(方案∩氨巍2/3/4)洼怔。針對方案一,可以簡單優(yōu)化為
  直接定義handler

private Handler mainHandler= new Handler();

發(fā)送消息

new Thread(){
            @Override
            public void run() {
                try {
                    //你的處理邏輯,這里簡單睡眠一秒
                    this.sleep(1000);
                    
                    //利用obtain
                    msg = Message.obtain(mainHandler, new Runnable() {
                        
                        @Override
                        public void run() {
                            titleView.setText("sendMsg——Result");
                        }
                    });
                    msg.sendToTarget();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

3.2 handler.post()

對于方案一的第二種方法左驾,又可以簡化為

     new Thread(){
            @Override
            public void run() {
                try {
                    //你的處理邏輯,這里簡單睡眠一秒
                    this.sleep(1000);
                    
                    mainHandler.post(new Runnable() {
                        
                        @Override
                        public void run() {
                            //你的處理邏輯
                            titleView.setText("postRunnable——Result");
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

3.3 runOnUiThread()

對于上邊的方案镣隶,在activity中又可以進一步簡化,不用new Handler對象诡右,直接調(diào)用runOnUiThread()方法

         /**
         * 使用activity的runOnUiThread
         */
        new Thread(){
            @Override
            public void run() {
                try {
                    //你的處理邏輯,這里簡單睡眠一秒
                    this.sleep(1000);
                    
                    runOnUiThread(new Runnable() {
                        
                        @Override
                        public void run() {
                            titleView.setText("runOnUiThread——Result");
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

3.4 view.post()

當然安岂,如果有子view或自定義view,處理邏輯后可以直接用view.post()方法

new Thread(){
            @Override
            public void run() {
                try {
                    //你的處理邏輯,這里簡單睡眠一秒
                    this.sleep(1000);
                    
                    viewPostBtn.post(new Runnable() {
                        
                        @Override
                        public void run() {
                            titleView.setText("viewPost——Result");
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

綜上帆吻,更新view看起來就不是那么難使用了域那。。
最后附上源代碼文件。
  點擊下載源碼


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末次员,一起剝皮案震驚了整個濱河市败许,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淑蔚,老刑警劉巖市殷,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異刹衫,居然都是意外死亡醋寝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門带迟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來音羞,“玉大人,你說我怎么就攤上這事仓犬⌒岽拢” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵婶肩,是天一觀的道長办陷。 經(jīng)常有香客問我,道長律歼,這世上最難降的妖魔是什么民镜? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮险毁,結(jié)果婚禮上制圈,老公的妹妹穿的比我還像新娘。我一直安慰自己畔况,他們只是感情好鲸鹦,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跷跪,像睡著了一般馋嗜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吵瞻,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天葛菇,我揣著相機與錄音,去河邊找鬼橡羞。 笑死眯停,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的卿泽。 我是一名探鬼主播莺债,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了齐邦?” 一聲冷哼從身側(cè)響起椎侠,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎措拇,沒想到半個月后肺蔚,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡儡羔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了璧诵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汰蜘。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖之宿,靈堂內(nèi)的尸體忽然破棺而出族操,到底是詐尸還是另有隱情,我是刑警寧澤比被,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布色难,位于F島的核電站,受9級特大地震影響等缀,放射性物質(zhì)發(fā)生泄漏枷莉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一尺迂、第九天 我趴在偏房一處隱蔽的房頂上張望笤妙。 院中可真熱鬧,春花似錦噪裕、人聲如沸蹲盘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽召衔。三九已至,卻和暖如春祭陷,著一層夾襖步出監(jiān)牢的瞬間苍凛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工颗胡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毫深,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓毒姨,卻偏偏與公主長得像哑蔫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容