Search code examples
androidjsonparsingandroid-recyclerviewpdf-reader

Android: Opening PDFs From a RecyclerView


enter image description here

The title of the question doesnt fully explain my problem so allow me to elaborate. I have an app that parses JSON data from the Google Civic API into a recyclerview. One particular field is a TextView that stores a PDF url in a string. How do I set the TextView so it is clickable and opens the PDF preferably in app. I've looked up solutions and I've tried using WebView and PDFReader amongst others, but I couldnt find any solutions that mentioned how to do this from a recyclerview, so I'm not sure where to place this code. Since I am clicking on an item in the recyclerView, I thought I might need to add the code in the recyclerview adapter instead of the main class.

Here is the code for the main class: This class handles the JSON parsing

    public class VoterInformation extends AppCompatActivity  {
    private static final String url = "https://www.googleapis.com/civicinfo/v2/voterinfo?address=2613+Irvington+Ave+San+Bernardino+CA+92407&electionId=2000&officialOnly=false&returnAllAvailableData=false&fields=contests(referendumBallotResponses%2CreferendumBrief%2CreferendumConStatement%2CreferendumEffectOfAbstain%2CreferendumPassageThreshold%2CreferendumProStatement%2CreferendumSubtitle%2CreferendumText%2CreferendumTitle%2CreferendumUrl)&key=AIzaSyB1B5mEKHK8PHDiNcGQ5ZU3fPIH9KWxAcQ";
    private TextView refTitle, refSub, refUrl;
    private LinearLayoutManager linearLayoutManager;
    private List<Refs> refList;
    private RecyclerView myrv;
    private RecyclerView.Adapter adapter;


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

        refTitle = findViewById(R.id.ref_title);         //Initialize TextViews
        refSub = findViewById(R.id.ref_sub);


        myrv = findViewById(R.id.ref_rv);        //Initialize recycler view
        refList = new ArrayList<>();
        adapter = new RefRvAdapter(refList, getApplicationContext());

        linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

        myrv.setHasFixedSize(true);
        myrv.setLayoutManager(linearLayoutManager);
        myrv.setAdapter(adapter);

        TextView pdf_url = findViewById(R.id.ref_url);
        pdf_url.setClickable(true);
        pdf_url.setMovementMethod(LinkMovementMethod.getInstance());


        getData();

    }



    private void getData(){
        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Loading...");
        progressDialog.show();

        StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                progressDialog.dismiss();
                try{
                    JSONObject jsonObject = new JSONObject(response);
                    JSONArray array = jsonObject.getJSONArray("contests");
                    String pdf_url = array.getJSONObject(0).getString("referendumUrl") ;
                    for(int i = 0; i < array.length(); i++){
                        JSONObject jo = array.getJSONObject(i);
                        Refs refs = new Refs(jo.getString("referendumTitle"),
                                jo.getString("referendumSubtitle"),
                                jo.getString("referendumUrl"));
                        refList.add(refs);
                    }
                    adapter = new RefRvAdapter(refList, getApplicationContext());
                    myrv.setAdapter(adapter);

                } catch(JSONException e){
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener(){
            @Override
            public void onErrorResponse(VolleyError error){
                Log.e("Volley", error.toString());
                progressDialog.dismiss();
            }
        });
        RequestQueue requestQueue = Volley.newRequestQueue(this);
        requestQueue.add(stringRequest);

    }


}

Here is my code for the adapter class:

public class  RefRvAdapter extends RecyclerView.Adapter<RefRvAdapter.MyViewHolder>{
    private Context context;
    private List<Refs> refsList;

    public RefRvAdapter(){}

    public RefRvAdapter(List<Refs> refList, Context context){
        this.refsList = refList;
        this.context = context;
    }
    @NonNull
    @Override
    public RefRvAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view;
        LayoutInflater mInflater = LayoutInflater.from(context);
        view = mInflater.inflate(R.layout.ref_card, viewGroup, false);
        final MyViewHolder viewHolder = new MyViewHolder(view);
        viewHolder.view_containers.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent (context, SingleReferendum.class);
                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                i.putExtra("referendumTitle", refsList.get(viewHolder.getAdapterPosition()).getRefTitle());
                i.putExtra("referendumSubtitle", refsList.get(viewHolder.getAdapterPosition()).getRefSub());
                i.putExtra("referendumUrl", refsList.get(viewHolder.getAdapterPosition()).getRefUrl());

