【问题标题】:ProgressDialog doesn't show up in AsyncTaskProgressDialog 没有出现在 AsyncTask 中
【发布时间】:2013-11-06 13:26:08
【问题描述】:

我正在创建一个依赖于应用程序从数据库中获取的数据的安卓应用程序。为了获取这些数据,我有以下类(此类从数据库中以 JSON 格式获取数据,翻译并返回):

public class Json {
    public String jsonResult;

    private Activity activity;
    private String url = "http://json.example.org/json.php";
    private String db, query;

    public Json(Activity activity) {
            this.activity = activity;
        }

    public String accessWebService(String db, String query) {
        JsonReadTask task = new JsonReadTask();

        this.db = db;
        this.query = query;

        task.execute(new String[] { url });

        try {
            task.get();
        } catch (InterruptedException e) {
            Toast.makeText(activity.getApplicationContext(), "FATAL ERROR: The thread got interrupted",
                    Toast.LENGTH_LONG).show();
        } catch (ExecutionException e) {
            Toast.makeText(activity.getApplicationContext(), "FATAL ERROR: The thread wasn't able to execute",
                    Toast.LENGTH_LONG).show();
        }
        return jsonResult;
    }

    // Async Task to access the web
    private class JsonReadTask extends AsyncTask<String, Void, String> {

        private final ProgressDialog dialog = new ProgressDialog(activity);

        protected String doInBackground(String... params) {
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost(params[0]);
            try {
                // add post data
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
                nameValuePairs.add(new BasicNameValuePair("db", db));
                nameValuePairs.add(new BasicNameValuePair("query", query));
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                HttpResponse response = httpclient.execute(httppost);
                jsonResult = inputStreamToString(response.getEntity().getContent()).toString();
                if (jsonResult.isEmpty()) {
                    Toast.makeText(activity.getApplicationContext(),
                            "Error, connection is up but didn't receive data. That's strange...", Toast.LENGTH_LONG)
                            .show();
                    this.cancel(true);
                }

            } catch (ClientProtocolException e) {
                // Toast.makeText(activity.getApplicationContext(),
                // "Error, Client Protocol Exception in JSON task",
                // Toast.LENGTH_LONG).show();
                Log.i("Json", "Error, Client Protocol Exception in JSON task");
                this.cancel(true);
            } catch (IOException e) {
                // Toast.makeText(activity.getApplicationContext(),
                // "Error, Please check your internet connection",
                // Toast.LENGTH_LONG).show();
                Log.i("Json", "Error, Please check your internet connection");
                this.cancel(true);
            }
            return null;
        }

        private StringBuilder inputStreamToString(InputStream is) {
            String rLine = "";
            StringBuilder answer = new StringBuilder();
            BufferedReader rd = new BufferedReader(new InputStreamReader(is));

            try {
                while ((rLine = rd.readLine()) != null) {
                    answer.append(rLine);
                }
            } catch (IOException e) {
                Toast.makeText(activity.getApplicationContext(), "Error..." + e.toString(), Toast.LENGTH_LONG).show();
            }
            return answer;
        }
    }// end async task
}

我注意到我的应用程序在访问数据库时冻结。经过一番谷歌搜索,我发现这是 accessWebService() 方法中的 .get() 方法造成的。我尝试像这样实现progressDialog(我还删除了.get() 方法):

private final ProgressDialog dialog = new ProgressDialog(activity);

protected void onPreExecute() {
    super.onPreExecute();
    this.dialog.setMessage("Loading...");
    this.dialog.setCancelable(false);
    this.dialog.show();
}

protected void onPostExecute(String result) {
    if (this.dialog.isShowing()) {
        this.dialog.dismiss();
    }
}

但对话框没有出现,我得到了NullPointerException,因为该应用程序仅在有数据时才有效:

result = json.accessWebService(db, query);

(也许要提一个重要的事情:我也在for循环中使用这种方法)

所以现在我的问题是:如何更改我的应用程序,以便在访问数据库时获得 ProgressDialog 而不会获得NullPointerException?我担心我必须重新构建我的整个应用程序,如果我必须这样做,我该怎么做?我希望你们能理解我的问题并解决这个问题,因为我真的需要帮助。提前致谢。

附:对不起,如果我的英语不是那么好,我不是母语人士。

