1. 程式人生 > >View.post在Android 7.0 api24(以上)已不再100%執行

View.post在Android 7.0 api24(以上)已不再100%執行

在Android 7.0 api24,Android 8.0 api25的手機上如果通過new建立的View,如果沒有將它通過addView()加入到ViewGroup佈局中,那通過View.post()傳送出去的任務將不再執行,也就無法通過Viwe.post更新UI。

例項

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mTv1.setText("這是Handler傳送的Message"
); } }; private void btn2Click() { final View view = new View(this); Log.d("liuyz:", "版本號:" + Build.VERSION.SDK_INT); view.post(new Runnable() { @Override public void run() { Log.d("liuyz:", "建立View後直接post"); } }); //Handler傳送一個延遲2秒的任務
mHandler.postDelayed(new Runnable() { @Override public void run() { Log.d("liuyz:", "ViewGroup添加了addView()"); mRoot.addView(view); } }, 2000); }

很簡單,建立一個View,一個直接呼叫View.post(),一個通過Handler.post()延遲2秒執行ViewGroup.addView()方法。

當在api23上不註釋掉Handler.post()方法中mRoot.addView(view)時,列印結果:

com.cn.liuyz.customviewdemo D/liuyz:: 版本號:23
com.cn.liuyz.customviewdemo D/liuyz:: 建立View後直接post
com.cn.liuyz.customviewdemo D/liuyz:: ViewGroup添加了addView()

當註釋掉Handler.post()方法中mRoot.addView(view)時,列印結果:

com.cn.liuyz.customviewdemo D/liuyz:: 版本號:23
com.cn.liuyz.customviewdemo D/liuyz:: 建立View後直接post

當在api24上不註釋掉Handler.post()方法中mRoot.addView(view)時,列印結果:

com.cn.liuyz.customviewdemo D/liuyz:: 版本號:24
com.cn.liuyz.customviewdemo D/liuyz:: ViewGroup添加了addView()
com.cn.liuyz.customviewdemo D/liuyz:: 建立View後直接post

當註釋掉Handler.post()方法中mRoot.addView(view)時,列印結果:

com.cn.liuyz.customviewdemo D/liuyz:: 版本號:24
com.cn.liuyz.customviewdemo D/liuyz:: ViewGroup添加了addView()

由此可得知在Android 7.0 api24的手機上,自定義View如果不通過addView()加入到ViewGroup中,那view.post()中的任務將不再執行

Android 7.0原始碼分析

View.post原始碼

public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        //假設它待會會成功執行
        getRunQueue().post(action);
        return true;
    }

當AttachInfo不為空時,呼叫Handler.post()執行任務,這個沒啥說的。
當AttachInfo為空時,官方給的註釋 假設它待會會成功執行 也就是說可能不執行。

那下面就看下怎麼不執行

getRunQueue方法

private HandlerActionQueue getRunQueue() {
        if (mRunQueue == null) {
            mRunQueue = new HandlerActionQueue();
        }
        return mRunQueue;
    }

返回一個HandlerActionQueue物件

再看post()方法

public void post(Runnable action) {
        postDelayed(action, 0);
    }

public void postDelayed(Runnable action, long delayMillis) {
        //建立一個HandlerAction物件
        final HandlerAction handlerAction = new HandlerAction(action, delayMillis);

        synchronized (this) {
            if (mActions == null) {
                //建立一個大小為4的陣列
                mActions = new HandlerAction[4];
            }
            //給HandlerAction陣列賦值即新增任務
            mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
            mCount++;
        }
    }

post方法就是把任務封裝到HandlerAction物件中,再新增到HandlerAction陣列中,當需要執行的時候,通過迴圈執行任務。

那看下最終處理任務的方法

public void executeActions(Handler handler) {
        synchronized (this) {
            final HandlerAction[] actions = mActions;
            for (int i = 0, count = mCount; i < count; i++) {
                final HandlerAction handlerAction = actions[i];
                handler.postDelayed(handlerAction.action, handlerAction.delay);
            }

            mActions = null;
            mCount = 0;
        }
    }

當需要處理任務時,呼叫的是executeActions方法,通過for迴圈執行封裝到HandlerAction物件中的任務,最後任務的執行是通過handler.postDelayed()執行,也是Handler的那套機制。

那看起來也挺靠譜啊,為什麼就不是100%執行呢?請往下看

