2019.01.01 更新:解決方法
2019.01.06 更新:另外一個同類型bug
衆所周知,安卓的WebView是個非常坑的控件,這想必不用我說多。花式記憶體洩漏、生命周期混亂之類,碎片化等等的bug我就不提了
然而今天一個發現實在是讓我大跌眼鏡
衆所周知,WebView的saveState與restoreState充滿了bug。Bug如此之多以至于Google在2014年去除了Webview.restoreState()恢複顯示資料的功能
https://developer.android.com/reference/android/webkit/WebView.html#restoreState(android.os.Bundle)developer.android.com
If it is called after this WebView has had a chance to build state (load pages, create a back/forward list, etc.) there may be undesirable side-effects. Please note that this method no longer restores the display data for this WebView.
然而,然而,在安卓裡Activity、Fragment和各種控件重建又是家常便飯的事。一個重建把使用者資料搞丢了怎麼辦?于是有兩大對策:
- 當縮頭烏龜,我就是不重建,這輩子都不會重建。于是有了這一句Google在文檔裡強烈反對的代碼(Google:你們又不肯丢資料又不肯崩布局讓我很為難啊)
android:configChanges="orientation|screenSize"
我不理會系統的onConfigurationChange事件不就完了
2. 實在不行要重建了,我人肉寫一套邏輯來恢複資料可以了吧?Bug多就多,反正常見的重建事件都給我縮頭躲過去了,剩下的不就是一些特例嗎,針對那些特例寫寫就完了。
正常來說這也就夠了,直到我今天發現,除了旋轉螢幕、分屏這些常見事件會觸發重建以外......
插拔藍牙鍵盤也會觸發重建!而且這玩意還不算在screenSize這個類型裡的!上面那句代碼攔不住這個事件
如果沒考慮到這種情況觸發的重建,那麼等接下來用到這個WebView的時候,鬼知道這個WebView裡面的狀态已經變成了什麼。然後再evaluate幾個Javascript,當場爆炸。
可能是插拔藍牙鍵盤這種東西不是每個人都會測試的,是以搜了一時半會居然搜不到相關讨論。這一下子就讓人後背發涼了,今天冒出來個插拔藍牙鍵盤,明天後天還指不定又冒出來個啥事件又繞過去了。
至于有多坑爹,看下面的測試
既然網上搜不到讨論,那很有可能很多已有項目也沒想到這點,于是我針對我目前感興趣的Markdown編輯器測試了一下
以下測試在一加6+H2OS 9.0.2上進行
- MarkdownEditors
首先是廣受好評的MarkdownEditors,這個項目隻在Markdown預覽裡用了WebView。進入預覽界面,插入藍牙鍵盤。嗯,好像沒事?你再點點後退鍵試試
運氣好的話你還能後退到主界面,大部分情況下直接就彈出來“MarkdownEditors”已停止運作,整個應用直接炸了,GG
2. MarkdownX
接下來是另一個廣受好評的MarkdownX。這個項目預覽界面和編輯界面貌似都用了WebView。進入預覽或者編輯界面,插入藍牙鍵盤,界面當場崩潰,GG
不過還好應用沒炸
3. MarkNote(馬克筆記)
馬克筆記隻在預覽界面使用了WebView,但非常好評的是,沒有大bug。除了看到一半時插入鍵盤會被強行滾回到頁面頂部以外。
4. 為知筆記
為知筆記不開源,是以到底怎麼實作的我也不知道。我隻知道,在為知筆記的建立一個“文本”筆記再插上藍牙鍵盤會有以下兩個情況随機發生
i. 應用當場爆炸
ii. 應用沒爆,隻是重新整理了一下,看起來沒問題。然而再點點傳回鍵試試,發現按鈕沒了響應
大機率用了WebView
5. 螞蟻筆記(Leanote)
螞蟻筆記是我很看好的開源筆記軟體。螞蟻筆記在“RichText”模式下插拔藍牙鍵盤,好消息是,應用不會崩潰,界面不會沒響應。
壞消息是,丢失所有未儲存的資料,外加強制回到頁面最頂端。
6-9. 易寫 & Dropdown Paper & Notion & JotterPad
沒有bug。不過這幾位都不開源,我猜他們是不是沒用到WebView
可以看到,中招的不少。由于後面幾個應用沒開源,不知道用沒用到WebView,無法統計總的中招率。但是讓我猜的話,我猜中招率為4/5
聲明一下,這篇文章不是為了噴某個軟體,作者深知“開源軟體就是你行你上”的精神。作者隻是表達自己對安卓WebView的強烈負面情緒。
再用原生WebView我吃X!!! (哎,真香......個屁,我還真得用)
目前作者還沒開始找解決辦法,android:configChanges這麼多,插拔藍牙鍵盤到底是哪個,我也沒深入研究過。有了解的大佬歡迎來評論
Update:解決方案,在android:configChanges裡同時加上keyboard|keyboardHidden這兩個事件
另外有空了我就去那幾個開源項目開Issue去
珍愛生命,遠離WebView
Update:
果然這種重建事件簡直讓人後背發涼,有老哥又發現一個:Github Issue
btw,拔插資料線也有類似的問題
我測試了一下,在12月更新之後,拔插充電線會導緻uimode的變化,Activity重新開機
原因已找到:開啟了省電模式之後,uimode&Configuration.UI_MODE_NIGHT_MASK的值為UI_MODE_NIGHT_YES,接上資料線後,這個值變為UI_MODE_NIGHT_NO,因而導緻Activity重新開機
這種省電模式+版本加持的特殊重建簡直是要了命