【问题标题】:ProgressDialog is not shown if I get the result of AsyncTask class from another class如果我从另一个类获得 AsyncTask 类的结果,则不会显示 ProgressDialog
【发布时间】:2014-01-04 18:13:28
【问题描述】:

如果我像这样从一个 AsynkTask 类中获取结果:

Register.java:

public void onClick(View v) {
    LoadFermate backgroundFermate = new LoadFermate(Register.this);
    ArrayList<HashMap<String, String>> fermate;
    try{
        fermate = backgroundFermate.execute().get();
        for (HashMap<String, String> fermata:fermate){
            Toast.makeText(Register.this , fermata.get("Nome"), Toast.LENGTH_SHORT).show();
        }
    }catch (InterruptedException e){
        e.printStackTrace();
    }catch (ExecutionException e){
        e.printStackTrace();
    }
}

ProgressDialog 未显示。相反,如果我在 onPostExecute 方法中做所有这些事情,它就会显示出来。这怎么可能?

我从that question 的其他类中学习了获取值的方法。

在这里我发布了我使用 ProgressDialog 的课程:

LoadingFermate.java:

package com.PacchettoPrincipale.app;

import [...]

public class LoadFermate extends AsyncTask<Void, Void, ArrayList<HashMap<String, String>>> {

    private Context context;

    public LoadFermate(Context context){
        this.context = context;
    }

    private ProgressDialog pDialog;

    private JSONArray mComments = null;
    private ArrayList<HashMap<String, String>> mCommentList;

    //testing on Emulator:
    private static final String DOWNLOAD_FERMATE_URL = "http://10.0.2.2/PrimaAppAndroid/fermate.php";



    //JSON IDS:
    private static final String TAG_COD = "CodFermata";
    private static final String TAG_POSTS = "posts";
    private static final String TAG_NOME = "Nome";

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(context);   //HERE I START THE PDIALOG, and in the onPostExecute method I dismiss it
        pDialog.setMessage("Download fermate...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();
    }

    @Override
    protected ArrayList<HashMap<String, String>> doInBackground(Void... voids) {
        updateJSONData();
        return mCommentList;
    }

    @Override
    protected void onPostExecute(ArrayList<HashMap<String, String>> hashMaps) {
        super.onPostExecute(hashMaps);

        pDialog.dismiss();
    }

    private void updateJSONData() {

        mCommentList = new ArrayList<HashMap<String, String>>();

        JSONParser jParser = new JSONParser();
        JSONObject json = jParser.getJSONFromUrl(DOWNLOAD_FERMATE_URL);

        try {

            mComments = json.getJSONArray(TAG_POSTS);

            for (int i = 0; i < mComments.length(); i++) {
                JSONObject c = mComments.getJSONObject(i);

                int CodFermata = c.getInt(TAG_COD);
                String Nome = c.getString(TAG_NOME);


                HashMap<String, String> map = new HashMap<String, String>();

                map.put(TAG_COD, String.valueOf(CodFermata));
                map.put(TAG_NOME, Nome);

                mCommentList.add(map);

            }
        } catch (JSONException e) {
            e.printStackTrace();
        }  
    }
}

【问题讨论】:

    标签: java android android-asynctask runtime-error progressdialog


    【解决方案1】:

    这是因为您的应用程序的 UI 线程在您等待任务完成时被阻塞。您的程序在此行被阻止:

    ermate = backgroundFermate.execute().get();

    文档中说“get():如有必要,等待计算完成,然后检索其结果。” (你可以在这里阅读:http://developer.android.com/reference/android/os/AsyncTask.html#get()

    在 Android 中,UI 元素(例如进度对话框)不能由多个线程操作。 (这意味着您不能调用它们的任何方法,否则最终会出现异常。)它们只能由创建它们的线程操作。该线程是您的应用程序的主线程(或 UI 线程)。

    但是我们需要在一个单独的线程上工作,并且仍然想更新 UI!

    这个问题可以通过多种方式解决。通过使用 Handlers 和 Runnables,但有时这可能很复杂。 AsyncTask 的概念是代替您完成这项工作。 OnPreExecute() 在 UI 线程上执行,然后在单独的线程上执行任务,onPostExecute() 也在主线程上执行。

    如果您知道这一点,我很抱歉。回到你的问题: 因为你通过在 AsyncTask 上调用 get() 来阻塞 UI 线程,所以 onPreExecute() 和 onPostExecute() 不能在 UI 线程上运行!它们被发布到主线程,但它们只有在主线程完成它正在做的事情后才会运行。也就是说,在 get() 返回之后。然后会显示一个对话框并立即关闭,这就是你看不到它的原因。

    不要以这种方式等待结果。在 onPostExecute() 中处理结果,因为它就是为此目的而设计的。

    【讨论】:

      【解决方案2】:
      this is just a test, later I'll need this HashMap in the calling class for making a graph(fermate are the liefs). Can I retrieve it in another way? 
      

      marcin_j 已经回答了get() 部分。调用 get() 会阻塞 ui 线程,使其不再异步。

      是的,有办法。您可以使用接口作为活动的回调。

      黑带检查答案

      How do I return a boolean from AsyncTask?

      在你的情况下,而不是布尔它的 HashMap。

      你也可以让你的 Asynctask 成为一个活动的内部类

      【讨论】:

      • 我决定不做内部活动,因为我需要 3 个或更多的 AsynkTask。在问题中,它会将结果传递给接口,但我会将这些数据发送到 Graph 类,因为我还会发送 Edges 并且该类会很大。如何从接口将其发送到其他类?
      • @giacomotb 不,您将数据从 asynctask 获取到活动类。一旦你在活动类中获得数据,决定做任何你想做的事情
      • 但是我只能在接口的方法上使用它们,还是我错了?
      • @giacomotb 如果你在实现的方法中得到一个字符串。您可以将String s 声明为实例变量,然后在实现的方法中对其进行初始化。然后你可以在其他地方使用s。我希望我明白这就是你所需要的
      • @giacomotb 你想要实现的接口方法之外的数据对吗?
      猜你喜欢
      • 2017-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 1970-01-01
      • 1970-01-01
      • 2016-02-20
      • 1970-01-01
      相关资源
      最近更新 更多