安卓開發筆記——打造屬於本身的博客園APP(三)

  在上一篇文章《安卓開發筆記——打造屬於本身的博客園APP(二)》中,咱們基本上實現了主界面的搭建,網絡框架的搭建,各博客列表頁面的展現包括更新效果,對圖片作了三級緩存處理(後面會把文章,新聞作成離線閃存,實現無網絡也能照常瀏覽)。css

  今天來說講博客詳情頁和評論頁面的實現,國際慣例,先上效果圖:(動態圖片比較大,加載須要點時間)html

 

  這裏說下,關於上篇文章XML的解析,我後來查了下確實有一些方便解析的工具,例如:FastXML,Xstram等且效率更高,這裏是在它的官方找到的一張數據圖:java

文章裏我就仍是先採用原生的pull解析了,等重構代碼時候再換上工具類吧,先把項目作完。 android

 

  好了,廢話很少說了,直接進入主題:git

一、關於RecyclerView的點擊事件github

  首先先來講下關於RecyclerView的點擊監聽事件,在上篇文章提到,RecyclerView是ListView升級版,顧名思義它是爲效率而生的,它不關心多餘的任何事情,好比Item項的動做監聽,Item項的分割線,Item項的添加動畫效果,只專一於數據的展現實現,相比ListView它更符合軟件設計原則,更加解耦。web

  上面提到它不關心Item項的動做監聽,很天然,它沒有和ListView控件同樣提供相似setOnItemClickListener這種監聽方法,須要咱們本身來實現,那麼很天然的,咱們會選擇在Adapter裏去設置監聽事件,關於RecyclerView不熟悉的朋友能夠先看下這篇文章:http://blog.csdn.net/lmj623565791/article/details/45059587正則表達式

  首先咱們在Adapter設置一個點擊回調接口,並提供setter方法:數據庫

 1     /**
 2      * 自定義點擊回調接口
 3      */
 4     public interface RecyclerViewListener {
 5         void setOnclickListener(View view, int pos);
 6     }
 7 
 8     private RecyclerViewListener mRecyclerViewListener;
 9 
10     /**
11      * 提供setter方法
12      *
13      * @param recyclerViewListener
14      */
15     public void setRecyclerViewListener(RecyclerViewListener recyclerViewListener) {
16         this.mRecyclerViewListener = recyclerViewListener;
17     }

  而後咱們在onBindViewHolder中設置監聽事件:緩存

1         //設置點擊監聽
2         viewholder.itemView.setTag(i);
3         viewholder.mMore.setTag(Integer.MAX_VALUE);
4         viewholder.itemView.setOnClickListener(new ItemClick());
5         viewholder.mMore.setOnClickListener(new ItemClick());

  再來個實現接口:

    /**
     * 點擊事件實現類
     */
    public class ItemClick implements View.OnClickListener{
        @Override
        public void onClick(View v) {
            if(mRecyclerViewListener!=null){
                mRecyclerViewListener.setOnclickListener(v,(int)v.getTag());
            }
        }
    }

  這樣子,咱們就能夠在咱們的博客列表頁面設置點擊事件了,關於下面的showPopUpMenu是一個點擊彈出窗口,能夠實現收藏博文和關注博主的功能,咱們下一篇文章會提到。這裏咱們實現當點擊RecyclerView條目的時候會經過Intent傳遞Blog對象到博文詳情頁面。

 1         //設置條目點擊監聽
 2         mBlogListAdapter.setRecyclerViewListener(new BlogListAdapter.RecyclerViewListener() {
 3             @Override
 4             public void setOnclickListener(View view, int pos) {
 5 
 6                 if (view.getId() == R.id.ib_more) {
 7                     //點擊菜單按鈕
 8                     showPopUpMenu(view, pos);
 9                 } else {
10                     //點擊條目,傳遞對象
11                     Intent intent = new Intent();
12                     intent.setClass(getActivity(), BlogContentActivity.class);
13                     Bundle bundle = new Bundle();
14                     bundle.putSerializable("blog", mBlogs.get(pos));
15                     intent.putExtras(bundle);
16                     startActivity(intent);
17                 }
18             }
19         });

 

二、關於博文詳情頁面的實現

  這裏是關於博文詳情的接口:http://wcf.open.cnblogs.com/blog/post/body/{POSTID} (POSTID表明文章Id)

