1. 程式人生 > >知乎日報客戶端--知乎日報板塊的實現

知乎日報客戶端--知乎日報板塊的實現

看完這一篇你應該學會:如何展示新聞資訊類,效果圖:


這一篇的知識點: 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;
    }
嗯。。