英文:
My news page in my app isn't retrieving any news and only a blank white page is being displayed instead of a newsfeed
问题
我目前正在使用 Android Studio 4.0 进行工作,构建版本号为 AI-193.6911.18.40.6514223。
在进入新闻页面后,我看到一个空白页面。似乎 API 没有检索到应该显示的新闻。我已经仔细检查了整个应用程序,以查找任何拼写错误(以防它与 API 参数不匹配)。一切看起来都是正确的,但 API 并未检索到数据。
以下是与问题相关的代码。
newspage.java:
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.Toast;
import com.example.nvirone.API.ApiClient;
import com.example.nvirone.API.ApiInterface;
import com.example.nvirone.Models.Article;
import com.example.nvirone.Models.News;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class Newspage extends AppCompatActivity {
// ...
// (代码略,与问题相关的其余部分)
// ...
public void LoadJson(){
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
String country = Utils.getCountry();
Call<News> call;
call = apiInterface.getNews(country, API_KEY);
call.enqueue(new Callback<News>() {
@Override
public void onResponse(Call<News> call, Response<News> response) {
if (response.isSuccessful() && response.body().getArticle()!=null){
articles.clear();
articles = response.body().getArticle();
adapter.notifyDataSetChanged();
}
}
@Override
public void onFailure(Call<News> call, Throwable t) {
Toast.makeText(Newspage.this, "无结果", Toast.LENGTH_LONG).show();
}
});
}
}
以上是与问题相关的代码部分。如果您还有其他需要帮助的地方,请随时提问。
英文:
I am currently working on Android Studio 4.0, Build #AI-193.6911.18.40.6514223.
Upon entering the news page, I am being shown a blank page. It appears that the API is not retrieving the news it's supposed to. I've double checked my entire app for any typos (in case it doesn't match the API parameters). Everything appears right but the API is not retrieving the data.
I have attached below the code with respect to the problem.
newspage.java:
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.widget.Toast;
import com.example.nvirone.API.ApiClient;
import com.example.nvirone.API.ApiInterface;
import com.example.nvirone.Models.Article;
import com.example.nvirone.Models.News;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class Newspage extends AppCompatActivity {
public static final String API_KEY = "(unique API key)";
private RecyclerView recyclerView;
private Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private List<Article> articles = new ArrayList<>();
private String TAG = Newspage.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_newspage);
recyclerView = findViewById(R.id.recyclerView);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new Adapter(articles, Newspage.this);
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setNestedScrollingEnabled(false);
LoadJson();
}
public void LoadJson(){
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
String country = Utils.getCountry();
Call<News> call;
call = apiInterface.getNews(country, API_KEY);
call.enqueue(new Callback<News>() {
@Override
public void onResponse(Call<News> call, Response<News> response) {
if (response.isSuccessful() && response.body().getArticle()!=null){
articles.clear();
articles = response.body().getArticle();
adapter.notifyDataSetChanged();
}
}
@Override
public void onFailure(Call<News> call, Throwable t) {
Toast.makeText(Newspage.this,"NO result",Toast.LENGTH_LONG).show();
}
});
}
}
Newsindetail.java:
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class NewInDetail extends AppCompatActivity {
WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_in_detail);
Intent intent = getIntent();
String url = intent.getStringExtra("url");
webView = findViewById(R.id.webView);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setLoadsImagesAutomatically(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.setWebViewClient(new WebViewClient());
webView.loadUrl(url);
}
}
Adapter:
package com.example.nvirone;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.example.nvirone.Models.Article;
import com.squareup.picasso.Picasso;
import java.util.List;
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
private List<Article> articles;
private Context context;
private AdapterView.OnItemClickListener OnItemClickListener;
private OnItemClickListener onItemCLickListener;
public Adapter(List<Article> articles, Context context) {
this.articles = articles;
this.context = context;
}
public Adapter() {
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holders, int position) {
final MyViewHolder holder = holders;
final Article model = articles.get(position);
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(Utils.getRandomDrawbleColor());
requestOptions.error(Utils.getRandomDrawbleColor());
requestOptions.diskCacheStrategy(DiskCacheStrategy.ALL);
requestOptions.centerCrop();
Glide.with(context).load(model.getUrlToImage()).apply(requestOptions)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
holder.progressBar.setVisibility(View.GONE);
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
holder.progressBar.setVisibility(View.GONE);
return false;
}
})
.transition(DrawableTransitionOptions.withCrossFade())
.into(holder.imageView);
holder.title.setText(model.getTitle());
holder.desc.setText(model.getDescription());
holder.source.setText(model.getSource().getName());
holder.time.setText('\u2022' + Utils.DateToTimeFormat(model.getPublishedAt()));
holder.published.setText(Utils.DateToTimeFormat(model.getPublishedAt()));
holder.author.setText(model.getAuthor());
String imageURL = model.getUrlToImage();
Picasso.get().load(imageURL).into(holder.imageView);
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(context,NewInDetail.class);
intent.putExtra("url",model.getUrl());
context.startActivity(intent);
}
});
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item,parent,false);
return new MyViewHolder(view, onItemCLickListener);
}
@Override
public int getItemCount() {
return articles.size();
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemCLickListener = onItemClickListener;
}
public interface OnItemClickListener{
void onItemClick(View view, int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView title, desc, author, published, source, time;
ImageView imageView;
ProgressBar progressBar;
OnItemClickListener onItemClickListener;
CardView cardView;
public MyViewHolder(@NonNull View itemView, OnItemClickListener onItemClickListener) {
super(itemView);
itemView.setOnClickListener(this);
title = itemView.findViewById(R.id.title);
desc = itemView.findViewById(R.id.desc);
author = itemView.findViewById(R.id.author);
published = itemView.findViewById(R.id.publishedAt);
source = itemView.findViewById(R.id.source);
time = itemView.findViewById(R.id.time);
imageView = itemView.findViewById(R.id.img);
progressBar = itemView.findViewById(R.id.progress_load_photo);
cardView = itemView.findViewById(R.id.cardView);
this.onItemClickListener = onItemCLickListener;
}
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(view, getAdapterPosition());
}
}
}
ApiClient:
package com.example.nvirone.API;
import java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClient {
public static final String BaseURL = "https://newsapi.org/v2/";
public static Retrofit retrofit ;
public static Retrofit getApiClient(){
if(retrofit==null){
retrofit = new Retrofit.Builder().baseUrl(BaseURL).client(getUnsafeOkHttpClient().build()).addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}
public static OkHttpClient.Builder getUnsafeOkHttpClient(){
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
return builder;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
ApiInterface:
package com.example.nvirone.API;
import com.example.nvirone.Models.News;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface ApiInterface {
@GET("top-headlines")
Call<News> getNews(
@Query("country") String country,
@Query("apiKey") String apiKey
);
}
Utils:
package com.example.nvirone;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
public class Utils {
public static ColorDrawable[] vibrantLightColorList =
{
new ColorDrawable(Color.parseColor("#ffeead")),
new ColorDrawable(Color.parseColor("#93cfb3")),
new ColorDrawable(Color.parseColor("#fd7a7a")),
new ColorDrawable(Color.parseColor("#faca5f")),
new ColorDrawable(Color.parseColor("#1ba798")),
new ColorDrawable(Color.parseColor("#6aa9ae")),
new ColorDrawable(Color.parseColor("#ffbf27")),
new ColorDrawable(Color.parseColor("#d93947"))
};
public static ColorDrawable getRandomDrawbleColor() {
int idx = new Random().nextInt(vibrantLightColorList.length);
return vibrantLightColorList[idx];
}
public static String DateToTimeFormat(String oldstringDate){
PrettyTime p = new PrettyTime(new Locale(getCountry()));
String isTime = null;
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
Locale.ENGLISH);
Date date = sdf.parse(oldstringDate);
isTime = p.format(date);
} catch (ParseException e) {
e.printStackTrace();
}
return isTime;
}
public static String DateFormat(String oldstringDate){
String newDate;
SimpleDateFormat dateFormat = new SimpleDateFormat("E, d MMM yyyy", new Locale(getCountry()));
try {
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",Locale.CHINA).parse(oldstringDate);
assert date != null;
newDate = dateFormat.format(date);
} catch (ParseException e) {
e.printStackTrace();
newDate = oldstringDate;
}
return newDate;
}
public static String getCountry(){
Locale locale = Locale.getDefault();
String country = locale.getCountry();
return country.toLowerCase();
}
}
Parameters according to the API:
NEWS:
package com.example.nvirone.Models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class News {
@SerializedName("status")
@Expose
private String status;
@SerializedName("totalResults")
@Expose
private int totalResult;
@SerializedName("articles")
@Expose
private List<Article> article;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getTotalResult() {
return totalResult;
}
public void setTotalResult(int totalResult) {
this.totalResult = totalResult;
}
public List<Article> getArticle() {
return article;
}
public void setArticle(List<Article> article) {
this.article = article;
}
}
Article :
package com.example.nvirone.Models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Article {
@SerializedName("source")
@Expose
private Source source;
@SerializedName("author")
@Expose
private String author;
@SerializedName("title")
@Expose
private String title;
@SerializedName("description")
@Expose
private String description;
@SerializedName("url")
@Expose
private String url;
@SerializedName("urlToImage")
@Expose
private String urlToImage;
@SerializedName("publishedAt")
@Expose
private String publishedAt;
public Source getSource() {
return source;
}
public void setSource(Source source) {
this.source = source;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrlToImage() {
return urlToImage;
}
public void setUrlToImage(String urlToImage) {
this.urlToImage = urlToImage;
}
public String getPublishedAt() {
return publishedAt;
}
public void setPublishedAt(String publishedAt) {
this.publishedAt = publishedAt;
}
}
Source:
package com.example.nvirone.Models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Source {
@SerializedName("id")
@Expose
private String id;
@SerializedName("name")
@Expose
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The cardview that is supposed to display the newsfeed :
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="11dp"
android:layout_marginRight="11dp"
android:layout_marginTop="7dp"
android:layout_marginBottom="7dp"
app:cardElevation="@dimen/cardview_default_elevation"
app:cardCornerRadius="15dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/img"
android:scaleType="centerCrop"
android:transitionName="img"
tools:ignore= "UnusedAttribute"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="80dp"
android:id="@+id/shadow_bottom"
android:src="@drawable/bottom_shadow"
android:layout_alignBottom="@+id/img" />
<ProgressBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@android:style/Widget.ProgressBar.Small"
android:id="@+id/progress_load_photo"
android:layout_marginTop="70dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:id="@+id/author"
android:drawablePadding="10dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@android:color/white"
android:singleLine="true"
android:text="Author"
android:gravity="bottom"
android:layout_marginRight="160dp"
android:layout_alignLeft="@+id/title"
android:layout_alignStart="@+id/title"
android:layout_alignRight="@+id/layoutDate"
android:layout_alignTop="@+id/layoutDate"
android:layout_alignEnd="@+id/layoutDate"/>
<FrameLayout
android:id="@+id/layoutDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/img"
android:background="@drawable/round_white"
android:padding="5dp"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:layout_marginTop="50dp">
<ImageView
android:src="@drawable/ic_date"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#606060"
android:id="@+id/publishedAt"
android:layout_marginLeft="27dp"
android:layout_marginRight="10dp"
android:text="01 January 2000"/>
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:textStyle="bold"
android:textColor="@color/colorTextTitle"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:text="Title"
android:textSize="17sp"
android:layout_marginTop="10dp"
android:layout_below="@id/img"
android:id="@+id/title"/>
<TextView
android:id="@+id/desc"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginRight="16dp"
android:layout_below="@+id/title"
android:layout_marginLeft="16dp"
android:layout_marginTop="5dp"
android:text="Desc"/>
<TextView
android:id="@+id/source"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_below="@+id/desc"
android:layout_marginLeft="16dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:fontFamily="sans-serif-light"
android:textStyle="bold"
android:textColor="@color/colorTextTitle"
android:ellipsize="end"
android:singleLine="true"
android:drawablePadding="10dp"
android:maxLines="1"
android:text="Source"/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_below="@+id/desc"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_toRightOf="@+id/source"
android:ellipsize="end"
android:singleLine="true"
android:drawablePadding="10dp"
android:maxLines="1"
android:text="Time"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>
EDIT :
I have added some code in the API interface
as follows and the same problem has come up again after trying to use this query :
@GET("everything")
Call<News> getNewsSearch(
@Query("q") String Keyword,
@Query("language") String language,
@Query("SortBy") String sortBy,
@Query("apiKey") String apiKey
);
答案1
得分: 0
你需要将以下方法添加到你的 Adapter.java
中:
public void addArticles(List<Article> articles) {
this.articles.addAll(articles);
int count = getItemCount();
notifyItemRangeInserted(count, count + articles.size());
}
然后在你的 NewsPage.java
中这样使用它:
public void LoadJson() {
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
String country = Utils.getCountry();
Call<News> call;
call = apiInterface.getNews(country, API_KEY);
call.enqueue(new Callback<News>() {
@Override
public void onResponse(Call<News> call, Response<News> response) {
List<Article> newArticles = response.body().getArticle();
if (response.isSuccessful() && newArticles != null) {
adapter.addArticles(newArticles);
}
}
@Override
public void onFailure(Call<News> call, Throwable t) {
Toast.makeText(NewsPage.this, "NO result", Toast.LENGTH_LONG).show();
}
});
}
英文:
You need to add this method in your Adapter.java
:
public void addArticles(List<Article> articles) {
this.articles.addAll(articles);
int count = getItemCount();
notifyItemRangeInserted(count, count + articles.size());
}
And use it this way in your NewsPage.java
:
public void LoadJson() {
ApiInterface apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
String country = Utils.getCountry();
Call<News> call;
call = apiInterface.getNews(country, API_KEY);
call.enqueue(new Callback<News>() {
@Override
public void onResponse(Call<News> call, Response<News> response) {
List<Article> newArticles = response.body().getArticle();
if (response.isSuccessful() && newArticles != null) {
adapter.addArticles(newArticles);
}
}
@Override
public void onFailure(Call<News> call, Throwable t) {
Toast.makeText(NewsPage.this, "NO result", Toast.LENGTH_LONG).show();
}
});
}
专注分享java语言的经验与见解,让所有开发者获益!
评论