【问题标题】:Android RecyclerView custom OnItemClickListener crashesAndroid RecyclerView 自定义 OnItemClickListener 崩溃
【发布时间】:2017-10-09 15:31:56
【问题描述】:

您好,我正在尝试为我的 RecyclerView 设置一个 onclicklistener,但是当我点击 RecyclerView 中的名称并显示错误代码时它崩溃了:

java.lang.NullPointerException:尝试调用接口方法 '空白 com.motivecodex.githubusers.adapter.RepositoryAdapter$OnItemClickListener.onItemClick(com.motivecodex.githubusers.database.table.Repository)' 在空对象引用上 在 com.motivecodex.githubusers.adapter.RepositoryAdapter$ViewHolder$1.onClick(RepositoryAdapter.java:52)

RepositoryAdapter.java

public class RepositoryAdapter extends RecyclerView.Adapter<RepositoryAdapter.ViewHolder> {

    private static final String LOG_TAG = "RepositoryAdapter";

    public interface OnItemClickListener {
        void onItemClick(Repository repository);
    }

    private List<Repository> repositories;

    private final OnItemClickListener listener;

    public RepositoryAdapter(List<Repository> repositories, OnItemClickListener listener) {
        this.repositories = repositories;
        this.listener = listener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.listitem_repository, parent, false);

        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.bind(repositories.get(position), listener);
//        Repository githubRepository = repositories.get(position);
//        holder.name.setText(githubRepository.getName());
//        holder.stars.setText(String.valueOf(githubRepository.getStargazersCount()));
//        holder.forks.setText(String.valueOf(githubRepository.getForksCount()));
    }

    @Override
    public int getItemCount() {
        if (repositories != null) {
            return repositories.size();
        }
        return 0;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        private TextView name, stars, forks;

        public ViewHolder(View view) {
            super(view);
            name = (TextView) view.findViewById(R.id.listitem_name);
            stars = (TextView) view.findViewById(R.id.listitem_stars);
            forks = (TextView) view.findViewById(R.id.listitem_forks);
        }

        public void bind(final Repository repository, final OnItemClickListener listener) {
            name.setText(repository.getName());
            stars.setText(String.valueOf(repository.getStargazersCount()));
            forks.setText(String.valueOf(repository.getForksCount()));
            name.setOnClickListener(new View.OnClickListener() {
                @Override public void onClick(View v) {
                    listener.onItemClick(repository);
                    Log.e(LOG_TAG, "Item clicked");
                }
            });
        }
    }
}

MainActivity.java

    mGithubRecyclerView = (RecyclerView) findViewById(R.id.github_repository_recyclerview);
            RecyclerView.LayoutManager mGithubLayoutManager = new LinearLayoutManager(getApplicationContext());
            mGithubRecyclerView.setLayoutManager(mGithubLayoutManager);
            mGithubRecyclerView.setHasFixedSize(true);

....

public void loadRepository(String username) {
        mGithubApi.listRepository(username).enqueue(new Callback<List<Repository>>() {
            @Override
            public void onResponse(Call<List<Repository>> call, Response<List<Repository>> response) {
                mGithubAdapter = new RepositoryAdapter(response.body(), MainActivity.java);
                mGithubRecyclerView.setAdapter(mGithubAdapter);
            }

            @Override
            public void onFailure(Call<List<Repository>> call, Throwable t) {
                Log.e("MainActivity", "error loading from API");
            }
        });
    }

@Override
    public void onItemClick(Repository repository) {
        Log.e(LOG_TAG, "Item clicked");
    }

【问题讨论】:

    标签: java android android-recyclerview onclicklistener


    【解决方案1】:

    listener.onItemClick(repository); 是错误的。您传递给 Adapter 的侦听器为 null。

    您是否从具有 RecyclerView 的 Activity/Fragment 正确初始化它?

    所以,如果你有一个 Activity,它应该是这样的:

    public class MyActivity extends AppCompatActivity implements RepositoryAdapter.OnItemClickListener {
    
    
         // lots of activity methods
    
    
         // called from adapter
         public void onItemClick () {
    
         }
    }
    

    然后,像这样将它传递给您的适配器,

    // 'this' is your listener
    RepositoryAdapter adapter = new RepoitoryAdapter(context, this);
    

    【讨论】:

      【解决方案2】:

      我会在onBindViewHolder 中使用setOnClickListner。对于onClickListner,您真的不需要RecyclerView 中的接口。 您可以传递一个 Intent 来处理 onClickListner 事件,例如:

      @Override
              public void onBindViewHolder(PosterViewHolder holder, final int position) {
      // Here pass whatever value you need on the current screen
                  final Movies movies = movieItems.get(position);
                  String posterUrlPath = movies.getPosterPath();
      
                  Picasso.with(context)
                          .load(Constants.MOVIE_POSTER_URL + posterUrlPath)
                          .placeholder(R.drawable.ic_movies_poster_placeholder)
                          .error(R.drawable.ic_picasso_error)
                          .into(holder.poster);
          // Here is where you get the intent for every properties you need
                  holder.itemView.setOnClickListener(new View.OnClickListener() {
                      @Override
                      public void onClick(View view) {
                          Intent intent = new Intent(context, MovieDetailsActivity.class);
                          intent.putExtra(Constants.MOVIE_POSTER, movies.getPosterPath());
                          intent.putExtra(Constants.MOVIE_BACKDROP, movies.getBackdropPath());
                          intent.putExtra(Constants.MOVIE_TITLE, movies.getTitle());
                          intent.putExtra(Constants.MOVIE_OVERVIEW, movies.getOverview());
                          intent.putExtra(Constants.MOVIE_RELEASE_DATE, movies.getReleaseDate());
                          intent.putExtra(Constants.MOVIE_RATINGS, movies.getVoteAverage());
                          context.startActivity(intent);
                      }
                  });
              }
      

      最后,不要忘记通知任何已注册的观察者数据集已更改。

      public void setRepositories(List<Repository> repo) {
          repositories.clear();
          movieItems = repo;
          notifyDataSetChanged();
      }
      

      在一个activity或fragment中,你可以如下调用set movies:

      adapter.setMovies(movieItems);
      

      ViewHolder类中分配对象:

      public class ViewHolder extends RecyclerView.ViewHolder {
      
              ImageView poster;
      
              public PosterViewHolder(View itemView) {
                  super(itemView);
                  poster = (ImageView) itemView.findViewById(R.id.popular_movies_poster_iv);
              }
      
          }
      

      希望这会有所帮助!

      【讨论】:

      • 不要在onBindViewHolder内分配任何对象,而是在ViewHolder类内设置监听器
      • 就像 pskink 说的,你可以在ViewHolder 里面做View.setOnClickListner。请问为什么不分配对象onBindViewHolder。我们可以对此进行辩论,但很高兴解释为什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      • 2016-05-21
      • 2011-10-24
      • 2018-06-27
      • 1970-01-01
      相关资源
      最近更新 更多