在上一篇文章《安卓開發筆記——打造屬於本身的博客園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>
這是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 }
這樣咱們就能夠經過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>
這裏只是先簡單的一個圖片替換和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>
列表樣式和詳細內容樣式:
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>
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>
主代碼:
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/本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。正在看本人博客的這位童鞋,我看你氣度不凡,談吐間隱隱有王者之氣,往後必有一番做爲!旁邊有「推薦」二字,你就順手把它點了吧,相得準,我分文不收;相不許,你也好回來找我!