                context.startActivity(i);
            }
        });
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RefRvAdapter.MyViewHolder myViewHolder, int i) {
        myViewHolder.refTitle.setText(refsList.get(i).getRefTitle());
        myViewHolder.refSub.setText(refsList.get(i).getRefSub());
        myViewHolder.refUrl.setText(refsList.get(i).getRefUrl());

    }

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


    public static class MyViewHolder extends RecyclerView.ViewHolder{
        TextView refTitle, refSub, refUrl;
        LinearLayout view_containers;
        public MyViewHolder(View itemView){
            super(itemView);
            refTitle = itemView.findViewById(R.id.ref_title);
            refSub = itemView.findViewById(R.id.ref_sub);
            refUrl = itemView.findViewById(R.id.ref_url);
            view_containers = itemView.findViewById(R.id.view_container_ref);

        }
    }
}

The app parses all the data just fine. I just want to make the url clickable. When the user clicks it, the pdf opens. Do I add the code in the RecyclerView adapter class, or in the main activity?

ANSWER: Edit the onBindViewHolder method like so.

@Override
    public void onBindViewHolder(@NonNull final RefRvAdapter.MyViewHolder myViewHolder, int i) {
        myViewHolder.refTitle.setText(refsList.get(i).getRefTitle());
        myViewHolder.refSub.setText(refsList.get(i).getRefSub());
        myViewHolder.refUrl.setText(refsList.get(i).getRefUrl());
        myViewHolder.view_containers.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent (context, SingleReferendum.class);
                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                i.putExtra("referendumTitle", refsList.get(myViewHolder.getAdapterPosition()).getRefTitle());
                i.putExtra("referendumSubtitle", refsList.get(myViewHolder.getAdapterPosition()).getRefSub());
                i.putExtra("referendumUrl", refsList.get(myViewHolder.getAdapterPosition()).getRefUrl());

                context.startActivity(i);
            }
        });

        myViewHolder.refUrl.setOnClickListener(new View.OnClickListener(){
            @Override   //handle pdf clicks
            public void onClick(View view) {
                String refUrl = refsList.get(myViewHolder.getAdapterPosition()).getRefUrl();
                Intent intent = new Intent (Intent.ACTION_VIEW, Uri.parse(refUrl));
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            }
        });

    }

Solution

  • If I didn't misunderstand what you mean,just modify methods:onCreateViewHolder and onBindViewHolder to:

    @NonNull
    @Override
    public RefRvAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view;
        LayoutInflater mInflater = LayoutInflater.from(context);
        view = mInflater.inflate(R.layout.ref_card, viewGroup, false);
        final MyViewHolder viewHolder = new MyViewHolder(view);
        return new MyViewHolder(view);
    }
    
    @Override
    public void onBindViewHolder(@NonNull RefRvAdapter.MyViewHolder myViewHolder, int i) {
        myViewHolder.refTitle.setText(refsList.get(i).getRefTitle());
        myViewHolder.refSub.setText(refsList.get(i).getRefSub());
        myViewHolder.refUrl.setText(refsList.get(i).getRefUrl());
        myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent (context, SingleReferendum.class);
                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                i.putExtra("referendumTitle", refsList.get(myViewHolder.getAdapterPosition()).getRefTitle());
                i.putExtra("referendumSubtitle", refsList.get(myViewHolder.getAdapterPosition()).getRefSub());
                i.putExtra("referendumUrl", refsList.get(myViewHolder.getAdapterPosition()).getRefUrl());
    
                context.startActivity(i);
            }
        }
        myViewHolder.refUrl.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String refUrl = refsList.get(myViewHolder.getAdapterPosition()).getRefUrl();
                //open pdf here.
            }
        });
    }
    

    Try it and feedback if it's OK.