简体   繁体   中英

Can't get custom list adapter to populate listview using asynctask

I'm trying to populate an ArrayList of objects and use those objects to populate a ListView. My Asynctask can get the json data and I can parse it and make the objects I need but my ListView doesn't populate. When I check to see if my ArrayList has any object in it before the adapter runs I can see that it doesn't. I want to know why my ListView isn't populating.

Here's my code: (Sorry if it's messy, some spots I haven't gotten to updating yet)

public class MovieDisplayFragment extends Fragment{

private ArrayList<Movie> movieList = new ArrayList<Movie>();
private MovieAdapter movieAdapter;
ListView listView;

public MovieDisplayFragment(){
}

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
    View rootView = inflater.inflate(R.layout.fragment_main, container, false);

    movieAdapter = new MovieAdapter(getActivity(), movieList);
    listView = (ListView) rootView.findViewById(R.id.listview_data);
    listView.setAdapter(movieAdapter);

    if(movieList.size() > 0) {
        Log.e("Hello", "1");
    }

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int position, long l){
            Movie movie = movieAdapter.getItem(position);
            Intent i = new Intent(getActivity(), DetailActivity.class)
                    .putExtra(Intent.EXTRA_TEXT, "Hello");
            startActivity(i);
        }
    });

    return rootView;
}

private void updateMovieData(){
    getMovieData movieData = new getMovieData();
    movieData.execute();
}

@Override
public void onStart(){
    super.onStart();
    updateMovieData();
}

public class getMovieData extends AsyncTask<Void, Void, List<Movie>> {

    private final String LOG_CAT = getMovieData.class.getSimpleName();

    private List<Movie> getMovieData(String movieJsonStr) throws JSONException {

        final String MOV_ITEMS = "results";
        final String MOV_TITLE = "original_title";
        final String MOV_DATE = "release_date";
        final String MOV_SYNOPSIS = "overview";
        final String MOV_VOTE = "vote_average";
        final String MOV_POSTER_URL = "poster_path";

        JSONObject movieJson = new JSONObject(movieJsonStr);
        JSONArray movieArray = movieJson.getJSONArray(MOV_ITEMS);

        Log.e("Hello", "2");

        for (int i = 0; i < movieArray.length(); i++) {

            JSONObject movie = movieArray.getJSONObject(i);

            movieList.add(new Movie(movie.getString(MOV_TITLE), movie.getString(MOV_DATE),
                    movie.getString(MOV_SYNOPSIS), movie.getString(MOV_VOTE), movie.getString(MOV_POSTER_URL)));

        }

        return movieList;
    }

    protected List<Movie> doInBackground(Void... params) {

        HttpURLConnection urlConnection = null;
        BufferedReader reader = null;

        String movieJsonStr = null;

        try {

            final String BASE_URL = "http://api.themoviedb.org/3/genre/10751/movies?api_key=358f3b44734f7e6404f2d01a62d3c176&include_all_movies=true&include_adult=true";
            Uri builtUri = Uri.parse(BASE_URL).buildUpon().build();
            URL url = new URL(builtUri.toString());

            Log.v(LOG_CAT, "Built URI " + builtUri.toString());

            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            InputStream inputStream = urlConnection.getInputStream();
            StringBuffer buffer = new StringBuffer();
            if (inputStream == null){
                movieJsonStr = null;
            }
            reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            while((line = reader.readLine()) != null){
                buffer.append(line + "\n");
            }

            if (buffer.length() == 0){
                movieJsonStr = buffer.toString();
            }
            movieJsonStr = buffer.toString();

            Log.v(LOG_CAT, "Movie String: " + movieJsonStr);
        } catch (IOException e) {
            Log.e("Fragment", "Error", e);
            movieJsonStr = null;

        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (final IOException e) {
                    Log.e("PlaceholderFragment", "Error closing stream", e);
                }
            }
        }

        try {
            return getMovieData(movieJsonStr);
        } catch (JSONException e) {
            Log.e(LOG_CAT, e.getMessage(), e);
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(List<Movie> movies){
        if(movies != null){
            movieAdapter.clear();
            for(Movie movieData : movies){
                movieAdapter.add(movieData);
            }
        }
    }
}

}

Put these 2 lines inside your onPostExecute() in Async.

movieAdapter = new MovieAdapter(getActivity(), movieList);
listView.setAdapter(movieAdapter);

AsyncTask runs in Background Thread. It gets the data from json after few seconds. But your adapter is called few milli seconds after your fragment is created.

So the data from the Json will not be there when you are setting the adapter.

Calling it in onPostExecute solves this problem as the adatpter is set after Json data is retrieved from the server!

Hope it helps a bit.

It looks like on post execute you are clearing the List that your adapter is using to populate the listview, then adding in new items to the list. However, in order to update the view after that happens, you need to call notifyDataSetChanged(); after updating the list

@Override
protected void onPostExecute(List<Movie> movies){
    if(movies != null){
        movieAdapter.clear();
        for(Movie movieData : movies){
            movieAdapter.add(movieData);
        }
        movieAdapter.notifyDataSetChanged();
    }
}

You are printing size of movieList (movieList.size()) much before movieList() is getting populated. It will never print "Hello" "1" in debugger. The asynctask will fill data in movieList much later than your movieList.size() check code in OnCreateView()

Anyways, after the below code

for(Movie movieData : movies)
{
   movieAdapter.add(movieData);
}

you need to insert this bit:

listView.setAdapter(movieAdapter);

You are populating the adapter but not setting it to your listView in your onPostExecute() in your getMovieData Asynctask.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM