【问题标题】:Modify View from a different thread从不同的线程修改视图
【发布时间】:2013-05-09 16:25:09
【问题描述】:

我正在从服务器获取 JSON,它是我的 ListView 的内容。 一切都很好,但是我想在调用 Json 时创建一个 ProgressDialog。 问题是我需要在不同的线程中调用 JSON(使用 http 方法)并将结果在 ListView 中显示给用户。

这是正在做的事情,但我遇到了错误"05-09 12:13:28.358: W/System.err(344): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."

try {       
            final ProgressDialog progDailog;
            progDailog =ProgressDialog.show(this,"HI", "Loading");

            new Thread(new Runnable() {

                @Override
                public void run() {
                    try 
                    {
                        JSONArray json = new JSONArray(executeHttpGet("http://m-devsnbp.insightlabs.cl/cuentos/json"));
                        progDailog.cancel();
                        ArrayList<HashMap<String, String>> talesList = new ArrayList<HashMap<String, String>>();
                        talesList = jsonToHash(json);
                        adapter = new LazyAdapter((Activity) ctx, talesList, 2);    
                        list.setAdapter(adapter);
                    } 
                    catch (InterruptedException e) 
                    {
                        e.printStackTrace();
                    } catch (JSONException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }   
                }
            }).start();

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

如何从不同的线程更新我的观点?或者这是一种更好的方法?

【问题讨论】:

    标签: android multithreading android-listview progressdialog


    【解决方案1】:

    您需要在主 ui 线程上更新 ui。使用 runOnUiThread

            runOnUiThread(new Runnable() //run on ui thread
                     {
                      public void run() 
                      { 
                        progDailog.cancel(); 
                        adapter = new LazyAdapter((Activity) ctx, talesList, 2);    
                        list.setAdapter(adapter);   
                      }
                     });
    

    还可以考虑使用异步任务。我建议 ypu 使用 asynctask

    http://developer.android.com/reference/android/os/AsyncTask.html

            ProgressDialog pd; 
            LazyAdapter adapter;  
            ListView list; 
            ArrayList<HashMap<String, String>> talesList = new ArrayList<HashMap<String, String>>();  
    

    在你的活动中 onCreate()

            pd = new ProgressDialog(ActivityName.this);
            pd.setTitle("Processing..."); 
            new TheTask().execute(); 
    

    在活动类中将 AsyncTask 定义为内部类

        class extends AsyncTask<Void,Void,Void>
        {
        @Override
    protected void onPreExecute() {
       // TODO Auto-generated method stub
          super.onPreExecute();
          pd.show();
              
    }
    
    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
                     try 
                    {
                        JSONArray json = new JSONArray(executeHttpGet("http://m-devsnbp.insightlabs.cl/cuentos/json"));
                        talesList = jsonToHash(json);
                        
                    } 
                    catch (InterruptedException e) 
                    {
                        e.printStackTrace();
                    } catch (JSONException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }   
        return null;
                 
    }
        
        @Override
    protected void onPostExecute(Void result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
                pd.dismiss();
                adapter = new LazyAdapter(AcctivityName.this, talesList, 2);    
                list.setAdapter(adapter); 
    }  
        }
    

    2021 年 1 月更新

    上述答案已过时( asynctask 已被删除)。还有其他更新 ui 的新方法。取决于您是使用协程还是 rxjava,您可以轻松更新 ui。在这种情况下,最好提出一个新问题。

    【讨论】:

    • 感谢您的详细解释!这样就解决了问题。
    • @FelipeDev.- 很高兴它有帮助。
    【解决方案2】:

    当您尝试从非 UI 线程更新视图时,您需要通过 post() 方法对其进行更新:

    try {       
                final ProgressDialog progDailog;
                progDailog =ProgressDialog.show(this,"HI", "Loading");
    
                Thread mThread = new Thread(new Runnable() {
    
                    @Override
                    public void run() {
                        try 
                        {
                            JSONArray json = new JSONArray(executeHttpGet("http://m-devsnbp.insightlabs.cl/cuentos/json"));
                            progDailog.cancel();
                            ArrayList<HashMap<String, String>> talesList = new ArrayList<HashMap<String, String>>();
                            talesList = jsonToHash(json);
                            adapter = new LazyAdapter((Activity) ctx, talesList, 2);    
                            list.setAdapter(adapter);
                        } 
                        catch (InterruptedException e) 
                        {
                            e.printStackTrace();
                        } catch (JSONException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }   
                    }
                });
    
                post(mThread);
    
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    

    【讨论】:

      【解决方案3】:

      Modyfing Views 应该只在 UI Thread 上进行,所以对我来说,你应该尝试使用一个处理 Activity 引用的类并将其传递给 runnable 以运行

      class UIUpdater{
      private static UIUpdater mInstance;
      private Activity mActivity;
          public static UIUpdater getInstance()
          {
              if(mInstance == null){
                  mInstance = new UIUpdater();
              }
              return mInstance;
          }
      
          public void runOnUiThread(Runnable run){
              mActivity.runOnUiThread(run);
          }
      } 
      

      另一种方法是使用 Loopers: 例如。

      Looper mMainLooper = Looper.getMainLooper();
      

      更多信息见here

      【讨论】:

        【解决方案4】:

        我认为有更好的方法来做到这一点。喜欢用AsyncTask

        这只是您想要做的代码示例。

        private class LongOperation extends AsyncTask<Void, Void, Void> {
        
          private ProgressDialog progressDialog;
          private ArrayList<HashMap<String, String>> talesList;
          private LazyAdapter adapter;
          private Context mContext;
        
          public LongOperation(Context c) {
            mContext = c;
            progressDialog = new ProgressDialog(c);
          }
        
          @Override
          protected void onPreExecute() {
            //operation start, show the dialog
            progressDialog.show();
          }
        
          @Override
          protected String doInBackground(Void... params) {
            //connect to server and get json
            try 
            {
              JSONArray json = new JSONArray(executeHttpGet("http://m-devsnbp.insightlabs.cl/cuentos/json"));
              talesList = new ArrayList<HashMap<String, String>>();
              talesList = jsonToHash(json);
            } 
            catch (InterruptedException e) 
            {
              e.printStackTrace();
            } catch (JSONException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            } catch (Exception e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
            }   
          }      
        
          @Override
          protected void onPostExecute(Void result) {
            //operation end, dismiss the dialog and set result to list
            progressDialog.dismiss();
            adapter = new LazyAdapter(mContext, talesList, 2);    
            list.setAdapter(adapter);
          }
        
        }
        

        一些你可能想看的链接:

        AsyncTask Android Example

        Understanding AsyncTask

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-03
          • 2013-09-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多