Vilcoyote
Vilcoyote

Reputation: 115

Waiting for asynchTask to finish

I'm doing my first android app. On one of the page, i need to connect to a Drupal site using REST services, retrieve some data (a list of videos url, their title, a description etc) and display it in a list. When i click on the list, i go to the details of the video.

Here is how i want to proceed. 1° Fetching all the data from the drupal site. 2° When clicking on an item of the list, passing the detail of that video to the next activity.

The problem is this: When connecting to the internet in android 3+, you can't do it on the main thread so i had to use AsyncTask to get the data. This worked, but then I want to save the videos in an ArrayList, and then access that list using either a getVideos() or getVideo(index) function. The first to populate the list, the second to retrieve data before going to the details activity. The problem is that the list is not yet populated when i try to access the list of videos.

Technically i don't really need/want to use the asynctask, but connecting to internet on the main thread throws an error saying it's not the proper way to do things.

Here is a simplified version on how i get the videos:

    public class VideoDaoImpl {
        private List<Video> videos ;

        public VideoDaoImpl (){
            videos = new ArrayList<Video>();
            new VideoTask(...).execute(); //fetch the videos in json format and 
            //call function onRemoteVideoCallComplete using a handler 
            //in the onPostExecute() function of the asyncTask
        }

        public List<Video> getVideos() {
            return videos;
        }

        public Video getVideo(int index){
            return videos.get(index);
        }

        public onRemoteVideoCallComplete(JSONObject json) {
            //transform Json into videos and add them to the videos arraylist
        }

    }

This is how i want to fill the video list in my activity:

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_videos_list);
        //get all videos (not yet filled since faster than second thread)
        List<Video> videos = videoDao.getVideos();
        //get a list of all the titles to display as the list
        List<String> formattedVideos = VideoHelper.formatVideosList(videos);

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, formattedVideos);

        ListView listView = (ListView) findViewById(R.id.videos_list);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new VideosListItemClickListener(this));
    }

So the question really is this. Is there a better way to to this, or is there a way to wait for the list to be filled.

Upvotes: 1

Views: 314

Answers (2)

marcbest
marcbest

Reputation: 1600

I would keep the AsyncTask as it is, however I would look into making use of the onPostExecute(). Inside the onPostExecute() I would convert your Json into a list of videos objects and then from this create the list of formatted videos. Then you could call a method passing the list of formatted videos back to your activity which will then set the list.

For example inside your async:

protected void onPostExecute(Json result) {
     //Create list of videos from json
     //Create formatted list
     //call method in activity to set list e.g activity.setList(formatted List)
 }

Upvotes: 2

Eduardo
Eduardo

Reputation: 4382

Using your approach makes the expected behavior be the one you are facing, i.e., the videos list is not yet filled. You are dealing with the problem using an assynchronous approach but thinking synchronously, and you know it, based on your comment "not yet filled since faster than second thread"

videoDao.getVideos();

should be called on your onPostExecute method, or after. I would do something like that, consider it a draft, not a complete solution.

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_videos_list);
    new VideoTask(...).execute(); // you should a use a something on your onPreExecute() inside this task showing a ProgressDialog so the user knows that something is "loading videos, please wait"

    List<Video> videos = videoDao.getVideos();
    if (!videos.isEmtpy()) {
      //get a list of all the titles to display as the list
      List<String> formattedVideos = VideoHelper.formatVideosList(videos);

      ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1, formattedVideos);

      ListView listView = (ListView) findViewById(R.id.videos_list);
      listView.setAdapter(adapter);
      listView.setOnItemClickListener(new VideosListItemClickListener(this));
    }
}

Basically what it shows as a difference is that you could extract your AsyncTask out of your VideoDAO. Execute it with a ProgressDialog to inform something is going, and then check if the videos list was filled. If it was, show the videos on your videos_list. Of course it is just a roughly made draft, but I think you can get the idea.

Upvotes: 0

Related Questions