实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇)

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24022165

今天给大家带来CSDN的完结篇,即加入文章的查看和文章中图片的保存~

今天的目标:


首先是对控件使用的考虑,既然是网络上的文章,可能首先想到的就是webview,这里直接把页面载入到webview中是肯定不行的,首先得把页面上的数据解析,然后可能需要一个html的模版,然后把数据填充到模版,再将模版用于webview的展示。想了想,还是不是很方面,因为不确定文章中的段落、图片的数量和位置。所以最终照着网络上流传的版本使用List实现。

思路:把页面上的数据解析成 标题、摘要、段落(*)、图片(*),自定以一个对象,解析完成后生成一个List,当然顺序一定要和原文的一直。然后针对标题、摘要、段落、图片各做一个List的item的布局,最终显示。

好了,先简单看下csdn文章页的html:

实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇)_第1张图片

我们在原先的代表上,添加对这样html页面的解析:

首先是封装的对象:

[java]  view plain copy
  1. package com.zhy.bean;  
  2.   
  3. import java.util.List;  
  4.   
  5. public class NewsDto  
  6. {  
  7.     private List newses;   
  8.     private String nextPageUrl ;  
  9.     public List getNewses()  
  10.     {  
  11.         return newses;  
  12.     }  
  13.     public void setNewses(List newses)  
  14.     {  
  15.         this.newses = newses;  
  16.     }  
  17.     public String getNextPageUrl()  
  18.     {  
  19.         return nextPageUrl;  
  20.     }  
  21.     public void setNextPageUrl(String nextPageUrl)  
  22.     {  
  23.         this.nextPageUrl = nextPageUrl;  
  24.     }   
  25.       
  26.       
  27. }  



[java]  view plain copy
  1. package com.zhy.bean;  
  2.   
  3. public class News  
  4. {  
  5.   
  6.     public static interface NewsType  
  7.     {  
  8.         public static final int TITLE = 1;  
  9.         public static final int SUMMARY = 2;  
  10.         public static final int CONTENT = 3;  
  11.         public static final int IMG = 4;  
  12.         public static final int BOLD_TITLE = 5;  
  13.     }  
  14.   
  15.     /** 
  16.      * 标题 
  17.      */  
  18.     private String title;  
  19.     /** 
  20.      * 摘要 
  21.      */  
  22.     private String summary;  
  23.     /** 
  24.      * 内容 
  25.      */  
  26.     private String content;  
  27.   
  28.     /** 
  29.      * 图片链接 
  30.      */  
  31.     private String imageLink;  
  32.   
  33.     /** 
  34.      * 类型 
  35.      */  
  36.     private int type;  
  37.   
  38.     public String getTitle()  
  39.     {  
  40.         return title;  
  41.     }  
  42.   
  43.     public void setTitle(String title)  
  44.     {  
  45.         this.title = title;  
  46.     }  
  47.   
  48.     public String getSummary()  
  49.     {  
  50.         return summary;  
  51.     }  
  52.   
  53.     public void setSummary(String summary)  
  54.     {  
  55.         this.summary = summary;  
  56.         this.type = NewsType.SUMMARY;  
  57.     }  
  58.   
  59.     public String getContent()  
  60.     {  
  61.         return content;  
  62.     }  
  63.   
  64.     public void setContent(String content)  
  65.     {  
  66.         this.content = content;  
  67.     }  
  68.   
  69.     public String getImageLink()  
  70.     {  
  71.         return imageLink;  
  72.     }  
  73.   
  74.     public void setImageLink(String imageLink)  
  75.     {  
  76.         this.imageLink = imageLink;  
  77.         this.type = NewsType.IMG;  
  78.   
  79.     }  
  80.   
  81.     public int getType()  
  82.     {  
  83.         return type;  
  84.     }  
  85.   
  86.     public void setType(int type)  
  87.     {  
  88.         this.type = type;  
  89.     }  
  90.   
  91.     @Override  
  92.     public String toString()  
  93.     {  
  94.         return "News [title=" + title + ", summary=" + summary + ", content=" + content + ", imageLink=" + imageLink  
  95.                 + ", type=" + type + "]";  
  96.     }  
  97.       
  98.       
  99.   
  100. }  
