thread - Android 主線程更新UI問題
問題描述
本人使用了OKGO的框架, 下載文件,在下載之前創建一個 等待框,在更新進度的回調中,更新等待框的百分比, 可是爆了如下錯誤!
通過LOG 發現 UI線程ID 不一樣
是什么問題? 求大神解決,以下是源碼~!
public void setDownloadUrl(String url) {if (TextUtils.isEmpty(url)) return;if (dialog == null) { dialog = new ProgressDialog(mainViewImpl.getContext()); dialog.setCancelable(false); dialog.setCanceledOnTouchOutside(false); dialog.setMessage('正在下載文件...'); dialog.setMax(100); dialog.setTitle('軟件更新');}dialog.show();L.i('(外)線程ID: ' + Thread.currentThread().getId());OkGo.get(url)//.tag(this)//.execute(new FileCallback() { //文件下載時,可以指定下載的文件目錄和文件名 @Override public void onSuccess(File file, Call call, Response response) {// file 即為文件數據,文件保存在指定目錄L.i('成功: ');if (dialog != null && dialog.isShowing()) dialog.dismiss();startUpdate(file); } @Override public void downloadProgress(long currentSize, long totalSize, float progress, long networkSpeed) {//這里回調下載進度(該回調在主線程,可以直接更新ui)L.i('(內)線程ID: ' + Thread.currentThread().getId());dialog.setMessage('正在下載文件......' + (int) (progress * 100) + '%'); } @Override public void onError(Call call, Response response, Exception e) {super.onError(call, response, e);L.i('失敗: ');if (dialog != null && dialog.isShowing()) dialog.dismiss(); }}); }
問題解答
回答1:你使用的是MVP架構,在Presenter中不應該操作View中的控件,而你在Presenter中操作了Dialog這個控件。所以正確的做法應該是下面的:
Interface View{ void showDialog(); void updateDialog(int count); void dismissDialog(); void showError(); void dismissError();}class Presenter{ View view; public Presenter(View view){ this.view=view; } public void setDownloadUrl(String url){ OkGo.get(url)// .tag(this)// .execute(new FileCallback() { //文件下載時,可以指定下載的文件目錄和文件名@Overridepublic void onSuccess(File file, Call call, Response response) { // file 即為文件數據,文件保存在指定目錄 view.dismissDialog();} @Overridepublic void downloadProgress(long currentSize, long totalSize, float progress, long networkSpeed) { view.update((int)progress);} @Overridepublic void onError(Call call, Response response, Exception e) { super.onError(call, response, e); view.dismissDialog(); view.showError();} }); } } 回答2:
你已經打印出downloadProgress()方法執行的環境不是UI線程,那么你把
dialog.setMessage('正在下載文件......' + (int) (progress * 100) + '%');
的執行放在UI線程就可以了.
runOnUiThread(new Runnable() { @Override public void run() {dialog.setMessage('正在下載文件......' + (int) (progress * 100) + '%'); }});
||-------------------------補充 -------------------------||
我剛剛也打印了log,在ui線程和子線程中:
03-03 15:20:54.592 30842-30842/com.didikee.commondependence E/test: Out-->ThreadName: main id: 103-03 15:20:54.592 30842-30891/com.didikee.commondependence E/test: Inner-->ThreadName: main id: 807
主線程的id是1,子線程的id是807,他們的名稱都是main,而線程的名稱是可以指定的:
public Thread(String name) {//這是指定線程名稱的構造函數init(null, null, name, 0); }
而線程的id卻是內部生成的,不可以手動指定,也就是說線程的名稱展示成什么并沒有說服力,id才是唯一,兩個id不一樣就不是同一線程,與主線程id不一樣那不一樣的那個就不是主線程,題主不知道糾結什么,可以去看Thread類的源碼:
tid = nextThreadID();....private static synchronized long nextThreadID() {return ++threadSeqNumber; }回答3:
下載任務執行在UIThread將會阻塞界面,為了不影響應用體驗,我們都會在異步線程當中執行下載任務,而異步線程中執行的回調自然是在異步線程了。Android中最常用的線程通訊機制是Handler:
Handler mHandler = new Handler(Looper.getMyLooper()); handler.post(new Runnable(){@Overridevoid run(){//在這里更新ui就好了} })
相關文章:
1. javascript - 前端開發 本地靜態文件頻繁修改,預覽時的緩存怎么解決?2. docker不顯示端口映射呢?3. python - linux怎么在每天的凌晨2點執行一次這個log.py文件4. css - 關于ul的布局5. android - 優酷的安卓及蘋果app還在使用flash技術嗎?6. mysql數據庫每次查詢是一條線程嗎?7. java - public <T> T findOne(T record) 這是什么意思8. html5和Flash對抗是什么情況?9. 小程序怎么加外鏈,語句怎么寫!求救新手,開文檔沒發現10. 如何分別在Windows下用Winform項模板+C#,在MacOSX下用Cocos Application項目模板+Objective-C實現一個制作游戲的空的黑窗口?
