知乎日報客戶端--知乎日報板塊的實現
看完這一篇你應該學會:如何展示新聞資訊類,效果圖:
這一篇的知識點: Fragment的替換,Recylerview[adapter, holder]的使用,Okhttp,JSONObject解析json
還是先給佈局:
zhihufragment.xml
RecylerView的item佈局: zhihu_list_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tool="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:orientation="horizontal" android:padding="5dp" android:layout_width="match_parent" android:layout_height="100dp"> <ImageView android:layout_width="120dp" android:id="@+id/zhihu_img" android:scaleType="centerCrop" android:padding="10dp" android:layout_height="match_parent" /> <LinearLayout android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:textSize="20sp" tools:text="wuiweqiyweuqiewwqwqwqew" android:id="@+id/zhihu_title" android:layout_weight="1"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" tools:text="知乎客戶端" android:id="@+id/zhihu_from"/> </LinearLayout> </LinearLayout>
由一個ImageView和兩個TextView構成,ImageView用來顯示知乎日報的圖片,textview來顯示標題和id。
接著是ZhihuFragment.java用來顯示zhihu_fragment.xml的,並且在這個裡面完成介面的初始化顯示資訊等:
下面會分幾個部分來講這個程式碼:public class ZhihuFragment extends Fragment { private Bitmap mBitmap; private List<News> 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<News> 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<News> 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<ZhihuAdapter.ViewHolder> { @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<ZhihuAdapter.ViewHolder> {
@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<News> 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<storiesArr.length();i++){
Log.d(TAG,"mNEws.size()===> " + 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();jsonobject解析放在list集合返回,通知recylerview資料發生改變。
獲得從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;
}
嗯。。