看完这一篇你应该学会:如何展示新闻资讯类,效果图:
上一篇讲的是 :知乎日报客户端--侧滑栏的实现
这一篇的知识点: Fragment的替换,Recylerview[adapter, holder]的使用,Okhttp,JSONObject解析json
还是先给布局:
zhihufragment.xml
RecylerView的item布局: zhihu_list_item.xml
由一个ImageView和两个TextView构成,ImageView用来显示知乎日报的图片,textview来显示标题和id。
接着是ZhihuFragment.java用来显示zhihu_fragment.xml的,并且在这个里面完成界面的初始化显示信息等:
public class ZhihuFragment extends Fragment {
private Bitmap mBitmap;
private List mNews;
private RecyclerView mRecyclerView;
private ZhihuAdapter mAdapter;
private boolean isGettingPre = false;
private ProgressDialog mDialog;
public static Fragment newInstance() {
return new ZhihuFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDialog = new ProgressDialog(getActivity());
mDialog.setTitle("加载中");
mDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mDialog.setCancelable(false);
Log.d("ZhihuFragmwnt","onCreate()");
if(!CheckNetWork.checkNet(getActivity())){
Toast.makeText(getActivity(),"网络连接失败...",Toast.LENGTH_SHORT).show();
}
mDialog.show();
mAdapter = new ZhihuAdapter();
final AsyncTask newsTask = new AsyncTask() {
@Override
protected List doInBackground(Object[] objects) {
mNews = Connect.getLatestNews(getActivity(),Connect.LATEST_URI);
return mNews;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
mRecyclerView.setAdapter(mAdapter);
mDialog.dismiss();
Log.d("mNews length===>", ""+mNews.size());
}
};
// newsTask.execute();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
Log.d("ZhihuFragment","计时器在执行===");
if(CheckNetWork.checkNet(getActivity())){
newsTask.execute();
this.cancel();
}
}
},0,1000);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d("ZhihuFragment","onCreateView()");
View v = inflater.inflate(R.layout.zhihufragment, container, false);
mRecyclerView = v.findViewById(R.id.recyler_view);
final LinearLayoutManager manager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(manager);
BitmapFactory.Options options = new BitmapFactory.Options();
mBitmap = CalculateInSampleSize.decodeSampleBitmapFromRes(getResources(),R.drawable.g,240,200);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.VERTICAL));
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if(isGettingPre){
return;
}
Log.d("item的长度",""+ manager.getItemCount()+"\n 当前itemindex: " + manager.findLastVisibleItemPosition());
if(manager.getItemCount() -manager.findLastVisibleItemPosition() < 2){
isGettingPre = true;
mDialog.show();
Log.d("Zhihu","只剩下4个item了");
AsyncTask task = new AsyncTask() {
@Override
protected List doInBackground(Object[] objects) {
mNews = Connect.getPreNews();
//mAdapter.notifyDataSetChanged()
return mNews;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Log.d("重新加载mnews==:",""+mNews.size());
Log.d("count===> " ,""+manager.getItemCount()+"////当前item下标===> " +manager.findLastVisibleItemPosition());
mAdapter.notifyDataSetChanged();
isGettingPre = false;
mDialog.dismiss();
}
};
task.execute();
}
}
});
return v;
}
private class ZhihuAdapter extends RecyclerView.Adapter {
@Override
public ZhihuAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(getActivity())
.inflate(R.layout.zhihu_list_item, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.mImageView.setImageBitmap(mNews.get(position).getBitmap());
holder.mTitle.setText(mNews.get(position).getTitle());
holder.mFrom.setText(mNews.get(position).getId());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(getActivity(),"点击了recylerview",Toast.LENGTH_SHORT).show();
// News n = Connect.newsDetail(mNews.get(position));
AsyncTask task = new AsyncTask() {
@Override
protected String doInBackground(Object[] objects) {
String data = Connect.newsDetail(mNews.get(position));
return data;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Intent intent = new Intent(getActivity(), NewsInfoActivity.class);
intent.putExtra("data",String.valueOf(o));
startActivity(intent);
}
};
task.execute();
}
});
}
@Override
public int getItemCount() {
return mNews.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
private TextView mTitle;
private TextView mFrom;
public ViewHolder(View itemView) {
//super();
super(itemView);
mImageView = itemView.findViewById(R.id.zhihu_img);
mTitle = itemView.findViewById(R.id.zhihu_title);
mFrom = itemView.findViewById(R.id.zhihu_from);
// itemView.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Toast.makeText(getActivity(),"点击了recylerview",Toast.LENGTH_SHORT).show();
// Intent intent = new Intent(getActivity(), NewsInfoActivity.class);
// startActivity(intent);
//
// }
// });
}
}
}
}
下面会分几个部分来讲这个代码:
1. onCreate方法
打开时,显示一个dialog加载中,因为程序要从网络上获取数据,因为Android不允许在主线程中进行任何网络操作,所以这里使用的时AsyncTask异步进行获取,等到获取到数据后,就让dialog消失。
2. onCreateView方法
这个里面先inflate我的zhihufragment.xml布局,并且设置LayoutManager,还对onScroll方法进行侦听。
我是让当数据中只剩下4条结果未显示时就去自动拉去数据。用layoutmanager获取itemcount总数,和当前最后显示的下标位置lastitemposition,所以当itemcount - lastitemposition<5时便去获取数据,然后解析返回的json字符串,包装成news类后,再通知recylerview数据的改变,就实现下拉时会一直获取数据。
3.构建Adapter和holder
private class ZhihuAdapter extends RecyclerView.Adapter {
@Override
public ZhihuAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(getActivity())
.inflate(R.layout.zhihu_list_item, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.mImageView.setImageBitmap(mNews.get(position).getBitmap());
holder.mTitle.setText(mNews.get(position).getTitle());
holder.mFrom.setText(mNews.get(position).getId());
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Toast.makeText(getActivity(),"点击了recylerview",Toast.LENGTH_SHORT).show();
// News n = Connect.newsDetail(mNews.get(position));
AsyncTask task = new AsyncTask() {
@Override
protected String doInBackground(Object[] objects) {
String data = Connect.newsDetail(mNews.get(position));
return data;
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Intent intent = new Intent(getActivity(), NewsInfoActivity.class);
intent.putExtra("data",String.valueOf(o));
startActivity(intent);
}
};
task.execute();
}
});
}
@Override
public int getItemCount() {
return mNews.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView mImageView;
private TextView mTitle;
private TextView mFrom;
public ViewHolder(View itemView) {
//super();
super(itemView);
mImageView = itemView.findViewById(R.id.zhihu_img);
mTitle = itemView.findViewById(R.id.zhihu_title);
mFrom = itemView.findViewById(R.id.zhihu_from);
// itemView.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Toast.makeText(getActivity(),"点击了recylerview",Toast.LENGTH_SHORT).show();
// Intent intent = new Intent(getActivity(), NewsInfoActivity.class);
// startActivity(intent);
//
// }
// });
}
}
}
创建内部类ZhihuAdapter继承Recylerview.Adapter
onCreateViewHolder用来加载并返回item条目
onBindViewHolder显示item的具体内容,并为itemView设置点击侦听,当点击打开新闻详情页
getItemCount返回item的长度
。
新闻详情页是 打开另一个activity,这个activity会显示一个WebView,里面加载html文件。
看一下获取数据部分:
public static List getLatestNews(Context context,String url) {
OkHttpClient client = new OkHttpClient(); //创建okHttp对象
Request request = new Request.Builder() //创建request对象
.url(url).build();
try {
Response response = client.newCall(request).execute();//得到Response对对象
//response.
if (response.isSuccessful()) {
String result = response.body().string();
JSONObject resultObj = new JSONObject(result);
latestNews_date = resultObj.getString("date");
Log.d(TAG,"latest date is==> " + latestNews_date );
JSONArray storiesArr = resultObj.getJSONArray("stories");
Log.d(TAG,"有"+storiesArr.length()+"个故事");
JSONObject firstStory = new JSONObject(storiesArr.get(0).toString());
Log.d("latest_remote_id===>",firstStory.getString("id"));
Log.d("pre_news_id=>",SharePres.getLatestNewsId(context));
if(firstStory.getString("id").equals(SharePres.getLatestNewsId(context))){
if(mNews.size() > 0){
return mNews;
}
}
mNews.clear();
SharePres.setLatestNewsId(context,firstStory.getString("id"));
for(int i=0;i " + mNews.size());
JSONObject stotyObj = new JSONObject( storiesArr.get(i).toString());
String id = stotyObj.getString("id");
String imgUrl = (String) stotyObj.getJSONArray("images").get(0);
String title = stotyObj.getString("title");
//Log.d(TAG,"img====> " + img + "\n id===> " + id + "\n title==> "+title);
Bitmap bitmap=getUrlBitmap(imgUrl);
News news = new News(id,title,bitmap);
mNews.add(news);
}
return mNews;
}
} catch (IOException e) {
Log.d(TAG, "连接失败", e);
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
使用okhttp,然后获得返回内容应该用 response.body().string();
获得从url获得bitmap方法:
private static Bitmap getUrlBitmap(String imgUrl){
Log.d("getBitmap===>", imgUrl);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(imgUrl).build();
try {
Response response = client.newCall(request).execute();
if(response.isSuccessful()){
Bitmap bitmap = BitmapFactory.decodeStream(response.body().byteStream());
return bitmap;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
嗯。。