-1

So I was following a video to do a news app from scratch in Android Studio and I encountered the error of the title. I tried to follow many of the answers in questions about the same error but its hard to understand because everyone has different codes as I spected. So here is my Adapter code:

package com.example.newsapp4;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;

import com.example.newsapp4.Model.Articles;
import com.squareup.picasso.Picasso;

import java.util.List;

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

    Context context;
    List<Articles> articles;

    public Adapter(Context context, List<Articles> articles) {
        this.context = context;
        this.articles = articles;
    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        final Articles a = articles.get(position);

        String imageUrl = a.getUrlToImage();

        holder.tvTitle.setText(a.getTitle());
        holder.tvSource.setText(a.getSource().getName());
        holder.tvDate.setText(a.getPublishedAt());


        Picasso.with(context).load(imageUrl).into(holder.imageView);
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        TextView tvTitle,tvSource,tvDate;
        ImageView imageView;
        CardView cardView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            tvTitle = itemView.findViewById(R.id.tvTitle);
            tvSource = itemView.findViewById(R.id.tvSource);
            tvDate = itemView.findViewById(R.id.tvDate);
            imageView = itemView.findViewById(R.id.image);
            cardView = itemView.findViewById(R.id.cardView);

        }
    }
}

And here is my java class where I call the adapter with the recyclerview:

package com.example.newsapp4;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.example.newsapp4.Model.Articles;
import com.example.newsapp4.Model.Headlines;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class sportsnews extends AppCompatActivity {
    Adapter adapter;
    Intent intencion;
    RecyclerView recyclerView;
    final String API_KEY = "my api key";

    List<Articles> articles = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sportsnews);

        recyclerView = findViewById(R.id.recyclerView1);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));

        String country = getCountry();
        retrieveJson(country, API_KEY);
    }

    public void retrieveJson(String country, String apiKey){

        Call<Headlines> call = ApiClient.getInstance().getApi().getHeadlines(country, apiKey);
        call.enqueue(new Callback<Headlines>() {
            @Override
            public void onResponse(Call<Headlines> call, Response<Headlines> response) {
                if(response.isSuccessful() && response.body().getArticles() != null){
                    articles.clear();
                    articles = response.body().getArticles();
                    adapter = new Adapter(sportsnews.this,articles);
                    recyclerView.setAdapter(adapter);
                }
            }


            @Override
            public void onFailure(Call<Headlines> call, Throwable t) {
                Toast.makeText(sportsnews.this, t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    public String getCountry(){
        Locale locale = Locale.getDefault();
        String country = locale.getCountry();
        return country.toLowerCase();

    }

    public void aPerfil(View vista){
        intencion = new Intent(this, profile_activity.class);
        startActivity(intencion);
    }
}

Notice that there is a method that goes with a button that is not applicated. The method is aPerfil.

This here is my manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.newsapp4">


    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".sportsnews" android:screenOrientation="locked"/>
        <activity android:name=".profile_activity" android:screenOrientation="locked"/>
        <activity android:name=".menuContent" android:screenOrientation="locked"/>
        <activity android:name=".MainActivity" android:screenOrientation="locked">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="preloaded_fonts"
            android:resource="@array/preloaded_fonts" />
    </application>

</manifest>

There are more activities before reaching the one that has the adapter.

Im guessing that in my api key I need to put the key that the webpage give me, something like a lot of numbers and letters, not a link.

Feel free to ask for more code if you need it.

Thanks for your time!

Syed Rafaqat Hussain
  • 1,009
  • 1
  • 9
  • 33

1 Answers1

0

move below code from onResponse to onCreate before retrieveJson(country, API_KEY);

adapter = new Adapter(sportsnews.this,articles);
recyclerView.setAdapter(adapter);

Create a setter in your Adapter something like below

public void setArticles(List<Articles> newArticle) {
    if (newArticle != null && newArticle.size() > 0) {
        this.articles = newArticle;
        notifyDataSetChanged();
    }
}

Then in your onResponse write something like below where earlier you were setting adapter in recylerview.

adapter.setArticles(articles)

Note: recylerView should always be attached to adapter when its inflating, you just cannot wait for API response because that runs on diff thread and will take time to fetch data till that time, OS will already try to inflate the recylerview and will fail if there is no adapter attached.

So we should always attach the adapter even with empty data as that is not the problem you can pass the data when you received it from API and then call notifyDataSetChanged() and then the adapter will take care of inflating each item.

Dinkar Kumar
  • 2,175
  • 2
  • 12
  • 22
  • Thanks, the error dissapeared but I cannot see the data from the news API in my cardview. – Sergio Campos Lacueva May 17 '21 at 14:58
  • did you done everything I explained above ? – Dinkar Kumar May 17 '21 at 15:12
  • Yes I did all you told me and no information from the api is displayed. Im getting the information from the api in this website: https://newsapi.org/ – Sergio Campos Lacueva May 17 '21 at 15:49
  • Can you update your question, with the latest changes so i can see them and help you debug further – Dinkar Kumar May 17 '21 at 16:21
  • I have the data displayed now finally, the problem was when I was putting the API, I was underestimating the whole API link so the source, in this case, bbc-news wont appear, I just did this `public static String source = "bbc-news";`. Then in the ApiInterface, in `getHeadlines` I putted source as a string in the Query and everything was working fine with your tips too!, thanks for your time! – Sergio Campos Lacueva May 17 '21 at 16:46