【问题标题】:Asynctask does not complete when making multiple httpcalls in doInBackground()在 doInBackground() 中进行多个 httpcall 时,Asynctask 未完成
【发布时间】:2014-01-25 12:47:03
【问题描述】:

我正在开发一个使用 v3 api 从两个频道获取 youtube 视频的应用程序。我发出两个查询:一个是获取视频列表,另一个是获取视频详细信息(持续时间和观看次数)列表。我使用 asynctask 执行这些操作,但该任务在第一次尝试时未完成。我必须退出应用程序,然后在显示列表之前重新打开。谁能告诉我为什么会发生这种情况以及我实现异步任务的方式是否有任何问题?下面是我的异步任务代码。

    private class Fetchlist extends AsyncTask<String, String, JSONArray> {
    private ProgressDialog pDialog;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(VideoListDemoActivity.this);
        pDialog.setMessage("Getting Data ...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(true);
        pDialog.show();

    }

    @Override
    protected JSONArray doInBackground(String... params) {
        JSONArray jsonArray1 = null;
        JSONArray jsonArray2 = null;
        JSONArray jsonArrayFinal = null;
        try {

            String urlvideos1 = "https://www.googleapis.com/youtube/v3/search?key=xyz&channelId=abc&part=snippet&order=viewCount&maxResults=20";
            String urlvideos2 = "https://www.googleapis.com/youtube/v3/search?key=xyz2&channelId=abc2&part=snippet&order=viewCount&maxResults=20";
            JSONParser jParser = new JSONParser();
            JSONObject jsonVideos1 = jParser.getJSONFromUrl(urlvideos1);
            JSONObject jsonVideos2 = jParser.getJSONFromUrl(urlvideos2);

            jsonArray1 = jsonVideos1.getJSONArray("items");
            jsonArray2 = jsonVideos2.getJSONArray("items");

            jsonArrayFinal = concatArray(jsonArray1, jsonArray2);

            for (int i = 0; i < jsonArrayFinal.length(); i++) {
                JSONObject jsonID = jsonArrayFinal.getJSONObject(i);
                Log.d("Async Values", "inside do in background");
                try {
                    JSONObject jsonVid = jsonID.getJSONObject("id");
                    JSONObject jsonSnippet = jsonID
                            .getJSONObject("snippet");
                    String title = jsonSnippet.getString("title");
                    String videoid = jsonVid.getString("videoId");

                    try {
                        String urltwo = "https://www.googleapis.com/youtube/v3/videos?id="
                                + videoid
                                + "&key=xyz&part=snippet,contentDetails,statistics,status";
                        JSONParser jParsertwo = new JSONParser();
                        JSONObject jsontwo = jParsertwo
                                .getJSONFromUrl(urltwo);
                        // JSONObject jsonID = json.getJSONObject("items");
                        JSONArray jsonArraytwo = jsontwo
                                .getJSONArray("items");
                        JSONObject jsonIDtwo = jsonArraytwo
                                .getJSONObject(0);
                        JSONObject jsonView = jsonIDtwo
                                .getJSONObject("statistics");
                        JSONObject jsonDuration = jsonIDtwo
                                .getJSONObject("contentDetails");
                        String Duration = jsonDuration
                                .getString("duration");

                        String strDuration = Duration;
                        SimpleDateFormat df = new SimpleDateFormat(
                                "'PT'mm'M'ss'S'");
                        String youtubeDuration = Duration;
                        Date d = df.parse(youtubeDuration);
                        Calendar c = new GregorianCalendar();
                        c.setTime(d);
                        c.setTimeZone(TimeZone.getDefault());
                        int minduration = c.get(Calendar.MINUTE);
                        int secduration = c.get(Calendar.SECOND);
                        String strMin = String.valueOf(minduration);
                        String strSec = String.valueOf(secduration);

                        // Toast.makeText(VideoListDemoActivity.this,
                        // strMin, Toast.LENGTH_LONG).show();

                        String viewcount = jsonView.getString("viewCount");
                        // Toast.makeText(VideoListDemoActivity.this,
                        // viewcount, Toast.LENGTH_LONG).show();

                        title = jsonSnippet.getString("title")
                                + "\n\nViews: " + viewcount + " Length: "
                                + strMin + ":" + strSec;

                    } catch (JSONException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        Log.d("JSON msg", e.toString());
                    }

                    if (!list.contains(title)) {
                        list.add(new VideoEntry(title, videoid));
                    }

                }

                catch (Exception e) {
                    Log.d("Do in background", e.toString());
                }

            }

        } catch (Exception e) {
            Log.d("Do in background", e.toString());
        }

        return jsonArrayFinal;
    }

    protected void onPostExecute(JSONArray jsonArrayFinal) {
        pDialog.dismiss();
        layout();

    }
}

