本人使用了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();
}
});
}
PHP中文网2017-04-18 09:15:26
你使用的是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() { //文件下载时,可以指定下载的文件目录和文件名
@Override
public void onSuccess(File file, Call call, Response response) {
// file 即为文件数据,文件保存在指定目录
view.dismissDialog();
}
@Override
public void downloadProgress(long currentSize, long totalSize, float progress, long networkSpeed) {
view.update((int)progress);
}
@Override
public void onError(Call call, Response response, Exception e) {
super.onError(call, response, e);
view.dismissDialog();
view.showError();
}
});
}
}
ringa_lee2017-04-18 09:15:26
你已经打印出downloadProgress()
方法执行的环境不是UI线程
,那么你把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: 1
03-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;
}
的执行放在UI
线程就可以了.🎜
rrreee
🎜||-------------------------补充 -------------------------||🎜
🎜我刚刚也打印了log,在ui线程和子线程中:🎜
rrreee
🎜主线程的id是1,子线程的id是807,他们的名称都是main,而线程的名称是可以指定的:🎜
rrreee
🎜而线程的id却是内部生成的,不可以手动指定,也就是说线程的名称展示成什么并没有说服力,id才是唯一,两个id不一样就不是同一线程,与主线程id不一样那不一样的那个就不是主线程,题主不知道纠结什么,可以去看Thread
类的源码:🎜
rrreeeringa_lee2017-04-18 09:15:26
下载任务执行在UIThread将会阻塞界面,为了不影响应用体验,我们都会在异步线程当中执行下载任务,而异步线程中执行的回调自然是在异步线程了。
Android中最常用的线程通讯机制是Handler:
Handler mHandler = new Handler(Looper.getMyLooper());
handler.post(new Runnable(){
@Override
void run(){
//在这里更新ui就好了
}
})