添加了一个新的业务方法,把html字符串转化为List对象:

[java]  view plain copy
  1. /** 
  2.      * 根据文章的url返回一个NewsDto对象 
  3.      *  
  4.      * @return 
  5.      * @throws CommonException 
  6.      */  
  7.     public NewsDto getNews(String urlStr) throws CommonException  
  8.     {  
  9.         NewsDto newsDto = new NewsDto();  
  10.         List newses = new ArrayList();  
  11.         String htmlStr = DataUtil.doGet(urlStr);  
  12.         Document doc = Jsoup.parse(htmlStr);  
  13.   
  14.         // 获得文章中的第一个detail  
  15.         Element detailEle = doc.select(".left .detail").get(0);  
  16.         // 标题  
  17.         Element titleEle = detailEle.select("h1.title").get(0);  
  18.         News news = new News();  
  19.         news.setTitle(titleEle.text());  
  20.         news.setType(NewsType.TITLE);  
  21.         newses.add(news);  
  22.         // 摘要  
  23.         Element summaryEle = detailEle.select("div.summary").get(0);  
  24.         news = new News();  
  25.         news.setSummary(summaryEle.text());  
  26.         newses.add(news);  
  27.         // 内容  
  28.         Element contentEle = detailEle.select("div.con.news_content").get(0);  
  29.         Elements childrenEle = contentEle.children();  
  30.   
  31.         for (Element child : childrenEle)  
  32.         {  
  33.             Elements imgEles = child.getElementsByTag("img");  
  34.             // 图片  
  35.             if (imgEles.size() > 0)  
  36.             {  
  37.                 for (Element imgEle : imgEles)  
  38.                 {  
  39.                     if (imgEle.attr("src").equals(""))  
  40.                         continue;  
  41.                     news = new News();  
  42.                     news.setImageLink(imgEle.attr("src"));  
  43.                     newses.add(news);  
  44.                 }  
  45.             }  
  46.             // 移除图片  
  47.             imgEles.remove();  
  48.   
  49.             if (child.text().equals(""))  
  50.                 continue;  
  51.               
  52.             news = new News();  
  53.             news.setType(NewsType.CONTENT);  
  54.               
  55.             try  
  56.             {  
  57.                 if(child.children().size()==1)  
  58.                 {  
  59.                     Element cc = child.child(0);  
  60.                     if(cc.tagName().equals("b"))  
  61.                     {  
  62.                         news.setType(NewsType.BOLD_TITLE);  
  63.                     }  
  64.                 }  
  65.                   
  66.             } catch (IndexOutOfBoundsException e)  
  67.             {  
  68.                 e.printStackTrace();  
  69.             }  
  70.             news.setContent(child.outerHtml());  
  71.             newses.add(news);  
  72.         }  
  73.         newsDto.setNewses(newses);  
  74.         return newsDto;  
  75.     }  
测试代码:

[java]  view plain copy
  1. @org.junit.Test  
  2.     public void test02()  
  3.     {  
  4.         NewsItemBiz biz = new NewsItemBiz();  
  5.         try  
  6.         {  
  7.             NewsDto newsDto = biz.getNews("http://www.csdn.net/article/2014-04-17/2819363-all-about-ddos");  
  8.               
  9.             List newses = newsDto.getNewses();  
  10.             for(News news : newses)  
  11.             {  
  12.                 System.out.println(news);  
  13.                   
  14.             }             
  15.           
  16.             System.out.println("-----");  
  17.             System.out.println(newsDto.getNextPageUrl());;  
  18.         } catch (CommonException e)  
  19.         {  
  20.             // TODO Auto-generated catch block  
  21.             e.printStackTrace();  
  22.         }  
  23.     }  

