java - 我的应用程序中的新闻页面没有检索任何新闻,并且只显示空白页而不是新闻源
问题描述
我目前正在开发 Android Studio 4.0,Build #AI-193.6911.18.40.6514223。
进入新闻页面后,我看到的是一个空白页面。API 似乎没有检索它应该检索的新闻。我已经仔细检查了我的整个应用程序是否有任何拼写错误(以防它与 API 参数不匹配)。一切正常,但 API 未检索数据。
我在代码下面附上了这个问题。
新闻页面.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);
}
}
适配器:
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());
}
}
}
接口客户端:
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);
}
}
}
接口接口:
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
);
}
实用程序:
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();
}
}
根据 API 的参数:
消息:
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;
}
}
文章 :
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;
}
}
资源:
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;
}
}
应该显示新闻源的卡片视图:
<?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>
编辑:
我在API interface
下面添加了一些代码,尝试使用此查询后再次出现相同的问题:
@GET("everything")
Call<News> getNewsSearch(
@Query("q") String Keyword,
@Query("language") String language,
@Query("SortBy") String sortBy,
@Query("apiKey") String apiKey
);
解决方案
您需要将此方法添加到您的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();
}
});
}
推荐阅读
- visual-studio - Visual Studio 2017 探查器结果
- ios - Alamofire:具有额外属性的可编码对象
- python - 根据其他列表中的单词对列表进行排序
- windows - 从批处理文件运行 GO 1.7.x 测试并排除供应商
- android - Android P API 28 中不推荐使用 ConnectivityManager.TYPE_WIFI 的替代方法是什么?
- jquery - IF URL做预定义功能
- json - 使用 JsonPath 映射数组
- java - Spring Boot Controller:以与 PagingAndSortingRepository 相同的样式返回资源
- javascript - VueMq 自定义断点和导入
- ruby - Sequel中多列上的匹配值列表