多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > 子線程不能更新UI線程總結

子線程不能更新UI線程總結

來源:程序員人生   發布時間:2017-05-06 14:50:49 閱讀次數:6575次

子線程不能更新UI線程總結

  • 子線程整的不能更新UI線程嗎
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

有時候大家做項目的時候偶爾會碰到這個毛病。不用說大家都知道是子線程更新主線程(UI)線程的問題,一樣大家也會給出相對應的解法:使用handle+Thread方法通過發送Message進行更新UI線程。
eg:

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                iv_img.setBackground(ContextCompat.getDrawable(MainActivity.this,R.drawable.ic_launcher));
                btn_commit.setText("iiiiiiiiiiiiiiiiiiiii  ");
                Toast.makeText(MainActivity.this,"阿斯蒂芬噶是的發送到",Toast.LENGTH_LONG).show();
            }
        }).start();

此時就會出現1下毛病:
這里寫圖片描述
此時我們都知道最簡單的1種解決方式就是:

        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = handler.obtainMessage();
                msg.what = 100;
                msg.obj = "發送消息";
                handler.sendMessage(msg);
            }
        }).start();
    }

接下來我們就來探究1下:子線程和UI線程之間更新問題。
首先我們要知道:

  • android利用程序遵守的是依照單線程模式的原則
    這是由于:Android UI操作其實不是線程安全的并且這些操作必須在UI線程中履行。
    android的UI線程就是主線程,當做粗第1次啟動的時候 Android會同時啟動1個對應的主線程(Main Thread),主線程主要負責處理與UI相干的事件,如:用戶的按鍵事件,用戶接觸屏幕的事件和屏幕繪圖事件,并把相干的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。這個和Java的運行機制是不同的。
    andorid在UI中進行繪圖和處理事件啟動1個監聽的作用 ,此時就必須要在UI中時時刻刻的進行相利用戶的點擊事件和UI操作事件。異步操作和耗時操作需要另外氣1個線程,不然UI線程在5s內未響利用戶的操作,系統就會彈出彈出對話框停止程序終止進程的提示。

我們想看看報錯的這行代碼在ViewRootImpl.java:

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

mThread是1個線程,如果改線程是當前的線程的時候,則繼續向下走,不會拋出異常。大家可以看到,我在onCreate方法,只有1個線程,肯定是當前的線程,那為何會報錯呢?我們接著往下看。
接下來我們看看checkThread()在那幾處用到了,其中有

  @Override
    public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
        checkThread();
        if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
        .......
        invalidateRectOnScreen(dirty);
        return null;
    }
 @Override
    public void requestFitSystemWindows() {
        checkThread();
        mApplyInsetsRequested = true;
        scheduleTraversals();
    }
   @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

從報錯的點 at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:848)我們可以看到是848行是invalidateChildInParent方法里調用的。我們進1步與發現invalidateChildInParent又在invalidateChild()里調用,在View中那個地方調用了呢?我們進1步向下跟進。

    void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
            boolean fullInvalidate) {
            ......    
            final AttachInfo ai = mAttachInfo;
            final ViewParent p = mParent;
            if (p != null && ai != null && l < r && t < b) {
                final Rect damage = ai.mTmpInvalRect;
                damage.set(l, t, r, b);
                p.invalidateChild(this, damage);
            }
            ......            
    }

而invalidateInternal方法在invalidate()方法中是這樣的

    void invalidate(boolean invalidateCache) {
        invalidateInternal(0, 0, mRight - mLeft, mBottom -  mTop, invalidateCache, true);
    }
到這里1目了然了。原來View中再重新回執的時候刷新方法里調用了ViewRootImpl的checkThre(),刷新是檢查該線程是否是當前的線程,即主線程。
我們根據源碼可以知道invalidate()–>checkThread()是1步1步去調用的。
android.view.View.setBackground()
android.view.View.setBackground()—->setBackgroundDrawable()–> invalidate()–>invalidateInternal()–>invalidateChild()–>checkThread()–>invalidateRectOnScreen()

現在我們清楚了,嚴格的來講原來子線程是不能刷新UI線程的。
解決方式:
第1種方式:

 new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg = handler.obtainMessage();
                msg.what = 100;
                msg.obj = "發送消息";
                handler.sendMessage(msg);
            }
        }).start();
    }

第2中方式:

         runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 try {
                     Thread.sleep(200);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 iv_img.setBackground(ContextCompat.getDrawable(MainActivity.this,R.drawable.ic_launcher));
             }
         });

第3種方式: 利用AsyncTask方法。
以上都是進程間通訊的幾種方式。這里我不再做過量的描寫。
如果您覺我的文章對您有所幫助,
QQ交換群 :232203809,歡迎入群
這里寫圖片描述
微信公眾號:終端研發部
(歡迎關注學習和交換)

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 久久天天躁狠狠躁夜夜2020一 | 欧美激情一区二区三区在线播放 | 国产精品久久久久国产精品 | jizz自拍 | 欧美日本综合一区二区三区 | 久久国产一久久高清 | 欧美色伊人 | 国产成人精品久久一区二区三区 | 精品国产欧美一区二区三区成人 | 国产亚洲欧美日韩在线观看一区二区 | 国产成人综合亚洲欧洲色就色 | 精品一久久香蕉国产二月 | 国产亚洲精品久久久久久 | 日本一视频一区视频二区 | 日产高清卡一卡二无卡三区 | 一区二区三区四区精品 | 欧美网站在线看 | 羞羞视频日本动漫免费网站 | 亚洲高清视频在线播放 | 国产乱码精品一区二区三区卡 | 最近高清中文字幕大全1 | 久久综合亚洲一区二区三区 | 欧美日本在线观看 | 中文字幕无线码中文字幕免费 | 国产一区二区三区四区在线观看 | 国产精品嫩草免费视频 | 亚洲精品第一区二区三区 | 欧美人马交 | 亚洲国产成人精品一区91 | 国产精品爱久久久久久久 | 欧美日韩精品国产一区二区 | 午夜羞羞影院 | 高清欧美性猛交xxxx黑人猛交 | www.黄色大片| 午夜在线观看视频在线播放版 | 国产或人精品日本亚洲77美色 | 欧美黑人性猛交 | 一区二区三区毛片免费 | 欧美性猛交xxxx乱大交蜜桃 | 最近免费中文字幕完整7 | 亚洲国产第一页 |