然后我们可以拿到这样的结果数据:

实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇)_第2张图片


好了,现在准备把解析完成的数据用到我们的app上。

上一教程已经完成了Xlist的显示,上拉与下拉,现在给它添加OnItemClickListener:

[java]  view plain copy
  1. mXListView.setOnItemClickListener(new OnItemClickListener()  
  2.         {  
  3.             @Override  
  4.             public void onItemClick(AdapterView parent, View view, int position, long id)  
  5.             {  
  6.                 NewsItem newsItem = mDatas.get(position-1);  
  7.                 Intent intent = new Intent(getActivity(), NewsContentActivity.class);  
  8.                 intent.putExtra("url", newsItem.getLink());  
  9.                 startActivity(intent);  
  10.             }  
  11.   
  12.         });  

到达显示内容的Activity页面:

[java]  view plain copy
  1. package com.zhy.csdndemo;  
  2.   
  3. import java.util.List;  
  4.   
  5. import me.maxwin.view.IXListViewLoadMore;  
  6. import me.maxwin.view.XListView;  
  7. import android.app.Activity;  
  8. import android.content.Intent;  
  9. import android.os.AsyncTask;  
  10. import android.os.Bundle;  
  11. import android.os.Looper;  
  12. import android.view.View;  
  13. import android.widget.AdapterView;  
  14. import android.widget.Toast;  
  15. import android.widget.AdapterView.OnItemClickListener;  
  16. import android.widget.ProgressBar;  
  17.   
  18. import com.zhy.bean.CommonException;  
  19. import com.zhy.bean.News;  
  20. import com.zhy.biz.NewsItemBiz;  
  21. import com.zhy.csdndemo.adapter.NewContentAdapter;  
  22.   
  23. public class NewsContentActivity extends Activity implements IXListViewLoadMore  
  24. {  
  25.   
  26.     private XListView mListView;  
  27.   
  28.     /** 
  29.      * 该页面的url 
  30.      */  
  31.     private String url;  
  32.     private NewsItemBiz mNewsItemBiz;  
  33.     private List mDatas;  
  34.   
  35.     private ProgressBar mProgressBar;  
  36.     private NewContentAdapter mAdapter;  
  37.   
  38.     @Override  
  39.     protected void onCreate(Bundle savedInstanceState)  
  40.     {  
  41.         super.onCreate(savedInstanceState);  
  42.         setContentView(R.layout.news_content);  
  43.   
  44.         mNewsItemBiz = new NewsItemBiz();  
  45.   
  46.         Bundle extras = getIntent().getExtras();  
  47.         url = extras.getString("url");  
  48.   
  49.         mAdapter = new NewContentAdapter(this);  
  50.           
  51.         mListView = (XListView) findViewById(R.id.id_listview);  
  52.         mProgressBar = (ProgressBar) findViewById(R.id.id_newsContentPro);  
  53.   
  54.         mListView.setAdapter(mAdapter);  
  55.         mListView.disablePullRefreash();  
  56.         mListView.setPullLoadEnable(this);  
  57.           
  58.         mListView.setOnItemClickListener(new OnItemClickListener()  
  59.         {  
  60.             @Override  
  61.             public void onItemClick(AdapterView parent, View view, int position, long id)  
  62.             {  
  63.                   
  64.                 News news = mDatas.get(position - 1);  
  65.                 String imageLink = news.getImageLink();  
  66.                 //Toast.makeText(NewContentActivity.this, imageLink, 1).show();  
  67.                 Intent intent = new Intent(NewsContentActivity.this,ImageShowActivity.class);  
  68.                 intent.putExtra("url", imageLink);  
  69.                 startActivity(intent);  
  70.             }  
  71.         });  
  72.           
  73.         mProgressBar.setVisibility(View.VISIBLE);  
  74.         new LoadDataTask().execute();  
  75.   
  76.     }  
  77.   
  78.     @Override  
  79.     public void onLoadMore()  
  80.     {  
  81.   
  82.     }  
  83.   
  84.     class LoadDataTask extends AsyncTask  
  85.     {  
  86.   
  87.           
  88.           
  89.         @Override  
  90.         protected Void doInBackground(Void... params)  
  91.         {  
  92.             try  
  93.             {  
  94.                 mDatas = mNewsItemBiz.getNews(url).getNewses();  
  95.             } catch (CommonException e)  
  96.             {  
  97.                 Looper.prepare();  
  98.                 Toast.makeText(getApplicationContext(), e.getMessage(), 1).show();  
  99.                 Looper.loop();  
  100.             }  
  101.   
  102.             return null;  
  103.         }  
  104.   
  105.         @Override  
  106.         protected void onPostExecute(Void result)  
  107.         {  
  108.             if(mDatas == null)  
  109.                 return ;   
  110.             mAdapter.addList(mDatas);  
  111.             mAdapter.notifyDataSetChanged();  
  112.             mProgressBar.setVisibility(View.GONE);  
  113.         }  
  114.   
  115.     }  
  116.       
  117.     /** 
  118.      * 点击返回按钮 
  119.      * @param view 
  120.      */  
  121.     public void back(View view)  
  122.     {  
  123.         finish();  
  124.     }  
  125.   
  126. }  

