recherche

Maison  >  Questions et réponses  >  le corps du texte

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();
                    }
                });
    }
天蓬老师天蓬老师2771 Il y a quelques jours1291

répondre à tous(3)je répondrai

  • PHP中文网

    PHP中文网2017-04-18 09:15:26

    Vous utilisez l'architecture MVP. Vous ne devez pas utiliser les contrôles de la vue dans le présentateur, mais vous utilisez le contrôle Dialog dans le présentateur.
    La bonne approche devrait donc être la suivante :

    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();
                            }
                        });
                        
             }
             
         }               
                        
            
    

    répondre
    0
  • ringa_lee

    ringa_lee2017-04-18 09:15:26

    Vous avez imprimé que l'environnement dans lequel la méthode downloadProgress() est exécutée n'est pas UI线程, alors vous mettez

    dialog.setMessage("正在下载文件......" + (int) (progress * 100) + "%");
    Mettez simplement l'exécution de

    sur le fil UI.

    runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    dialog.setMessage("正在下载文件......" + (int) (progress * 100) + "%");
                }
            });

    ||-------------------------Supplément-------------------------------- - -----||

    Je viens d'imprimer le log, dans le fil et sous-fil de l'interface utilisateur :

    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

    L'identifiant du thread principal est 1, l'identifiant du sous-thread est 807, leurs noms sont tous deux principaux, et le nom du thread peut être spécifié :

    public Thread(String name) {
            //这是指定线程名称的构造函数
            init(null, null, name, 0);
        }

    L'ID du fil est généré en interne et ne peut pas être spécifié manuellement. En d'autres termes, le nom du fil n'est pas convaincant. L'ID est le seul. Si les deux ID sont différents, ce n'est pas le même fil. . Ils ne sont pas les mêmes que le fil principal. Si l'identifiant est différent, alors le fil différent n'est pas le fil principal. Vous ne savez pas avec quoi lutter. Vous pouvez consulter le code source du Thread. classe :

    tid = nextThreadID();
    ....
    private static synchronized long nextThreadID() {
            return ++threadSeqNumber;
        }

    répondre
    0
  • ringa_lee

    ringa_lee2017-04-18 09:15:26

    L'exécution des tâches de téléchargement dans UIThread bloquera l'interface. Afin de ne pas affecter l'expérience de l'application, nous exécuterons les tâches de téléchargement dans des threads asynchrones, et les rappels exécutés dans des threads asynchrones le seront naturellement dans des threads asynchrones.
    Le mécanisme de communication par thread le plus couramment utilisé dans Android est Handler :

        Handler mHandler = new Handler(Looper.getMyLooper());
        handler.post(new Runnable(){
            @Override
            void run(){
            //在这里更新ui就好了
            }
        })

    répondre
    0
  • Annulerrépondre