這裏是關於博文詳情的XML解析代碼:

 1 package com.lcw.rabbit.myblog.parser;
 2 
 3 import org.xmlpull.v1.XmlPullParser;
 4 import org.xmlpull.v1.XmlPullParserException;
 5 import org.xmlpull.v1.XmlPullParserFactory;
 6 
 7 import java.io.IOException;
 8 import java.io.InputStream;
 9 
10 /**
11  * 對博文詳情xml數據的解析
12  * Created by Lichenwei
13  * Date: 2015-08-17
14  * Time: 13:32
15  */
16 public class BlogContentXmlParser {
17 
18 
19     /**
20      * 用於解析博文詳情的xml,返回Avatar的List集合對象
21      *
22      * @param inputStream
23      * @param encode
24      * @return
25      * @throws XmlPullParserException
26      * @throws IOException
27      */
28     public static String getBlogContent(InputStream inputStream, String encode) throws XmlPullParserException, IOException {
29 
30         String info="";
31         //獲取XmlPullParser實例
32         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
33         XmlPullParser parser = factory.newPullParser();
34         parser.setInput(inputStream, encode);
35         //獲取解析事件
36         int eventType = parser.getEventType();
37         //當xml文檔未到尾端時
38         while (eventType != XmlPullParser.END_DOCUMENT) {
39             switch (eventType) {
40                 //解析根標籤的時候,實例化集合
41                 case XmlPullParser.START_DOCUMENT:
42                     break;
43                 case XmlPullParser.START_TAG:
44                     if("string".equals(parser.getName())){
45                         parser.next();
46                         info=parser.getText();
47                     }
48                     break;
49             }
50             eventType = parser.next();
51         }
52         return info;
53 
54     }
55 
56 }

  關於博文詳情頁的實現,我作了不少方法的嘗試,由於咱們獲取的數據是Html代碼,咱們很天然的會想到用WebView,可是用WebView來展現,咱們須要一個固定的樣式來控制頁面內容,否則會致使頁面格式沒法控制,好比文字的排布換行,圖片的大小控制,包括總體頁面的屏幕適配,因爲咱們獲取的只是部分Html代碼,因此會純在不少問題,而且有滑動卡頓(對於安卓來講,WebView原本就是個軟肋)。

  而後我嘗試着用Html類下的fromHtml方法來實現對頁面代碼的格式化,它是基於TextView的,發現滑動很流暢,文字大小也能夠控制的很好,但又有一個問題出現了,關於圖片的展現問題,雖然fromHtml提供了另一個包含ImageGetter的構造方法,可是在咱們經過異步獲取圖片的時候它不發預知圖片尺寸的大小,致使最後獲取出來的圖片會覆蓋了文字。

效果如圖:

  後來我嘗試的去GitHub上找找開源的組件發現了HtmlTextView:https://github.com/sufficientlysecure/html-textview,可是也不可以達到想要的效果,最後無奈的用了一個最笨的方法去作,就是在咱們獲取到Html格式數據的時候,咱們經過String的replace方法用正則表達式方式去判斷位置,好比<img/>標籤,而後經過添加換行符號<br/>來人工換行,這樣子看似沒什麼問題,可是圖片畢竟有不少,有大有小,也並非很完美的能夠解決問題。

  最後我以爲不該該老在安卓端裏去考慮問題,畢竟咱們的數據是從網絡獲取下來的,咱們對它們具備徹底的掌控權,爲啥不從Html代碼端去考慮問題的解決呢?而後我決定寫一個靜態的Html模板,對它作了移動端的屏幕適配,而後再把咱們獲取到的內容插入進去。(這裏而外再提一個方法,咱們也能夠經過Jsoup去解析Html代碼,而後去建立一個實體對象,把內容加入到List集合,而後再經過頁面展現)

  好了,看下個人Html靜態模板的實現:

這是Html模板:

 1 <html>
 2 <head>
 3     <title>Blog Content</title>
 4     <meta name="viewport"
 5           content="width=device-width, minimum-scale=0.5, initial-scale=1.2, maximum-scale=2.0, user-scalable=1"/>
 6     <link rel="stylesheet" type="text/css" href="css.css"/>
 7 
 8 </head>
 9 <body>
10 <div id="header">
11     <h3>
12         #title#
13     </h3>
14 
15     <div class="describe"><p/>#author#<p/>
16 
17         <div id="info">#info#<p/>#time#</div>
18     </div>
19 </div>
20 <div id="content">
21     #content#
22 </div>
23 </body>
24 </html>
BlogContent.html

這是Css文件:

 1 body{font-family:Helvetica,"Microsoft Yahei",Verdana,Helvetica,SimSun,Arial,"Arial Unicode MS",MingLiu,PMingLiu,"MS Gothic",sans-serief;margin:0;padding:0 8px;background-color:#efeff0;color:#333;word-wrap:break-word;}
 2 p{margin-top:0;margin-bottom:5pt;line-height: 1.6em;}  
 3 #header{text-align:center;background:transparent url('webBgLine.png') repeat-x scroll center bottom; padding-top:6pt;margin-bottom:5pt;-webkit-background-size:320px 2px;}
 4 #header h3{margin-bottom:0px; margin-top:5px;font-size:14pt;padding:0 5pt;color:#464646;line-height:1.3em;}
 5 .describe{color:#8e8e8e;font-size:12pt;padding:4pt 0; color:#333;}
 6 #info{ font-size:10pt;line-height:1.6; color:#787878;}
 7 #content{ font-size:12pt;line-height:1.8;}
 8 img{max-width:80%;height:auto;}
 9 div.bimg{text-align:center;padding:0;}
10 .photo_title{font-weight:bold;font-size:14pt;margin-top:15px;}
11 .langs_cn{color:#006200;}
12 audio{width:100%}
13 *{-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
14     /*-webkit-text-size-adjust: none;*/ /* prevent webkit from resizing text to fit */
15     -webkit-tap-highlight-color: rgba(0,0,0,0.15); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
16     /*-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
17 }
18 @media screen and (-webkit-device-pixel-ratio: 2) {
19     #header{background-image:transparent url('webBgLine@2x.png') repeat-x scroll center bottom;-webkit-background-size:320px 1px;}
20 }
Css.css

  這樣咱們就能夠經過Java端實現動態插入了,因爲是加載了靜態模板,滑動起來也不會出現卡頓。

1 InputStream inputStream = getAssets().open("NewsDetail.html");
2                     byte[] temp = AppUtil.readInputStream(inputStream);
3                     String content = new String(temp);
4                     mWebView.loadDataWithBaseURL("file:///android_asset/", content.replace("#title#", mBlog.getBlogTitle()).replace("#author#", "做者:" + mBlog.getAuthorName()).replace("#info#", "推薦:" + mBlog.getBlogDiggs() + "\t\t評論:" + mBlog.getBlogComments() + "\t\t瀏覽:" + mBlog.getBlogViews()).replace("#time#", TimeUtil.ParseDateToString(TimeUtil.ParseUTCDate(mBlog.getBlogPublished())))
5                             .replace("#content#", mInfo), "text/html", "utf-8", null);

 

  看下佈局文件,這裏用到了一個Material Design裏的FAB(Floating Action Button)浮動按鈕,這個控件很簡單,只須要設置對應的屬性,而後其餘用法和普通控件是保持一致的。

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:app="http://schemas.android.com/apk/res-auto"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:fitsSystemWindows="true"
 6     android:orientation="vertical">
 7 
 8     <!--ToolBar-->
 9     <include layout="@layout/activity_toolbar" />
10 
11 
12     <FrameLayout
13         android:layout_width="match_parent"
14         android:layout_height="match_parent">
15 
16         <WebView
17             android:id="@+id/wv_blog_content"
18             android:layout_width="match_parent"
19             android:layout_height="match_parent"
20             android:scrollbars="vertical"
21             />
22 
23         <ProgressBar
24             android:id="@+id/pb_bar"
25             style="@style/MyProgressBar"
26             android:layout_width="match_parent"
27             android:layout_height="wrap_content"
28             android:layout_gravity="center_vertical"
29             android:indeterminate="true" />
30 
31         <android.support.design.widget.FloatingActionButton
32             android:id="@+id/fab_comment"
33             android:layout_width="wrap_content"
34             android:layout_height="wrap_content"
35             android:layout_gravity="right|bottom"
36             android:layout_marginBottom="30dp"
37             android:layout_marginRight="20dp"
38             android:src="@mipmap/ic_star_outline_white_24dp"
39             app:backgroundTint="@color/md_green_600"
40             app:borderWidth="0dp"
41             app:elevation="8dp"
42             app:fabSize="normal"
43             app:pressedTranslationZ="12dp"
44             app:rippleColor="@color/md_green_800" />
45     </FrameLayout>
46 </LinearLayout>
BlogContent.xml

  這裏只是先簡單的一個圖片替換和Toast的顯示,具體操做等下篇文章咱們用到數據庫的時候再說。

 1         mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fab_comment);
 2 
 3         mFloatingActionButton.setOnClickListener(new View.OnClickListener() {
 4             @Override
 5             public void onClick(View v) {
 6                 if (!isLike) {
 7                     isLike = true;
 8                     mFloatingActionButton.setImageResource(R.mipmap.ic_grade_white_24dp);
 9                     Toast.makeText(BlogContentActivity.this, "文章已收藏", Toast.LENGTH_SHORT).show();
10                     //添加收藏文章到數據庫
11                 } else {
12                     isLike = false;
13                     mFloatingActionButton.setImageResource(R.mipmap.ic_star_outline_white_24dp);
14                     Toast.makeText(BlogContentActivity.this, "取消文章收藏", Toast.LENGTH_SHORT).show();
15                     //從數據庫刪除收藏文章
16                 }
17             }
18         });

  而後這裏是關於WebView的設置,你們也能夠參考這篇文章本身作設置:http://www.pedant.cn/2014/09/10/webview-optimize-points/#0-tsina-1-5518-397232819ff9a47a7b7e80a40613cfe1

 1 mWebView = (WebView) findViewById(R.id.wv_blog_content);
 2         //避免中文亂碼
 3         mWebView.getSettings().setDefaultTextEncodingName("utf-8");
 4         //適配低版本,關閉圖片自動加載
 5         if (Build.VERSION.SDK_INT >= 19) {
 6             mWebView.getSettings().setLoadsImagesAutomatically(true);
 7         } else {
 8             mWebView.getSettings().setLoadsImagesAutomatically(false);
 9         }
10         //等頁面加載完畢再加載圖片
11         WebViewClient webViewClient = new WebViewClient() {
12             @Override
13             public void onPageFinished(WebView view, String url) {
14                 //關閉Progress
15                 mProgressBar.setVisibility(View.GONE);
16                 if (!view.getSettings().getLoadsImagesAutomatically()) {
17                     view.getSettings().setLoadsImagesAutomatically(true);
18                 }
19             }
20         };
21         mWebView.setWebViewClient(webViewClient);
22         mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
23         mWebView.getSettings().setJavaScriptEnabled(false);
24         mWebView.getSettings().setSupportZoom(false);
25         mWebView.getSettings().setBuiltInZoomControls(false);
26         mWebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
27         mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);

 

三、關於評論詳情頁面的實現

  這裏是關於博文詳情的接口:http://wcf.open.cnblogs.com/blog/post/{POSTID}/comments/{PAGEINDEX}/{PAGESIZE} (POSTID表明文章Id,PAGEINDEX表明評論頁數,PAGESIZE表明評論每頁展現的條數)這裏不得不吐槽下接口的殘疾,都沒提供用戶頭像數據,只能用默認灰白頭像作了。

  這個就很簡單了,直接能夠複製咱們以前作首頁列表的XML佈局文件甚至是Fragment裏的主邏輯代碼,只須要作一下頁面內容的小改動就能夠了,下面直接給代碼。

博文評論主頁樣式:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:app="http://schemas.android.com/apk/res-auto"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:fitsSystemWindows="true"
 6     android:gravity="center"
 7     android:orientation="vertical">
 8 
 9     <!--ToolBar-->
10     <include layout="@layout/activity_toolbar" />
11     <android.support.v4.widget.SwipeRefreshLayout
12         android:id="@+id/swipe_refresh"
13         android:layout_width="match_parent"
14         android:layout_height="match_parent"
15         android:layout_margin="4dp">
16 
17         <android.support.v7.widget.RecyclerView
18             android:id="@+id/rv_view"
19             android:layout_width="match_parent"
20             android:layout_height="match_parent"
21             android:background="@color/md_grey_200"
22             android:scrollbars="vertical"
23             />
24     </android.support.v4.widget.SwipeRefreshLayout>
25 
26     <com.lcw.rabbit.myblog.view.MyProgressBar
27         android:id="@+id/progressbar"
28         android:layout_width="match_parent"
29         android:layout_height="20dp"
30         android:layout_gravity="bottom"
31         android:visibility="gone"
32         />
33 
34 
35 
36 </LinearLayout>
activity_blog_comment.xml

列表樣式和詳細內容樣式:

 1 <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:app="http://schemas.android.com/apk/res-auto"
 3     android:id="@+id/cv_cardview"
 4     android:layout_width="match_parent"
 5     android:layout_height="wrap_content"
 6     android:layout_margin="8dp"
 7     android:gravity="center"
 8     app:cardCornerRadius="6dp">
 9 
10     <include layout="@layout/recyclerview_item_blogcommentlist_content" />
11 
12 </android.support.v7.widget.CardView>
recyclerview_blogcommentlist.xml
 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:app="http://schemas.android.com/apk/res-auto"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content"
 5     android:background="?android:selectableItemBackground"
 6     android:orientation="horizontal"
 7     android:padding="3dp">
 8 
 9     <!--信息內容-->
10     <LinearLayout
11         android:layout_width="0dp"
12         android:layout_height="wrap_content"
13         android:layout_marginLeft="3dp"
14         android:layout_weight="1"
15         android:orientation="vertical">
16 
17         <LinearLayout
18             android:layout_width="wrap_content"
19             android:layout_height="wrap_content"
20             android:layout_marginLeft="3dp"
21             android:layout_weight="1"
22             android:padding="3dp"
23             android:orientation="horizontal">
24 
25             <!--頭像-->
26             <com.makeramen.roundedimageview.RoundedImageView
27                 android:id="@+id/iv_userhead"
28                 android:layout_width="25dp"
29                 android:layout_height="25dp"
30                 android:layout_gravity="center_vertical"
31                 android:layout_marginRight="5dp"
32                 android:src="@mipmap/avatar_default"
33                 app:riv_border_color="#ffffff"
34                 app:riv_border_width="2dip"
35                 app:riv_corner_radius="30dip"
36                 app:riv_mutate_background="true"
37                 app:riv_oval="true"
38                 app:riv_tile_mode="repeat" />
39 
40             <TextView
41                 android:id="@+id/tv_name"
42                 android:layout_width="match_parent"
43                 android:layout_height="wrap_content"
44                 android:layout_gravity="center_vertical"
45                 android:layout_marginTop="2dp"
46                 android:layout_weight="1"
47                 android:ellipsize="end"
48                 android:singleLine="true"
49 
50                 android:text="用戶暱稱"
51                 android:textColor="@color/md_green_700"
52                 android:textSize="16sp"
53                 android:textStyle="bold" />
54         </LinearLayout>
55 
56         <TextView
57             android:id="@+id/tv_comment"
58             android:layout_width="match_parent"
59             android:layout_height="wrap_content"
60             android:layout_weight="1"
61             android:maxLines="3"
62             android:layout_marginLeft="3dp"
63             android:text="文章評論內容"
64             android:textSize="16sp" />
65 
66         <LinearLayout
67             android:layout_width="match_parent"
68             android:layout_height="match_parent"
69             android:layout_margin="1dp"
70             android:layout_weight="1"
71             android:padding="3dp"
72             android:orientation="horizontal">
73 
74             <TextView
75                 android:layout_width="wrap_content"
76                 android:layout_height="match_parent"
77                 android:gravity="center_vertical"
78                 android:text="評論時間:"
79                 android:textColor="@color/md_grey_500"
80                 android:textSize="12sp" />
81 
82             <TextView
83                 android:id="@+id/tv_time"
84                 android:layout_width="wrap_content"
85                 android:layout_height="match_parent"
86                 android:layout_marginRight="5dp"
87                 android:gravity="center_vertical"
88                 android:textColor="@color/md_grey_500"
89                 android:textSize="12sp" />
90 
91         </LinearLayout>
92 
93     </LinearLayout>
94 
95 
96 </LinearLayout>
recyclerview_blogcommentlist_content.xml

主代碼:

  1 package com.lcw.rabbit.myblog;
  2 
  3 import android.os.Bundle;
  4 import android.support.v4.widget.SwipeRefreshLayout;
  5 import android.support.v7.app.AppCompatActivity;
  6 import android.support.v7.widget.DefaultItemAnimator;
  7 import android.support.v7.widget.LinearLayoutManager;
  8 import android.support.v7.widget.RecyclerView;
  9 import android.support.v7.widget.Toolbar;
 10 import android.view.View;
 11 
 12 import com.android.volley.Request;
 13 import com.android.volley.Response;
 14 import com.android.volley.VolleyError;
 15 import com.android.volley.toolbox.StringRequest;
 16 import com.lcw.rabbit.myblog.adapter.BlogCommentListAdapter;
 17 import com.lcw.rabbit.myblog.entity.Comment;
 18 import com.lcw.rabbit.myblog.parser.BlogCommentXmlParser;
 19 import com.lcw.rabbit.myblog.utils.VolleyRequestQueueManager;
 20 import com.lcw.rabbit.myblog.view.MyProgressBar;
 21 import com.mugen.Mugen;
 22 import com.mugen.MugenCallbacks;
 23 import com.mugen.attachers.BaseAttacher;
 24 
 25 import org.xmlpull.v1.XmlPullParserException;
 26 
 27 import java.io.ByteArrayInputStream;
 28 import java.io.IOException;
 29 import java.util.ArrayList;
 30 import java.util.List;
 31 
 32 /**
 33  * 博文評論頁
 34  */
 35 public class BlogCommentActivity extends AppCompatActivity {
 36     private Toolbar mToolbar;
 37     private SwipeRefreshLayout mSwipeRefreshLayout;
 38     private RecyclerView mRecyclerView;
 39     private BlogCommentListAdapter mBlogCommentListAdapter;
 40     //無限滾動
 41     private BaseAttacher mBaseAttacher;
 42     private MyProgressBar myProgressBar;
 43 
 44     private String mBlogId;
 45     private List<Comment> mComments;
 46 
 47     //默認第一頁
 48     private int currentPage = 1;
 49     //是否正在加載
 50     private boolean isLoading = false;
 51 
 52 
 53     @Override
 54     protected void onCreate(Bundle savedInstanceState) {
 55         super.onCreate(savedInstanceState);
 56         setContentView(R.layout.activity_blog_comment);
 57         initView();
 58         initData();
 59         initAction();
 60         getBlogComment(mBlogId, 1, 10);
 61     }
 62 
 63     private void initAction() {
 64         //設置下拉刷新
 65         mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
 66             @Override
 67             public void onRefresh() {
 68                 getBlogComment(mBlogId, 1, 10);
 69             }
 70         });
 71 
 72 
 73         //設置無限滾動,上拉加載
 74         mBaseAttacher = Mugen.with(mRecyclerView, new MugenCallbacks() {
 75             @Override
 76             public void onLoadMore() {
 77                 //加載更多
 78                 isLoading = true;
 79                 mBaseAttacher.setLoadMoreEnabled(false);
 80                 myProgressBar.setVisibility(View.VISIBLE);
 81                 getBlogComment(mBlogId, (currentPage + 1), 10);
 82             }
 83 
 84             @Override
 85             public boolean isLoading() {
 86                 return isLoading;
 87             }
 88 
 89             @Override
 90             public boolean hasLoadedAllItems() {
 91                 return isLoading;
 92             }
 93         }).start();
 94         //離底部一項的時候加載更多
 95         mBaseAttacher.setLoadMoreOffset(1);
 96     }
 97 
 98     /**
 99      * 獲取Intent傳遞過來的數據
100      */
101     private void initData() {
102         mBlogId = getIntent().getExtras().getString("blogId");
103         //設置空數據源
104         mComments=new ArrayList<Comment>();
105         mBlogCommentListAdapter = new BlogCommentListAdapter(this,mComments);
106         mRecyclerView.setAdapter(mBlogCommentListAdapter);
107     }
108 
109 
110     /**
111      * 獲取博客評論數據並設置
112      * @param blogId
113      * @param page
114      * @param num
115      */
116     private void getBlogComment(String blogId, final int page, int num) {
117         //更新當前頁數
118         currentPage = page;
119         StringRequest request = new StringRequest(Request.Method.GET, "http://wcf.open.cnblogs.com/blog/post/" + blogId + "/comments/" + page + "/" + num, new Response.Listener<String>() {
120             @Override
121             public void onResponse(String s) {
122                 try {
123                     //獲取評論數據數據並解析XML
124                     ByteArrayInputStream inputStream = new ByteArrayInputStream(s.getBytes());
125                     List<Comment> comments = BlogCommentXmlParser.getBlogComment(inputStream, "utf-8");
126                     if (page == 1) {
127                         //清空以前的數據預防重複加載
128                         mComments.clear();
129                     }
130                     for (Comment comment : comments) {
131                         //整理數據源
132                         mComments.add(comment);
133                     }
134 
135                     if (mBlogCommentListAdapter == null) {
136                         //若是Adapter不存在
137                         mBlogCommentListAdapter = new BlogCommentListAdapter(BlogCommentActivity.this,mComments);
138                         mRecyclerView.setAdapter(mBlogCommentListAdapter);
139                     } else {
140                         //存在通知adatper數據源更新
141                         mBlogCommentListAdapter.refreshData(mComments);
142 
143                     }
144                     //關閉下拉刷新樣式
145                     mSwipeRefreshLayout.setRefreshing(false);
146                     isLoading = false;
147                     myProgressBar.setVisibility(View.GONE);
148                     mBaseAttacher.setLoadMoreEnabled(true);
149 
150 
151                 } catch (XmlPullParserException e) {
152                     e.printStackTrace();
153                 } catch (IOException e) {
154                     e.printStackTrace();
155                 }
156             }
157         }, new Response.ErrorListener() {
158             @Override
159             public void onErrorResponse(VolleyError volleyError) {
160 
161             }
162         });
163         VolleyRequestQueueManager.addRequest(request, "BlogCommentList");
164 
165     }
166 
167     private void initView() {
168         mToolbar = (Toolbar) findViewById(R.id.activity_toolbar);
169         mToolbar.setTitle("文章評論");
170         setSupportActionBar(mToolbar);
171         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
172 
173         mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
174         //設置拉下刷新滾動條顏色
175         mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);
176         mRecyclerView = (RecyclerView) findViewById(R.id.rv_view);
177         mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
178         mRecyclerView.setItemAnimator(new DefaultItemAnimator());
179         myProgressBar = (MyProgressBar)findViewById(R.id.progressbar);
180 
181 
182     }
183 
184 
185 }

適配器代碼:

  1 package com.lcw.rabbit.myblog.adapter;
  2 
  3 import android.content.Context;
  4 import android.content.res.Resources;
  5 import android.graphics.Bitmap;
  6 import android.graphics.BitmapFactory;
  7 import android.support.v7.widget.RecyclerView;
  8 import android.text.Html;
  9 import android.view.LayoutInflater;
 10 import android.view.View;
 11 import android.view.ViewGroup;
 12 import android.widget.TextView;
 13 
 14 import com.lcw.rabbit.myblog.R;
 15 import com.lcw.rabbit.myblog.entity.Comment;
 16 import com.lcw.rabbit.myblog.utils.TimeUtil;
 17 import com.makeramen.roundedimageview.RoundedImageView;
 18 
 19 import java.util.List;
 20 
 21 /**
 22  * 推薦博文評論列表適配器
 23  * Created by Lichenwei
 24  * Date: 2015-08-16
 25  * Time: 22:34
 26  */
 27 public class BlogCommentListAdapter extends RecyclerView.Adapter<BlogCommentListAdapter.RecyclerViewViewHolder> {
 28 
 29     private Context mContext;
 30     private List<Comment> mComments;
 31 
 32     public BlogCommentListAdapter(Context context, List<Comment> comments) {
 33         this.mContext = context;
 34         this.mComments = comments;
 35     }
 36 
 37     /**
 38      * 設置新的數據源,提醒adatper更新
 39      *
 40      * @param comments
 41      */
 42     public void refreshData(List<Comment> comments) {
 43         this.mComments = comments;
 44         this.notifyDataSetChanged();
 45     }
 46 
 47     /**
 48      * 建立ViewHolder
 49      *
 50      * @param viewGroup
 51      * @param i
 52      * @return
 53      */
 54     @Override
 55     public RecyclerViewViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
 56         View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_item_blogcommentlist, viewGroup, false);
 57         return new RecyclerViewViewHolder(view);
 58     }
 59 
 60     /**
 61      * 根據資源ID返回Bitmap對象
 62      *
 63      * @param resId
 64      * @return
 65      */
 66     public Bitmap getBitmapFromRes(int resId) {
 67         Resources res = mContext.getResources();
 68         return BitmapFactory.decodeResource(res, resId);
 69 
 70     }
 71 
 72     /**
 73      * 綁定數據
 74      *
 75      * @param viewholder
 76      * @param i
 77      */
 78     @Override
 79     public void onBindViewHolder(RecyclerViewViewHolder viewholder, int i) {
 80         //設置頭像
 81 //        if (mAuthors.get(i).getAuthorPic() != null && !"".equals(mAuthors.get(i).getAuthorPic())) {
 82 //            ImageCacheManager.loadImage(mAuthors.get(i).getAuthorPic(), viewholder.mUserhead, getBitmapFromRes(R.mipmap.avatar_default), getBitmapFromRes(R.mipmap.avatar_default));
 83 //        } else {
 84 //            viewholder.mUserhead.setImageResource(R.mipmap.avatar_default);
 85 //        }
 86         viewholder.mName.setText(mComments.get(i).getAuthorName());
 87         //處理評論內容裏的Html代碼
 88         viewholder.mContent.setText(Html.fromHtml(mComments.get(i).getCommentContent()));
 89         //處理日期特殊格式
 90         viewholder.mTime.setText(TimeUtil.DateToChineseString(TimeUtil.ParseUTCDate(mComments.get(i).getCommentTime())));
 91     }
 92 
 93     @Override
 94     public int getItemCount() {
 95         return mComments.size();
 96     }
 97 
 98     /**
 99      * 自定義ViewHolder
100      */
101     public static class RecyclerViewViewHolder extends RecyclerView.ViewHolder {
102         private RoundedImageView mUserhead;
103         private TextView mName;
104         private TextView mContent;
105         private TextView mTime;
106 
107         public RecyclerViewViewHolder(View view) {
108             super(view);
109             mUserhead = (RoundedImageView) view.findViewById(R.id.iv_userhead);
110             mName = (TextView) view.findViewById(R.id.tv_name);
111             mContent = (TextView) view.findViewById(R.id.tv_comment);
112             mTime = (TextView) view.findViewById(R.id.tv_time);
113 
114         }
115 
116 
117     }
118 }

獲取博文詳情XML解析:

 1 package com.lcw.rabbit.myblog.parser;
 2 
 3 import com.lcw.rabbit.myblog.entity.Comment;
 4 
 5 import org.xmlpull.v1.XmlPullParser;
 6 import org.xmlpull.v1.XmlPullParserException;
 7 import org.xmlpull.v1.XmlPullParserFactory;
 8 
 9 import java.io.IOException;
10 import java.io.InputStream;
11 import java.util.ArrayList;
12 import java.util.List;
13 
14 /**
15  * 對博文評論頁xml數據的解析
16  * Created by Lichenwei
17  * Date: 2015-08-17
18  * Time: 13:32
19  */
20 public class BlogCommentXmlParser {
21 
22 
23     /**
24      * 用於解析博文評論詳情的xml,返回Avatar的List集合對象
25      *
26      * @param inputStream
27      * @param encode
28      * @return
29      * @throws XmlPullParserException
30      * @throws IOException
31      */
32     public static List<Comment> getBlogComment(InputStream inputStream, String encode) throws XmlPullParserException, IOException {
33         List<Comment> mComments = null;
34         Comment mComment = null;
35 
36         //獲取XmlPullParser實例
37         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
38         XmlPullParser parser = factory.newPullParser();
39         parser.setInput(inputStream, encode);
40         //獲取解析事件
41         int eventType = parser.getEventType();
42         //當xml文檔未到尾端時
43         while (eventType != XmlPullParser.END_DOCUMENT) {
44             switch (eventType) {
45                 //解析根標籤的時候,實例化集合
46                 case XmlPullParser.START_DOCUMENT:
47                     mComments = new ArrayList<Comment>();
48                     mComment = new Comment();
49                     break;
50                 case XmlPullParser.START_TAG:
51                     //當解析到entry標籤的時候,實例化Blog對象
52                     if ("entry".equals(parser.getName())) {
53                         mComment = new Comment();
54                     }
55                     if ("id".equals(parser.getName())) {
56                         parser.next();
57                         mComment.setCommentId(parser.getText());
58                     } else if ("published".equals(parser.getName())) {
59                         parser.next();
60                         mComment.setCommentTime(parser.getText());
61                     } else if ("name".equals(parser.getName())) {
62                         parser.next();
63                         mComment.setAuthorName(parser.getText());
64                     } else if ("uri".equals(parser.getName())) {
65                         parser.next();
66                         mComment.setAuthorUrl(parser.getText());
67                     } else if ("content".equals(parser.getName())) {
68                         parser.next();
69                         mComment.setCommentContent(parser.getText());
70                     }
71                     break;
72                 case XmlPullParser.END_TAG:
73                     //當解析到entry標籤結束的時候添加入Blogs集合,清空Blog對象
74                     if ("entry".equals(parser.getName())) {
75                         mComments.add(mComment);
76                         mComment = null;
77                     }
78                     break;
79 
80             }
81             //手動跳轉第一次遍歷
82             eventType = parser.next();
83         }
84 
85         return mComments;
86 
87     }
88 }

 

好了,今天先寫到這裏,改天繼續更新,有什麼建議或疑問,能夠在文章評論給我留言。

 

接下篇:《安卓開發筆記——打造屬於本身的博客園APP(四)

 

做者:李晨瑋
出處:http://www.cnblogs.com/lichenwei/本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,往後必有一番做爲!旁邊有「推薦」二字,你就順手把它點了吧,相得準,我分文不收;相不許,你也好回來找我!

相關文章
相關標籤/搜索