接下来看这个Activity中ListView的Adapter

[java]  view plain copy
  1. package com.zhy.csdndemo.adapter;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.content.Context;  
  7. import android.graphics.Bitmap;  
  8. import android.text.Html;  
  9. import android.util.Log;  
  10. import android.view.LayoutInflater;  
  11. import android.view.View;  
  12. import android.view.ViewGroup;  
  13. import android.widget.BaseAdapter;  
  14. import android.widget.ImageView;  
  15. import android.widget.TextView;  
  16.   
  17. import com.nostra13.universalimageloader.core.DisplayImageOptions;  
  18. import com.nostra13.universalimageloader.core.ImageLoader;  
  19. import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;  
  20. import com.nostra13.universalimageloader.core.assist.ImageScaleType;  
  21. import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;  
  22. import com.zhy.bean.News;  
  23. import com.zhy.bean.News.NewsType;  
  24. import com.zhy.csdndemo.R;  
  25.   
  26. public class NewContentAdapter extends BaseAdapter  
  27. {  
  28.     private LayoutInflater mInflater;  
  29.     private List mDatas = new ArrayList();  
  30.   
  31.     private ImageLoader imageLoader = ImageLoader.getInstance();  
  32.     private DisplayImageOptions options;  
  33.   
  34.     public NewContentAdapter(Context context)  
  35.     {  
  36.         mInflater = LayoutInflater.from(context);  
  37.   
  38.         imageLoader.init(ImageLoaderConfiguration.createDefault(context));  
  39.         options = new DisplayImageOptions.Builder().showStubImage(R.drawable.images)  
  40.                 .showImageForEmptyUri(R.drawable.images).showImageOnFail(R.drawable.images).cacheInMemory()  
  41.                 .cacheOnDisc().imageScaleType(ImageScaleType.EXACTLY).bitmapConfig(Bitmap.Config.RGB_565)  
  42.                 .displayer(new FadeInBitmapDisplayer(300)).build();  
  43.     }  
  44.   
  45.     public void addList(List datas)  
  46.     {  
  47.         mDatas.addAll(datas);  
  48.     }  
  49.   
  50.     @Override  
  51.     public int getCount()  
  52.     {  
  53.         return mDatas.size();  
  54.     }  
  55.   
  56.     @Override  
  57.     public Object getItem(int position)  
  58.     {  
  59.         return mDatas.get(position);  
  60.     }  
  61.   
  62.     @Override  
  63.     public long getItemId(int position)  
  64.     {  
  65.         return position;  
  66.     }  
  67.   
  68.     @Override  
  69.     public int getItemViewType(int position)  
  70.     {  
  71.         switch (mDatas.get(position).getType())  
  72.         {  
  73.         case NewsType.TITLE:  
  74.             return 0;  
  75.         case NewsType.SUMMARY:  
  76.             return 1;  
  77.         case NewsType.CONTENT:  
  78.             return 2;  
  79.         case NewsType.IMG:  
  80.             return 3;  
  81.         case NewsType.BOLD_TITLE:  
  82.             return 4;  
  83.         }  
  84.         return -1;  
  85.     }  
  86.   
  87.     @Override  
  88.     public int getViewTypeCount()  
  89.     {  
  90.         return 5;  
  91.     }  
  92.   
  93.     @Override  
  94.     public boolean isEnabled(int position)  
  95.     {  
  96.         switch (mDatas.get(position).getType())  
  97.         {  
  98.         case NewsType.IMG:  
  99.             return true;  
  100.         default:  
  101.             return false;  
  102.         }  
  103.     }  
  104.   
  105.     @Override  
  106.     public View getView(int position, View convertView, ViewGroup parent)  
  107.     {  
  108.         News news = mDatas.get(position); // 获取当前项数据  
  109.   
  110.         Log.e("xxx", news.toString());  
  111.   
  112.         ViewHolder holder = null;  
  113.         if (null == convertView)  
  114.         {  
  115.             holder = new ViewHolder();  
  116.             switch (news.getType())  
  117.             {  
  118.             case NewsType.TITLE:  
  119.                 convertView = mInflater.inflate(R.layout.news_content_title_item, null);  
  120.                 holder.mTextView = (TextView) convertView.findViewById(R.id.text);  
  121.                 break;  
  122.             case NewsType.SUMMARY:  
  123.                 convertView = mInflater.inflate(R.layout.news_content_summary_item, null);  
  124.                 holder.mTextView = (TextView) convertView.findViewById(R.id.text);  
  125.                 break;  
  126.             case NewsType.CONTENT:  
  127.                 convertView = mInflater.inflate(R.layout.news_content_item, null);  
  128.                 holder.mTextView = (TextView) convertView.findViewById(R.id.text);  
  129.                 break;  
  130.             case NewsType.IMG:  
  131.                 convertView = mInflater.inflate(R.layout.news_content_img_item, null);  
  132.                 holder.mImageView = (ImageView) convertView.findViewById(R.id.imageView);  
  133.                 break;  
  134.             case NewsType.BOLD_TITLE:  
  135.                 convertView = mInflater.inflate(R.layout.news_content_bold_title_item, null);  
  136.                 holder.mTextView = (TextView) convertView.findViewById(R.id.text);  
  137.                 break;  
  138.             }  
  139.             convertView.setTag(holder);  
  140.         } else  
  141.         {  
  142.             holder = (ViewHolder) convertView.getTag();  
  143.         }  
  144.   
  145.         if (null != news)  
  146.         {  
  147.             switch (news.getType())  
  148.             {  
  149.             case NewsType.IMG:  
  150.                 imageLoader.displayImage(news.getImageLink(), holder.mImageView, options);  
  151.                 break;  
  152.             case NewsType.TITLE:  
  153.                 holder.mTextView.setText(news.getTitle());  
  154.                 break;  
  155.             case NewsType.SUMMARY:  
  156.                 holder.mTextView.setText(news.getSummary());  
  157.                 break;  
  158.             case NewsType.CONTENT:  
  159.                 holder.mTextView.setText("\u3000\u3000"+Html.fromHtml(news.getContent()));  
  160.                 break;  
  161.             case NewsType.BOLD_TITLE:  
  162.                 holder.mTextView.setText("\u3000\u3000"+Html.fromHtml(news.getContent()));  
  163.             default:  
  164.   
  165.                 // holder.mTextView.setText(Html.fromHtml(item.getContent(),  
  166.                 // null, new MyTagHandler()));  
  167.                 // holder.content.setText(Html.fromHtml("
      加粗sdfsdf
        ",  
      •                 // null, new MyTagHandler()));  
      •                 break;  
      •             }  
      •         }  
      •         return convertView;  
      •     }  
      •   
      •     private final class ViewHolder  
      •     {  
      •         TextView mTextView;  
      •         ImageView mImageView;  
      •     }  
      • }  