【问题讨论】:

    标签: android android-asynctask progressdialog


    【解决方案1】:

    ... 我发现是 accessWebService() 方法中的 .get() 方法导致了这种情况。我试图实现一个progressDialog...

    没错。 get() 是一个阻塞调用,简单地添加一个ProgressDialog 不会解决它。您需要删除.get(),这可能会解决您的ProgressDialog 未显示的问题。

    AsyncTask 必须在主 Thread 上执行,因此请确保您正在这样做。

    您遇到的另一个问题是Toast.LENGTH_LONG).show();UI 上运行,而您在doInBackground() 中运行它是不可能发生的。您需要将result 发送到onPostExecute(),如果需要,您可以在那里显示您的Toast。这也可以在onProgressUpdate() 中完成。

    【讨论】:

    • 是的,很抱歉我没有在我的问题中提到它,但我确实删除了 .get() 方法。关于第二件事(吐司),不幸的是,这也无济于事。 (这不是问题,因为只有在出现错误时才进行敬酒)
    • 如果您需要在任务完成后得到响应并执行某些操作,您可以see this SO answer 了解如何使用interface
    • 这可能很有用,但我有一个问题。我使用 json.accessWebService(db, query);在一个班级中多次,每次获得不同的数据。我也在 forloops 中使用该方法。考虑到这一点,我将如何使用这种机制?
    • @Quitlox 我必须看看你在做什么才能确定,但​​也许这对你不起作用。如果您需要在任务完成而不是使用.get() 时发生一些事情,这很好,因为它不会阻止UI。您只需将interface 添加到您的Activity 中,然后在onPostExecute() 中调用它,以便它可以返回数据或一些响应,以便Activity 可以在需要时采取适当的措施。
    • 实际上,也许我可以使用它。我必须在我的代码中进行很多更改,但我也许它会起作用。感谢您的努力。
    【解决方案2】:

    这个空指针异常发生是因为result 值为空。把条件放在前面

    if(result != null ) {
    
       // CODE FOR PARSING 
    } else {
    
       return;
    }
    

    【讨论】:

    • 是的,但如果我这样做,应用程序将无法继续,因为它没有数据。
    • 如果你在 else 块中使用 return 它将继续,现在看看我更新的答案。
    • tnx 用于回答,事实上,如果我这样做,我会看到加载对话框并且应用程序不会崩溃。但由于它只检查一次结果(当它为空时,它会过早地检查它,因为此时 AsyncTask 还没有准备好),所以结果为空。所以应用程序不能做任何事情,因为它需要数据。有什么建议吗?
    【解决方案3】:

    您可以在 asyncTask 启动之前开始显示进度条,并在 asyncTask 完成时结束显示。

    将处理程序传递给 asyncTask 和 sendMessage onPostExecute 方法。然后在 UI 线程上处理消息并隐藏进度条

    例如在 UI (mainActivity) 中有处理程序字段。在那里你应该处理隐藏进度条:

    public Handler refreshChannelsHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EPGManager.ERROR_MESSAGE:
                    //do some stuff
                    break;
                case EPGManager.SUCCESS_MESSAGE:
                    //do some stuff
                    break;
            }
            super.handleMessage(msg);
        }
    };
    

    然后你可以用你的处理程序调用 asyncTask

    epgManager.loadChannels(refreshChannelsHandler);
    

    AsyncTask 在方法内部,所以它看起来像这样:

    public void loadChannels(Handler handler) {
        AsyncTask task = new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] params) {
                try {
                    //do AsyncTask Job
                } catch (Exception e) {
                    return new LoadingResult((Handler) params[0], false);
                }
                return new LoadingResult((Handler) params[0], false);
            }
    
            @Override
            protected void onPostExecute(Object o) {
                super.onPostExecute(o);
                LoadingResult loadingResult = ((LoadingResult)o);
                sendMessageToHandler(loadingResult.handler, loadingResult.isSuccess);              
            }
        };
        task.execute(handler);
    }
    

    方法如下:

    private void sendMessageToHandler(Handler handler, boolean isSuccess) {
        handler.sendEmptyMessage(isSuccess ? SUCCESS_MESSAGE : ERROR_MESSAGE);
    }
    

    最后是内部类

    private class LoadingResult {
        private Handler handler;
        private boolean isSuccess;
    
        public LoadingResult(Handler handler, boolean isSuccess) {
    
            this.handler = handler;
            this.isSuccess = isSuccess;
        }
    
        public Handler getHandler() {
            return handler;
        }
    
        public void setHandler(Handler handler) {
            this.handler = handler;
        }
    
        public boolean isSuccess() {
            return isSuccess;
        }
    
        public void setSuccess(boolean isSuccess) {
            this.isSuccess = isSuccess;
        }
    }
    

    哦,别忘了常量

    public static final int SUCCESS_MESSAGE = 1;
    public static final int ERROR_MESSAGE = -1;
    

    希望对你有帮助:)

    【讨论】:

    • 在这里使用Handler 有什么意义? AsyncTask 已经有在UI 上运行的方法(除了doInBackground()
    • 好吧,在我的情况下,项目结构和 UI 位于不同的包中。所有 asyncTask 都在 Engine 包中,无法访问 UI 包。只有 UI 包可以调用 Engine 包方法,因此传递一个 Handler 可以帮助我以干净合法的方式获得已完成 AsyncTask 的答案,并且仍然拥有我的项目结构:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多