下面是布局代码。它是 youtube api 演示的一部分并实现了片段。

    private void layout() {
    boolean isPortrait = getResources().getConfiguration().orientation ==      Configuration.ORIENTATION_PORTRAIT;
listFragment.getView().setVisibility(
        isFullscreen ? View.GONE : View.VISIBLE);
listFragment.setLabelVisibility(isPortrait);
closeButton.setVisibility(isPortrait ? View.VISIBLE : View.GONE);

if (isFullscreen) {
    videoBox.setTranslationY(0); // Reset any translation that was
                                    // applied in portrait.
    setLayoutSize(videoFragment.getView(), MATCH_PARENT, MATCH_PARENT);
    setLayoutSizeAndGravity(videoBox, MATCH_PARENT, MATCH_PARENT,
            Gravity.TOP | Gravity.LEFT);
} else if (isPortrait) {
    setLayoutSize(listFragment.getView(), MATCH_PARENT, MATCH_PARENT);
    setLayoutSize(videoFragment.getView(), MATCH_PARENT, WRAP_CONTENT);
    setLayoutSizeAndGravity(videoBox, MATCH_PARENT, WRAP_CONTENT,
            Gravity.BOTTOM);
} else {
    videoBox.setTranslationY(0); // Reset any translation that was
                                    // applied in portrait.
    int screenWidth = dpToPx(getResources().getConfiguration().screenWidthDp);
    setLayoutSize(listFragment.getView(), screenWidth / 4, MATCH_PARENT);
    int videoWidth = screenWidth - screenWidth / 4
            - dpToPx(LANDSCAPE_VIDEO_PADDING_DP);
    setLayoutSize(videoFragment.getView(), videoWidth, WRAP_CONTENT);
    setLayoutSizeAndGravity(videoBox, videoWidth, WRAP_CONTENT,
            Gravity.RIGHT | Gravity.CENTER_VERTICAL);
}

}

【问题讨论】:

  • "第一次尝试未完成任务"???你的意思是 doInBackground() 没有完全完成它的任务?为什么你评论了“onPostExecute()”方法?
  • @Faizan:是的,我的异步任务没有完成。我必须退出应用程序,然后再次打开它才能看到列表。注释的 onPostExecute 未使用,我已将其删除。实际的 onPostExecute 写在上面
  • 你怎么能说它不完整
  • 我认为不完整是指ProgressDialog 永远不会在onPostExecute() 被评论时自行解散。
  • @AndroidWarrior: onPostExecute() 没有评论。实际上,它非常有用,并且正在使用中完成大部分任务,并且进度对话框也已被关闭。

标签: android android-asynctask


【解决方案1】:

我认为您所有的 http 调用都应该在 doInBackground() Method 中。您在 ui 线程中进行调用,方法是将它们放入 postExecute() Method 中。所以你认为你的async task 没有完成。实际上async task 在完成时会调用回调 postExecute()。对你来说,它会在postExecute() 中被调用并再次调用你的http 调用。 希望你清楚。

【讨论】:

  • 我将所有 http 调用移至 doInBackground() 但问题仍然存在。 onPostExecute() 仅用于关闭 pDialog。上面贴了新代码。
  • @SidM 是被解雇的对话框。再放一个 try catch 块。检查你的日志猫 json 解析是否有问题。我的意思是 json 异常被抛出或 wt ?
  • 是的,pDialog 被关闭,但布局没有被渲染,所以我只剩下黑屏并且没有数据。顺便说一句,网络似乎在对话结束后很长时间(20-30 秒)就被利用了。不会引发 JSON 解析问题。只是布局没有被渲染。
  • 不使用异步任务是否可以实现进度对话框?
  • 如果可能的话,我也想尝试一下。任何帮助或资源都会很棒:)
【解决方案2】:

在异步任务完成时添加此方法,然后在最后调用方法,因此您必须在此处关闭您的 dailog

   @Override
           protected void onPostExecute() {
            super.onPreExecute();

           pDialog.dismiss();

    }

【讨论】:

  • 我应该在 onPostExecute() 开始时还是在所有任务完成后结束 pDialog?
  • 一开始应该没问题。 onPostExecute() 用于更新 UI。因此,您关闭 pDialog 并在 UI 上显示内容。
  • onpost() 会在所有过程完成后自动调用,所以不要担心我们刚刚更新我们的 UI 的帖子
【解决方案3】:

这样做:

在后期执行中:

  protected void onPostExecute(JSONArray JSON)  {
           pDialog.dismiss();

      try{
for (int i=0; i<JSON.length(); i++)
            {
            JSONObject jsonID = JSON.getJSONObject(i);
// do what you want
}
}

没有必要反复调用url

【讨论】:

  • 您无法在onPostExecute 中获得JsonObject,您必须在doInBackground 中获得它。这个工具导致networkExceptionOnUiThread
  • 我可以在同一个 doInBackground() 中进行多个 http 调用,并将单个 JSONArray 中的所有结果返回到 onPostExecute() 吗?
  • @SidM 要读取,您必须从响应中获取 InputStream。流中的数据来自网络。因此阅读涉及网络操作
【解决方案4】:

所有大部分任务都必须在doInBackground() 中完成,因为它在单独的线程上完成,而onpostExecute() 在主线程上运行。在doInBackground() 中完成所有繁重的工作并返回从此处更新您的 UI 所需的任何内容,并从 onPostExecute()() 更新您的 UI

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 2015-11-29
    • 1970-01-01
    相关资源
    最近更新 更多