0

我正在尝试使用 ListFragment 创建电影列表(按照本教程)。在片段中,我有一个加载器和一个从 Web 服务下载信息的 AsyncTaskLoader。AsyncTaskLoader 正确下载了所有信息,并且正确执行了“onLoadFinished”方法。在 onLoadFinished 中,我调用 listadapter 中的一个函数来设置新数据,然后调用 notifyDataSetChanged()。我知道适配器中的数据设置正确(日志语句将打印适配器类中第一部电影的标题),但列表视图不会显示任何内容。但是,如果我向适配器的构造函数提供电影列表,它就可以工作。

ListFragment 的代码(不是所有代码,只有设置适配器、加载器等的代码):

public class MovieListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<MovieInformation>>{

  public static final String TAG = "MovieListFragment";
  private SimpleMovieListAdapter listAdapter;

  public MovieListFragment() {
  }

  @Override public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    System.out.println("DataListFragment.onActivityCreated");

    setEmptyText("No results");
    listAdapter = new SimpleMovieListAdapter(getActivity(), R.layout.movie_list_row_layout);
    setListAdapter(listAdapter);
    setListShown(false);
    getLoaderManager().initLoader(0, null, this);
}

装载机:

public Loader<List<MovieInformation>> onCreateLoader(int arg0, Bundle arg1) {
    Log.d(TAG, "onCreateLoader");
    return new MovieListDownloader(getActivity());
}

@Override
public void onLoadFinished(Loader<List<MovieInformation>> arg0,
        List<MovieInformation> data) {
    listAdapter.setData(data);
    Log.d(TAG, "onLoadFinished");
    Log.d(TAG, ("length is: " + data.size()));
    setListShown(true);
    /*
    if(data != null && !data.isEmpty()){
        setListShown(true);
    }else{
        setListShownNoAnimation(true);
    }
    */
}

@Override
public void onLoaderReset(Loader<List<MovieInformation>> arg0) {
    Log.d(TAG, "onLoaderReset");
    listAdapter.setData(null);
}

适配器:

public class SimpleMovieListAdapter extends ArrayAdapter<MovieInformation> {
  private static final String TAG = "SimpleMovieListAdapter";
  private Context context;
  private List<MovieInformation> movies;
  ImageLoader imageLoader;

  public SimpleMovieListAdapter(Context context, int textViewResourceId,
        List<MovieInformation> objects) {
      super(context, textViewResourceId, objects);
      this.context = context;
      this.movies = objects;
      imageLoader =  ImageLoader.getInstance();

  }
  public SimpleMovieListAdapter(Context context, int textViewResourceId){
      super(context, textViewResourceId);
      this.context = context;
      imageLoader =  ImageLoader.getInstance();
  }

  public void setData(List<MovieInformation> movies){
      this.movies = movies;

      //This log statement will display the title of the first movie in the set (so the list of movies is updated correctly)
      Log.d(TAG, this.movies.get(0).getTitle());
      notifyDataSetChanged();
  }

  public View getView(int position, View convertView, ViewGroup parent){
    Log.d(TAG, ("GetView position" + position));
    View rowView;
    LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if(convertView == null){
        rowView = inflater.inflate(R.layout.movie_list_row_layout, parent, false);
    } else {
        rowView = convertView;
    }

    TextView titleText = (TextView) rowView.findViewById(R.id.movie_list_title);
    TextView yearText = (TextView) rowView.findViewById(R.id.movie_list_year);
    TextView voteAverageText = (TextView) rowView.findViewById(R.id.movie_list_vote_average);
    ImageView posterView = (ImageView) rowView.findViewById(R.id.movie_list_poster);
    titleText.setText(movies.get(position).getTitle());
    yearText.setText("(" + movies.get(position).getYear() + ")");
    voteAverageText.setText(movies.get(position).getFormattedRatingAndVoteCount() + " " + 
            context.getString(R.string.movie_info_votes) + ")");


    imageLoader.displayImage((MyApplication.POSTER_SOURCE_ADDRESS + 
            movies.get(position).getPosterPath()), posterView, MyApplication.options);

    return rowView;
}
}

编辑 1 我在发布问题后立即找到了解决方案,但我认为这不是一个“好”的解决方案。在 onLoadFinished 中,我没有将数据传递给 adapter.setData(),而是简单地创建了一个新适配器(将电影数组传递给构造函数),然后再次调用 setListAdapter()。它可以工作,但感觉像是一个丑陋的解决方案(创建和设置新适配器可能会消耗更多资源?)。

编辑 2 只是为了澄清适配器类中关于 setData 的一些事情:将所有数据添加到数组(this.movi​​es)后,我循环遍历整个数组并使用日志语句打印每部电影的标题。所以数据在调用setData后存储在adapterclass中的arraylist中,但是listview仍然没有填充数据。

public void setData(List<MovieInformation> movies){
         this.movies = movies;

    if(movies != null){
        this.movies.addAll(movies);

    }
    for(MovieInformation m : this.movies){
        Log.d(TAG, ("movie : " + this.movies.indexOf(m) + " " + this.movies.get(this.movies.indexOf(m)).getTitle()));
    }
    notifyDataSetChanged();
}
4

1 回答 1

0

尝试这个:

而不是做

  public void setData(List<MovieInformation> movies){
      this.movies = movies;

      //This log statement will display the title of the first movie in the set (so the list of movies is updated correctly)
      Log.d(TAG, this.movies.get(0).getTitle());
      notifyDataSetChanged();
  }

更改此行 this.movies = movies;

this.movies.clear(); 
if(movies!=null){

this.movies.addAll(movies); }

notifyDataSetChanged();

编辑

当您创建列表视图时,您正在使用此构造函数:

  public SimpleMovieListAdapter(Context context, int textViewResourceId){
  super(context, textViewResourceId);
  this.context = context;
  imageLoader =  ImageLoader.getInstance();

}

您没有创建数据列表的新实例,请尝试添加以下行:this.movies = new ArrayList<MovieInformation>();

并添加另一个修复程序,它应该可以工作

编辑 #2 更改您的适配器以扩展基本适配器,更改您的构造函数,如下所示:

并相应地更新您创建新适配器的行

public class SimpleMovieListAdapter extends BaseAdapter {
  private static final String TAG = "SimpleMovieListAdapter";
  private Context context;
  private List<MovieInformation> movies;
  ImageLoader imageLoader;

  public SimpleMovieListAdapter(Context context, List<MovieInformation> objects) {
      this.context = context;
      this.movies = objects;
      imageLoader =  ImageLoader.getInstance();

  }
  public SimpleMovieListAdapter(Context context){
      this.context = context;
      this.movies = new ArrayList<MovieInformation>();
      imageLoader =  ImageLoader.getInstance();
  }
于 2013-09-20T21:54:15.620 回答