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. mysql优化 - mysql count(id)查询速度如何优化?2. mysql主从 - 请教下mysql 主动-被动模式的双主配置 和 主从配置在应用上有什么区别?3. python - django 里自定义的 login 方法,如何使用 login_required()4. node.js - node_moduls太多了5. 主从备份 - 跪求mysql 高可用主从方案6. angular.js - 不适用其他构建工具,怎么搭建angular1项目7. angular.js - Angular路由和express路由的组合使用问题8. python如何不改动文件的情况下修改文件的 修改日期9. java8中,逻辑与 & 符号用在接口类上代表什么意思10. python - 关于ACK标志位的TCP端口扫描的疑惑?
