0

I am working on an app that fetches youtube videos from two channels using the v3 api. I fire two queries: one to get a list of videos & the other to get a list of the video details (duration and views). Im doing these using an asynctask but the task does not complete at first attempt. I have to exit the app and then re-open before the list is displayed. Can anyone tell me why this might be happening and if there is anything wrong with the way I have implemented the asynctask? Below is my code for the 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();

    }
}

Below is the layout code. Its part of the youtube api demo and implements fragments.

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

}

Sid M
  • 130
  • 3
  • 15
  • " task does not complete at first attempt"??? You mean doInBackground() is not completing its task completely? And why you have commented "onPostExecute()" method? – Faizan Mubasher Jan 23 '14 at 05:11
  • @Faizan: Yes my asynctask does not complete. I have to exit the app and then open it again before i can see the list. onPostExecute that is commented is not used and I have removed the same.. The actual onPostExecute is written way above – Sid M Jan 23 '14 at 05:15
  • how u can say its not complete – Sush Jan 23 '14 at 05:15
  • I think by not complete he means the `ProgressDialog` never dismisses itself as `onPostExecute()` is commented. – CodeWarrior Jan 23 '14 at 05:17
  • @AndroidWarrior: onPostExecute() is not commented. It is very much there and in use doing the bulk of the task in fact and progress dialog has also been dismissed. – Sid M Jan 23 '14 at 05:23
  • you can't get `JsonObject` in `onPostExecute`, you must get that in `doInBackground`. this implement cause `android.os.NetworkOnMainThreadException`, for more info see my question ( http://stackoverflow.com/questions/20343548/android-os-networkonmainthreadexception-in-asynktask-class ) – Shayan Pourvatan Jan 23 '14 at 05:25
  • why you are making http request again n again, just need once in doInbackground. – Vijju Jan 23 '14 at 05:59
  • I have moved all network requests to doInBackground() now onPostExecute() is used only to dismiss progress dialog and render layout. The list still does not load the videos on first attempt and on re-opening the app sometime force closes. – Sid M Jan 23 '14 at 13:03

4 Answers4

2

I think all your http calls should be inside doInBackground() Method.Your making calls in ui thread by making putting them in postExecute() Method. So your thinking that your async task is not getting completed. Actually async task on its completion calls a callback postExecute(). For you its getting called and again in postExecute() your making http calls. Hope your clear.

Sush
  • 3,864
  • 2
  • 17
  • 35
  • I moved all http calls to doInBackground() but the problem still persists. onPostExecute() is used to dismiss pDialog only. Posted the new code above. – Sid M Jan 23 '14 at 13:06
  • @SidM is the dialog getting dissmissed. one more ur putting try catch blocks. check ur log cat is there any is issue with json parsing. i mean json exception is getting thrown or wt ? – Sush Jan 23 '14 at 13:08
  • Yes the pDialog is getting dismissed but the layout is not getting rendered so i am left with a black screen and no data. Incidentally the network seems to get utilized long after the dialog is dismissed (20-30 secs). No issues with JSON parsing are thrown. Just the layout is not getting rendered. – Sid M Jan 23 '14 at 13:17
  • Is it possible to implement progress dialog without use of asynctask? – Sid M Jan 23 '14 at 15:07
  • Id like to give that a go too if possible.. any help or resources would be great :) – Sid M Jan 24 '14 at 05:59
  • try two buttons.. one will show up the dialog box and one will dissmiss it – Sush Jan 24 '14 at 06:28
  • Incidentally while parsing urlvideos1 on emulator the app hangs and i get many such messages in my logcat "Skipped 51 frames! The application may be doing too much work on its main thread." – Sid M Jan 24 '14 at 07:57
  • Any idea how one can spped up the network operations? – Sid M Jan 24 '14 at 09:30
  • Thanks for the resource. I did go through some of them and have found my implementation is not too far off from the approaches described. I think the main issue is that I need to make multiple httpcalls. I have implemented asynctasks with single httpcall in the past and they work as desired. This time however it seems to display the progressdialog for some time and then nothing.. I then need to re-open the app to see the content. I even tried creating separate asynctasks for each httpcall but to no avail.. – Sid M Jan 25 '14 at 04:50
  • Robospice sounds interesting will give that a go. – Sid M Jan 25 '14 at 05:02
0

All the bulk of the task must be done in doInBackground() as it's done on a separate thread whereas onpostExecute() runs on the main thread. Do all the heavy work indoInBackground() and return whatever is required to update your UI from here itself and update your UI from onPostExecute()()

CodeWarrior
  • 5,026
  • 6
  • 30
  • 46
0

add this method coz when asynk task complete then thz method call at the last so u have to dismiss your dailog here

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

           pDialog.dismiss();

    }
Bhanu Sharma
  • 5,135
  • 2
  • 24
  • 49
  • should i dismiss pDialog at the start of onPostExecute() or at the end after all the tasks are completed? – Sid M Jan 23 '14 at 05:21
  • At the start should be fine. onPostExecute() is used to update the UI. So, you dismiss pDialog and display content on the UI. – android_dev_ Jan 23 '14 at 05:25
  • onpost() is automatically call after all process had been done so don't worry about thz dude in on post we just update our UI – Bhanu Sharma Jan 23 '14 at 07:16
0

do like that:

in post execute:

  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
}
}

There is not need to again and again calling url

Ravind Maurya
  • 977
  • 15
  • 24
  • 2
    you can't get `JsonObject` in `onPostExecute`, you must get that in `doInBackground`. this implement cause `networkExceptionOnUiThread` – Shayan Pourvatan Jan 23 '14 at 05:17
  • Can I make multiple http calls within the same doInBackground() and return all results in single JSONArray to onPostExecute()? – Sid M Jan 23 '14 at 05:44
  • @SidM to read, you have to get InputStream from response. and data to the stream comes from Network. thus reading involves in network operation – Shayan Pourvatan Jan 23 '14 at 05:52