executeActions方法是在View的dispatchAttachedToWindow()方法中呼叫的

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
        mAttachInfo = info;
        ....省略....
        if (mRunQueue != null) {
            mRunQueue.executeActions(info.mHandler);
            mRunQueue = null;
        }
        ....省略....
    }

dispatchAttachedToWindow方法的呼叫,是依賴於ViewGroup的addView(View child)方法,看原始碼

public void addView(View child) {
        addView(child, -1);
    }

public void addView(View child, int index) {
        ....省略....
        addView(child, index, params);
    }

public void addView(View child, int index, LayoutParams params) {
        ....省略....
        addViewInner(child, index, params, false);
    }

private void addViewInner(View child, int index, LayoutParams params,
            boolean preventRequestLayout) {
        ....省略....
        AttachInfo ai = mAttachInfo;
        if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
            boolean lastKeepOn = ai.mKeepScreenOn;
            ai.mKeepScreenOn = false;

            //在此呼叫了自定義View的方法
            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
            if (ai.mKeepScreenOn) {
                needGlobalAttributesUpdate(true);
            }
            ai.mKeepScreenOn = lastKeepOn;
        }
        ....省略....
    }

看到這裡應該能稍微看明白點了吧,其實只要記住,在Android 7.0以後不要使用View.post了,使用Handler.post或其他方式代替就行

總結

如果使用new或者LayoutInflater建立一個View,而沒有通過addView()將它新增到ViewGroup佈局中,那View.post()發出去的Runnable任務將不會被執行到,也就起不到更新UI的作用了。

相關推薦

View.post在Android 7.0 api24(以上)不再100%執行

在Android 7.0 api24,Android 8.0 api25的手機上如果通過new建立的View,如果沒有將它通過addView()加入到ViewGroup佈局中,那通過View.post()傳送出去的任務將不再執行,也就無法通過Viwe.post

離線環境下redhat7.2及centOS(7.0版本以上)安裝python3.6以及tensorflow1.5、opencv3.4.5流程和採坑總結

離線環境下redhat7.2已及centOS(7.0版本以上)安裝python3.6以及tensorflow1.5、opencv3.4.5流程和採坑總結 序 Tensorflow的安裝環境 安裝環境監測 離線安裝兩種方式

Android 7.0以上使用OpenCL

由於從Android 7.0, API 24, 開始, 系統將阻止應用連結至非公開NDK庫, 所以, 使用libOpenCL.so時與面向低版本的Android平臺有所不同, 需要把依賴的非公開NDK庫打包到APK中 確定依賴的庫 首先應該確定你所使用的libOpenC.so所依賴的庫, 使用命令objd

關於安卓7.0以上的Https請求抓包問題android:networkSecurityConfig

Android 7.0(API 級別 24)及更高版本預設只承認系統CA,所以預設是安全的,不需要配置。如果想要系統承認使用者自己安裝的CA,則修改配置(比如除錯時會需要抓包)。 面向 Android 6.0(API 級別 23)及更低版本應用的預設配置如下所示,這段配置的意思是,承認系

PictureSelector 7.0以上拍照或拍攝 出現的FileUriExposedException

因為本人專案中用到第三方庫圖片選擇器(PictureSelector),在選擇器中點選拍照或者拍攝遇到點選事件不響應,遇到FileUriExposedException異常,在百度搜索好久都沒有詳細的解決資料,我在這裡將解決辦法告訴大家,希望能幫助到你們! Andr

Android 7.0以上系統訪問相機問題詳解

本章節講述Android 7.0及以上獲取相機問題 1.清單檔案 2.專案配置 3.程式碼 /** * Android 6.0系統及以上申請敏感許可權方法 * */ private void reque

Android 6.0 7.0以上 動態許可權

android 6.0版本開始,google粑粑處於安全性考慮,敏感的許可權只在manifest註冊已經不可以了(例如攝像頭許可權,定位許可權等等),需要在程式碼中動態註冊。 以下對許可權做一些介紹(轉載): 以下是需要單獨申請的許可權,共分為9組,每組只要有一個許可權申

Android 7.0及其以上系統拍照,開啟相簿,裁剪,報錯: android.os.FileUriExposedException: file:///storage/emulated/0/.....

全部程式碼:點選下載注意:如果你原先的應用的targetSdkVersion本來就小與27。那就拍照。什麼都不修改。也不會崩潰。但是、一旦你修改了你的targetSdkVersion為27.或者28。那你的應用就會報出這些問題。。具體原因。請自行百度下targetSdkVer