我们复写了getViewTypeCount , getItemViewType ,isEnabled 因为我们的item的样式不止一种,且为显示图片的那个Item让它可以点击。

最后就是图片展示的Activity:

[java]  view plain copy
  1. package com.zhy.csdndemo;  
  2.   
  3. import android.app.Activity;  
  4. import android.graphics.Bitmap;  
  5. import android.os.AsyncTask;  
  6. import android.os.Bundle;  
  7. import android.view.View;  
  8. import android.widget.ProgressBar;  
  9. import android.widget.Toast;  
  10.   
  11. import com.polites.android.GestureImageView;  
  12. import com.zhy.csdndemo.util.FileUtil;  
  13. import com.zhy.csdndemo.util.Http;  
  14.   
  15. public class ImageShowActivity extends Activity  
  16. {  
  17.   
  18.     private String url;  
  19.     private ProgressBar mLoading;  
  20.     private GestureImageView mGestureImageView;  
  21.     private Bitmap mBitmap;  
  22.   
  23.     @Override  
  24.     protected void onCreate(Bundle savedInstanceState)  
  25.     {  
  26.         super.onCreate(savedInstanceState);  
  27.         setContentView(R.layout.activity_image_page);  
  28.   
  29.         // 拿到图片的链接  
  30.         url = getIntent().getExtras().getString("url");  
  31.         mLoading = (ProgressBar) findViewById(R.id.loading);  
  32.         mGestureImageView = (GestureImageView) findViewById(R.id.image);  
  33.   
  34.         new DownloadImgTask().execute();  
  35.   
  36.     }  
  37.   
  38.     /** 
  39.      * 点击返回按钮 
  40.      *  
  41.      * @param view 
  42.      */  
  43.     public void back(View view)  
  44.     {  
  45.         finish();  
  46.     }  
  47.   
  48.     /** 
  49.      * 点击下载按钮 
  50.      *  
  51.      * @param view 
  52.      */  
  53.     public void downloadImg(View view)  
  54.     {  
  55.         mGestureImageView.setDrawingCacheEnabled(true);  
  56.         if (FileUtil.writeSDcard(url, mGestureImageView.getDrawingCache()))  
  57.         {  
  58.             Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show();  
  59.         } else  
  60.         {  
  61.             Toast.makeText(getApplicationContext(), "保存失败", Toast.LENGTH_SHORT).show();  
  62.         }  
  63.         mGestureImageView.setDrawingCacheEnabled(false);  
  64.     }  
  65.   
  66.     class DownloadImgTask extends AsyncTask  
  67.     {  
  68.         @Override  
  69.         protected Void doInBackground(Void... params)  
  70.         {  
  71.             mBitmap = Http.HttpGetBmp(url);  
  72.             return null;  
  73.         }  
  74.   
  75.         @Override  
  76.         protected void onPostExecute(Void result)  
  77.         {  
  78.             mGestureImageView.setImageBitmap(mBitmap);  
  79.             mLoading.setVisibility(View.GONE);  
  80.             super.onPostExecute(result);  
  81.         }  
  82.   
  83.     }  
  84. }  
好了,省略了一些辅助类的方法和布局文件。下面看下效果。

好了,上传文件限制2M,没办法录太多。



源码点击此处下载

你可能感兴趣的:(实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇))