E/RecyclerView:没有连接适配器;跳过布局错误 Android Studio with API 29

E/RecyclerView: No adapter attached; Skipping layout ERROR Android Studio with API 29

所以我在 Android Studio 中跟随一个视频从头开始做一个新闻应用程序,我遇到了标题错误。我试图按照有关相同错误的问题中的许多答案进行操作,但很难理解,因为正如我所看到的,每个人都有不同的代码。所以这是我的适配器代码:

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);

        }
    }
}

这里是我的 java class 我用 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);
    }
}

请注意,有一个方法与未应用的按钮一起使用。方法是aPerfil.

这是我的 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>

在到达具有适配器的活动之前还有更多活动。

我猜想在我的 api 密钥中我需要输入网页给我的密钥,比如很多数字和字母,而不是 link。

如果需要,请随时索取更多代码。

感谢您的宝贵时间!

将下面的代码从 onResponse 移动到 onCreate 之前 retrieveJson(country, API_KEY);

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

在您的 Adapter 中创建一个 setter,如下所示

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

然后在你的 onResponse 中写下类似下面你之前在 recylerview 中设置适配器的地方。

adapter.setArticles(articles)

注意: recylerView 在充气时应始终附加到适配器,你不能等待 API 响应,因为它在 diff 线程上运行并且需要时间获取数据到那个时候,OS 已经尝试膨胀 recylerview,如果没有连接适配器将失败。

因此,即使数据为空,我们也应该始终附加适配器,因为这不是问题,您可以在从 API 收到数据时传递数据,然后调用 notifyDataSetChanged(),然后适配器会处理为每个项目充气。