Eclipse Logcat沒有輸出,主要集中在華為或者安卓7.0版本以上的手機

最近給cocos2d-x搭建安卓開發環境的時候,匯入專案到eclipse中,在真機上執行專案時,logcat一直沒有輸出,換了低端點的手機可以輸出,後來發現好像安卓7.0以上的手機都沒輸出,target一直顯示unknow,各種重啟eclipse和adb,設定手

Android 7.0 以上保留數據去除鎖屏密碼的方法

ngs idt ech auto 密碼加密 方法 b- mar jpg 在很多情況下,由於我們的疏忽,導致忘記了鎖屏密碼。也沒有開啟 USB 調試,內置存儲中還有要保留的數據。我們需要在不清除數據的情況下刪除鎖屏密碼。接下來我們就介紹該如何做。 註意事項 首先要註意

微信環境的PHP版本升級7.0以上的一些坑

api open blog oba pos body 升級 環境 ont 坑一:微信支付Api.class.php 或 微信API :WxPay.Api.php 的 notify() 方法 支付結果通用通知 //獲取通知的數據 // $xml = $G

續:糾正:ubuntu【7.04】可以安裝,而且完美的安裝 ! for《Oracle-10.2.0.1,打補丁10.2.0.5:在 debian 版本4【不含4】以上,及 ubuntu 7.04【不含7.04】以上都可以安裝!》

etc ubun oracl poweroff ++ ldconfig red aio edi n次的測試後,最終證明,如下做法,可以完美安裝。 中間都不帶任何一個錯誤的!!!完美! dhclient vi /etc/profile ll cd /e

Android 7.0以上系統獲取以content開頭的檔案拿不到正確路徑,報錯column-data-does-not-exist

我們專案的使用場景,手機qq開啟檔案,選擇其他開啟方式,選擇我們自己的應用開啟,通過intent.getData()獲取檔案地址,後來發現在Android7.0之後的版本,獲取到的地址不正確,說檔案不存在。日誌報錯column-data-does-not-exist, 經過一天的折騰,終於在網上

Android開發——Android 7.0以上出現儲存圖片失敗的問題

前言 在日常的Android開發當中,我們可能遇到儲存圖片的需求。這個功能是相對容易去實現的,但是今天我更新之前的專案的程式碼的時候出現了一個Android 7.0儲存圖片失敗的情況。因為不是本人開發的,我將程式碼從頭看起,看起來沒有程式碼寫的沒有錯誤呀!我就有點頭疼呀,到底是哪個環

python+appium-desktop:安卓(android)7.0以上使用appium無法定位元素(無法refresh)且 無法執行指令碼

--解決方法:   啟動appium時配置中新增: "automationName":"uiautomator2" --擴充套件:     想支援安卓7.0及以上版本需要滿足一下3點:     1、使用appium-desktop 1.6.3以及以上版本     2、啟動appium的driver配置新增:"

CentOS 7.0在虛擬機以上版本的安裝步驟

聲明 當前時間 https csdn alt 進行 掛載 打開 nom 1、安裝完成後顯示如下 2、修改圖中標出的鏡像位置,選擇自己安裝的iso鏡像位置 3、設置完成後,點擊“開啟此虛擬機” 4、開啟之後,鼠標點進去(點擊黑色屏幕,鼠標消失)

安卓7.0以上作業系統長按桌面logo建立快捷方式

本文已授權微信公眾號:鴻洋(hongyangAndroid)在微信公眾號平臺原創首發。 就在前幾天的一個晚上, Google召開了它的秋季釋出會,

Android拍照及圖片裁剪、呼叫系統相簿(相容6.0以上許可權處理及7.0以上檔案管理)

前言: 最近工作修改較舊的專案時,涉及到了圖片相關功能 ,在使用安卓6.0手機及7.1手機拍照時,遇到了因許可權及檔案管理導致程式崩潰等問題。 剛好把功能修改完,把程式碼簡單地貼一下,方便以後使用。 本文demo包含以下要點: Android6.0執

Android 7.0以上(包含8.0), 或者有虛擬按鍵,popupWindow彈窗位置異常的終極解決方案

問題描述 前段時間發現Popupwindow在8.0的手機上顯示成全屏了,搜了下發現7.0以上就有這個問題了,好久沒寫Popwindow了,才知道(尷尬)。於是總結了在以下情況可能出問題: 當設定PopupWindow 的高度為 MATCH_PARENT,呼叫 showAsD