0

I've implemented the recyclerView clicklistener using best practices yet it still isn't working. The recyclerview is loading data from the internet using retrofit and should take users to the site where the article was published below is my code:

NOTE: My RecyclerView is a RecyclerView of Cardviews

RecyclerView Adapter

    public class NewsArticleAdapter extends RecyclerView.Adapter<NewsArticleAdapter.Viewholder> {
    private ArrayList<Article> newsArticles = new ArrayList<>();
    private Context context;
    private OnArticleListener onArticleListener;

    public NewsArticleAdapter(List<Article> newsArticles, Context context, OnArticleListener onArticleListener) {
        this.newsArticles = (ArrayList<Article>) newsArticles;
        this.context = context;
        this.onArticleListener = onArticleListener;
    }

    @NonNull
    @Override
    public Viewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_list_item, parent, false);
        Viewholder viewholder = new Viewholder(view, onArticleListener);
        return viewholder;
    }

    @Override
    public void onBindViewHolder(@NonNull Viewholder holder, int position) {
        Article currentArticle = newsArticles.get(position);

        holder.newsHeadline.setText(currentArticle.getTitle());
        Glide.with(context)
                .load(currentArticle.getUrlToImage())
                .placeholder(R.drawable.ic_launcher_foreground)
                .into(holder.newsImage);
        holder.newsContent.setText(currentArticle.getContent());
//        holder.publishedTime.setText(UTCtoLocalDateConverter(currentArticle.getPublishedAt()));


    }

    @Override
    public int getItemCount() {
        return newsArticles.size();
    }

    public class Viewholder extends RecyclerView.ViewHolder implements View.OnClickListener {
        OnArticleListener onArticleClickedListner;
        TextView newsHeadline;
        TextView newsContent;
        //       TextView publishedTime;
        ImageView newsImage;
        ConstraintLayout parentLayout;

        public Viewholder(@NonNull View itemView, OnArticleListener onArticleListener) {
            super(itemView);
            newsHeadline = itemView.findViewById(R.id.news_headline_textView);
            newsContent = itemView.findViewById(R.id.news_content_textView);
//            publishedTime = itemView.findViewById(R.id.published_time_textView);
            newsImage = itemView.findViewById(R.id.news_image_view);
            parentLayout = itemView.findViewById(R.id.list_item_parent_layout);
            onArticleClickedListner = onArticleListener;
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            Log.d("RecyclerViewAdapter", "item position clicked: " + getAdapterPosition());
            onArticleClickedListner.onArticleClicked(getAdapterPosition());
        }
    }

    /*RecyclerView onItemClickListenerInterface*/
    public interface OnArticleListener {
        void onArticleClicked(int position);

    }

}

MainActivity (Houses RecyclerView)

public class MainActivity extends AppCompatActivity implements NewsArticleAdapter.OnArticleListener {
private RecyclerView newsRecyclerView;
private NewsArticleAdapter newsAdapter;
private NewsAPI NewsAPI;
private ArrayList<Article> newsArticles;



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    newsRecyclerView = findViewById(R.id.newsRecyclerView);
    newsAdapter = new NewsArticleAdapter(new ArrayList<Article>(), this, this);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
    newsRecyclerView.setLayoutManager(layoutManager);
    newsRecyclerView.setAdapter(newsAdapter);


    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(RetrofitClient.BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    NewsAPI = retrofit.create(NewsAPI.class);

    Call<Example> call = NewsAPI.getRootJSONObject();

    call.enqueue(new Callback<Example>() {
        @Override
        public void onResponse(Call<Example> call, Response<Example> response) {
            if (response.isSuccessful()) {
                newsArticles = (ArrayList<Article>) response.body().getArticles();
                refreshAdapterWithNewsArticles(newsArticles);
            } else {
                Log.d("MainActivity", "Error in on Response " + String.valueOf(response.code()));
            }
        }

        @Override
        public void onFailure(Call<Example> call, Throwable t) {
            Toast.makeText(MainActivity.this, "Error retrieving News Articles :(", Toast.LENGTH_SHORT).show();
        }
    });


}
/*
 *Method used to generate list of data using recyclerView with costom adapter
 *  */
private void refreshAdapterWithNewsArticles(List<Article> body) {
    newsAdapter = null;
    newsAdapter = new NewsArticleAdapter(body, this, MainActivity.this);
    newsRecyclerView.setAdapter(newsAdapter);

}

@Override
public void onArticleClicked(int position) {
    Log.d("MainActivity", "onArticleClicked Was called in MainACtivity");
    Article currentArticle = newsArticles.get(position);
    Uri articleUri = Uri.parse(currentArticle.getUrl());
    Intent intent = new Intent(Intent.ACTION_VIEW, articleUri);
    startActivity(intent);
}

}

JavaHava
  • 189
  • 2
  • 15

2 Answers2

0

Inspired by the code provided in this answer from Jacob Tabak, in your mainActivity under onCreate method.

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(MainActivity.this, recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
        @Override
        public void onItemClick(View view, int position) {
            //whatever you want to do with position
        }

        @Override
        public void onLongItemClick(View view, int position) {
            //whatever you want to do with position
        }
    }));

and create a new class name it RecyclerItemClickListener and paste this

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
GestureDetector mGestureDetector;
private OnItemClickListener mListener;

public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null && mListener != null) {
                mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
            }
        }
    });
}

@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
        mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        return true;
    }
    return false;
}

@Override
public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
}

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}

public interface OnItemClickListener {
    public void onItemClick(View view, int position);

    public void onLongItemClick(View view, int position);
}}

It is a custom RecyclerItemClickListener.

Ian Campbell
  • 23,484
  • 14
  • 36
  • 57
Rajnish Sharma
  • 390
  • 2
  • 14
  • Ok it is from stack overflow but I don't know who originally gave this answer, so how will I tag the person or post? I am using this code for more than 6 months. I you could help me to spot the person or post who answered this, I will be grateful to you and will definitely give him all the credit! – Rajnish Sharma Jul 21 '20 at 17:46
  • One way is to simply edit in a link to the original answer which I linked in my comment. I edited in one possible way. Feel free to modify it however you want. Thanks for your response! Answers on Stack Overflow are provided under the CC Attribution license, so you're free to use them as long as you attribute the work to the original author. – Ian Campbell Jul 21 '20 at 17:49
0

Why don't you try the listener from the onBindViewHolder() method?

holder.your_layout_item.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            onArticleClickedListner.onArticleClicked(position);
        }
    });

If you have any confusion I can explain it more clear. If you solved it you can accept the answer.

Brahma Datta
  • 1,102
  • 1
  • 12
  • 20
  • I thought making a new onclick listener for every viewholded call is bad practice? Won't that take a lot of resources because onbindviewholder is called frequently? – JavaHava Jul 21 '20 at 17:12
  • I thought the same previously. But when it comes like the 3-4 items of the layout like name, item name, item position then we can do it in OnBindViewHolder because view holder doesn't talk every value. so I had practiced using the onBindView() method. And I didn't find any issue with that. @JavaHava – Brahma Datta Jul 21 '20 at 17:20
  • Ok I understand, what is the groupinfo that your are referencing in your code – JavaHava Jul 21 '20 at 19:04
  • it's actually the value of the position as if you want the text value at a particular position. I think it's not a need for your question. You only need a position right? If it solved your problem can you upvote and accept, please? it may reach other developers.@JavaHava – Brahma Datta Jul 21 '20 at 19:13