日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Android更新UI的幾種方法

 黃三歲大愛(ài)人生 2019-05-07

第一種場(chǎng)景:

在UI線程中更新UI,這種是最簡(jiǎn)單的,直接更新UI即可。
代碼如下

public class MainActivity extends AppCompatActivity { private Button bt_click_me; private TextView tv_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_click_me = findViewById(R.id.bt_click_me); tv_text = findViewById(R.id.tv_text); bt_click_me.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tv_text.setText('111111111111111'); } }); } }

第二種場(chǎng)景:

從子線程中更新UI

代碼如下

public class MainActivity extends AppCompatActivity {

    private Button bt_click_me;
    private TextView tv_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bt_click_me = findViewById(R.id.bt_click_me);
        tv_text = findViewById(R.id.tv_text);

        bt_click_me.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        tv_text.setText('111111111111111');
                    }
                });
                thread.start();
            }
        });
    }
}

當(dāng)點(diǎn)擊按鈕更新UI的時(shí)候就會(huì)發(fā)現(xiàn)報(bào)了異常,異常如下

圖片.png

這個(gè)異常證明了子線程不能直接更新UI,解決方案如下

(1)通過(guò)Activity中的runOnUIThread方法

public class MainActivity extends AppCompatActivity { private Button bt_click_me; private TextView tv_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_click_me = findViewById(R.id.bt_click_me); tv_text = findViewById(R.id.tv_text); bt_click_me.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Thread thread = new Thread(new Runnable() { @Override public void run() { runOnUiThread(new Runnable() { @Override public void run() { tv_text.setText('111111111111111'); } }); } }); thread.start(); } }); } }

我們來(lái)深入源碼

/**
 * Runs the specified action on the UI thread. If the current thread is the UI
 * thread, then the action is executed immediately. If the current thread is
 * not the UI thread, the action is posted to the event queue of the UI thread.
 *
 * @param action the action to run on the UI thread
 */
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

源碼的意思是說(shuō), 如果當(dāng)前線程不是UI線程, 那么執(zhí)行

mHandler.post(action);

否則直接執(zhí)行run。

這個(gè)結(jié)論直接告訴了我們,Handler的post方法也能做到從子線程更新UI。

(2)通過(guò)Handler的post方法

public class MainActivity extends AppCompatActivity {

    private Handler handler = new Handler();

    private Button bt_click_me;
    private TextView tv_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bt_click_me = findViewById(R.id.bt_click_me);
        tv_text = findViewById(R.id.tv_text);

        bt_click_me.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                tv_text.setText('111111111111111');
                            }
                        });
                    }
                });
                thread.start();
            }
        });
    }
}

我在UI線程中new了一個(gè)Handler對(duì)象,在子線程中用這個(gè)對(duì)象來(lái)調(diào)用post方法。

我們來(lái)深入源碼

/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. * * @return 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. */ public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }

在Handler對(duì)象中,有一個(gè)post方法,分析源碼得知, 這個(gè)方法將形參r封裝到一個(gè)消息里面, 再利用sendMessageDelayed方法將消息發(fā)送(添加)到消息隊(duì)列。(注:理解這句話需要對(duì)Handler機(jī)制有一定的了解)

我們得出結(jié)論,通過(guò)handler發(fā)送消息也能實(shí)現(xiàn)子線程更新UI。

(3)通過(guò)handler發(fā)送消息來(lái)實(shí)現(xiàn)子線程更新UI

public class MainActivity extends AppCompatActivity {

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 1:
                    tv_text.setText('111111111111111');
                    break;
            }
        }
    };

    private Button bt_click_me;
    private TextView tv_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bt_click_me = findViewById(R.id.bt_click_me);
        tv_text = findViewById(R.id.tv_text);

        bt_click_me.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {

                        Message message = Message.obtain();
                        message.what = 1;
                        handler.sendMessage(message);

                    }
                });
                thread.start();
            }
        });
    }
}

(4)通過(guò)view的post方法實(shí)現(xiàn)

public class MainActivity extends AppCompatActivity { private Button bt_click_me; private TextView tv_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt_click_me = findViewById(R.id.bt_click_me); tv_text = findViewById(R.id.tv_text); bt_click_me.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Thread thread = new Thread(new Runnable() { @Override public void run() { bt_click_me.post(new Runnable() { @Override public void run() { tv_text.setText('111111111111111'); } }); } }); thread.start(); } }); } }

我們來(lái)深入源碼

/**
 * <p>Causes the Runnable to be added to the message queue.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 *
 * @return 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.
 *
 * @see #postDelayed
 * @see #removeCallbacks
 */
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }

    // Postpone the runnable until we know on which thread it needs to run.
    // Assume that the runnable will be successfully placed after attach.
    getRunQueue().post(action);
    return true;
}

其實(shí)最終也調(diào)用了mHandler.post(action)方法。

第二種場(chǎng)景總結(jié):

(1)Android從子線程更新UI就是通過(guò)Handler來(lái)實(shí)現(xiàn)的,官方發(fā)明Handler主要就是給我們更新UI用的。

其實(shí)吧, 一些腦洞大開(kāi)的猿類動(dòng)物偏不按照常理出牌:

(1)在子線程中他偏偏不用Handler更新UI?
public class MainActivity extends AppCompatActivity { private TextView tv_text; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_text = findViewById(R.id.tv_text); tv_text.setText('1111111'); Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i=0;i<500000;i ){ Log.e('aa', String.valueOf(i));//耗時(shí)操作 if(i==499999){ tv_text.setText('22222222'); } } } }); thread.start(); } }

這個(gè)例子是從onCreate方法中的子線程更新UI, 其中有耗時(shí)操作

圖片.png

上述的例子依然報(bào)錯(cuò), 那么怎么才能不讓他報(bào)錯(cuò)呢,往下看

public class MainActivity extends AppCompatActivity {

    private TextView tv_text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tv_text = findViewById(R.id.tv_text);
        tv_text.setText('1111111');
        Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        tv_text.setText('22222222');
                    }
                });
        thread.start();
    }
}

當(dāng)我去除耗時(shí)操作時(shí),就不會(huì)報(bào)這個(gè)錯(cuò)誤了,那么為什么呢?

我們來(lái)翻看源碼

在ViewRootImpl類中找到了這個(gè)方法,這個(gè)方法就是之所以報(bào)錯(cuò)的根本

void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( 'Only the original thread that created a view hierarchy can touch its views.'); } }

而ViewRootImpl對(duì)象是在執(zhí)行到onResume才創(chuàng)建時(shí)的,所以得出結(jié)論,onCreate中的子線程如果不是耗時(shí)操作,基本都是可以更新UI的,但不能保證。因?yàn)橐粋€(gè)是UI線程,一個(gè)是子線程,我們誰(shuí)也不知道哪個(gè)線程更快一些。

(2)把消息從UI線程發(fā)送到子線程?
public class MainActivity extends AppCompatActivity {

    private Button bt_click_me;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bt_click_me = findViewById(R.id.bt_click_me);

        bt_click_me.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message message = Message.obtain();
                message.what = 1;
                handler.sendMessage(message);
            }
        });

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                Looper looper = Looper.myLooper();
                handler = new Handler(looper){
                    @Override
                    public void handleMessage(Message msg) {
                        super.handleMessage(msg);
                        Log.d('aa', '11111');
                    }
                };
                Looper.loop();
            }
        });
        thread.start();
    }
}

UI線程本身就有Looper,但是子線程是沒(méi)有Looper的,所以必須新建Looper來(lái)輪詢Looper中的消息隊(duì)列。

? 著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多