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

来源:互联网 发布:河北工业大学知乎 编辑:程序博客网 时间:2024/05/19 18:12

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

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

今天的目标:


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

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

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

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

首先是封装的对象:

package com.zhy.bean;import java.util.List;public class NewsDto{private List<News> newses; private String nextPageUrl ;public List<News> getNewses(){return newses;}public void setNewses(List<News> newses){this.newses = newses;}public String getNextPageUrl(){return nextPageUrl;}public void setNextPageUrl(String nextPageUrl){this.nextPageUrl = nextPageUrl;} }



package com.zhy.bean;public class News{public static interface NewsType{public static final int TITLE = 1;public static final int SUMMARY = 2;public static final int CONTENT = 3;public static final int IMG = 4;public static final int BOLD_TITLE = 5;}/** * 标题 */private String title;/** * 摘要 */private String summary;/** * 内容 */private String content;/** * 图片链接 */private String imageLink;/** * 类型 */private int type;public String getTitle(){return title;}public void setTitle(String title){this.title = title;}public String getSummary(){return summary;}public void setSummary(String summary){this.summary = summary;this.type = NewsType.SUMMARY;}public String getContent(){return content;}public void setContent(String content){this.content = content;}public String getImageLink(){return imageLink;}public void setImageLink(String imageLink){this.imageLink = imageLink;this.type = NewsType.IMG;}public int getType(){return type;}public void setType(int type){this.type = type;}@Overridepublic String toString(){return "News [title=" + title + ", summary=" + summary + ", content=" + content + ", imageLink=" + imageLink+ ", type=" + type + "]";}}
添加了一个新的业务方法,把html字符串转化为List对象:

/** * 根据文章的url返回一个NewsDto对象 *  * @return * @throws CommonException */public NewsDto getNews(String urlStr) throws CommonException{NewsDto newsDto = new NewsDto();List<News> newses = new ArrayList<News>();String htmlStr = DataUtil.doGet(urlStr);Document doc = Jsoup.parse(htmlStr);// 获得文章中的第一个detailElement detailEle = doc.select(".left .detail").get(0);// 标题Element titleEle = detailEle.select("h1.title").get(0);News news = new News();news.setTitle(titleEle.text());news.setType(NewsType.TITLE);newses.add(news);// 摘要Element summaryEle = detailEle.select("div.summary").get(0);news = new News();news.setSummary(summaryEle.text());newses.add(news);// 内容Element contentEle = detailEle.select("div.con.news_content").get(0);Elements childrenEle = contentEle.children();for (Element child : childrenEle){Elements imgEles = child.getElementsByTag("img");// 图片if (imgEles.size() > 0){for (Element imgEle : imgEles){if (imgEle.attr("src").equals(""))continue;news = new News();news.setImageLink(imgEle.attr("src"));newses.add(news);}}// 移除图片imgEles.remove();if (child.text().equals(""))continue;news = new News();news.setType(NewsType.CONTENT);try{if(child.children().size()==1){Element cc = child.child(0);if(cc.tagName().equals("b")){news.setType(NewsType.BOLD_TITLE);}}} catch (IndexOutOfBoundsException e){e.printStackTrace();}news.setContent(child.outerHtml());newses.add(news);}newsDto.setNewses(newses);return newsDto;}
测试代码:

@org.junit.Testpublic void test02(){NewsItemBiz biz = new NewsItemBiz();try{NewsDto newsDto = biz.getNews("http://www.csdn.net/article/2014-04-17/2819363-all-about-ddos");List<News> newses = newsDto.getNewses();for(News news : newses){System.out.println(news);}System.out.println("-----");System.out.println(newsDto.getNextPageUrl());;} catch (CommonException e){// TODO Auto-generated catch blocke.printStackTrace();}}

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



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

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

mXListView.setOnItemClickListener(new OnItemClickListener(){@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id){NewsItem newsItem = mDatas.get(position-1);Intent intent = new Intent(getActivity(), NewsContentActivity.class);intent.putExtra("url", newsItem.getLink());startActivity(intent);}});

到达显示内容的Activity页面:

package com.zhy.csdndemo;import java.util.List;import me.maxwin.view.IXListViewLoadMore;import me.maxwin.view.XListView;import android.app.Activity;import android.content.Intent;import android.os.AsyncTask;import android.os.Bundle;import android.os.Looper;import android.view.View;import android.widget.AdapterView;import android.widget.Toast;import android.widget.AdapterView.OnItemClickListener;import android.widget.ProgressBar;import com.zhy.bean.CommonException;import com.zhy.bean.News;import com.zhy.biz.NewsItemBiz;import com.zhy.csdndemo.adapter.NewContentAdapter;public class NewsContentActivity extends Activity implements IXListViewLoadMore{private XListView mListView;/** * 该页面的url */private String url;private NewsItemBiz mNewsItemBiz;private List<News> mDatas;private ProgressBar mProgressBar;private NewContentAdapter mAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.news_content);mNewsItemBiz = new NewsItemBiz();Bundle extras = getIntent().getExtras();url = extras.getString("url");mAdapter = new NewContentAdapter(this);mListView = (XListView) findViewById(R.id.id_listview);mProgressBar = (ProgressBar) findViewById(R.id.id_newsContentPro);mListView.setAdapter(mAdapter);mListView.disablePullRefreash();mListView.setPullLoadEnable(this);mListView.setOnItemClickListener(new OnItemClickListener(){@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id){News news = mDatas.get(position - 1);String imageLink = news.getImageLink();//Toast.makeText(NewContentActivity.this, imageLink, 1).show();Intent intent = new Intent(NewsContentActivity.this,ImageShowActivity.class);intent.putExtra("url", imageLink);startActivity(intent);}});mProgressBar.setVisibility(View.VISIBLE);new LoadDataTask().execute();}@Overridepublic void onLoadMore(){}class LoadDataTask extends AsyncTask<Void, Void, Void>{@Overrideprotected Void doInBackground(Void... params){try{mDatas = mNewsItemBiz.getNews(url).getNewses();} catch (CommonException e){Looper.prepare();Toast.makeText(getApplicationContext(), e.getMessage(), 1).show();Looper.loop();}return null;}@Overrideprotected void onPostExecute(Void result){if(mDatas == null)return ; mAdapter.addList(mDatas);mAdapter.notifyDataSetChanged();mProgressBar.setVisibility(View.GONE);}}/** * 点击返回按钮 * @param view */public void back(View view){finish();}}

接下来看这个Activity中ListView的Adapter

package com.zhy.csdndemo.adapter;import java.util.ArrayList;import java.util.List;import android.content.Context;import android.graphics.Bitmap;import android.text.Html;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;import com.nostra13.universalimageloader.core.DisplayImageOptions;import com.nostra13.universalimageloader.core.ImageLoader;import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;import com.nostra13.universalimageloader.core.assist.ImageScaleType;import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;import com.zhy.bean.News;import com.zhy.bean.News.NewsType;import com.zhy.csdndemo.R;public class NewContentAdapter extends BaseAdapter{private LayoutInflater mInflater;private List<News> mDatas = new ArrayList<News>();private ImageLoader imageLoader = ImageLoader.getInstance();private DisplayImageOptions options;public NewContentAdapter(Context context){mInflater = LayoutInflater.from(context);imageLoader.init(ImageLoaderConfiguration.createDefault(context));options = new DisplayImageOptions.Builder().showStubImage(R.drawable.images).showImageForEmptyUri(R.drawable.images).showImageOnFail(R.drawable.images).cacheInMemory().cacheOnDisc().imageScaleType(ImageScaleType.EXACTLY).bitmapConfig(Bitmap.Config.RGB_565).displayer(new FadeInBitmapDisplayer(300)).build();}public void addList(List<News> datas){mDatas.addAll(datas);}@Overridepublic int getCount(){return mDatas.size();}@Overridepublic Object getItem(int position){return mDatas.get(position);}@Overridepublic long getItemId(int position){return position;}@Overridepublic int getItemViewType(int position){switch (mDatas.get(position).getType()){case NewsType.TITLE:return 0;case NewsType.SUMMARY:return 1;case NewsType.CONTENT:return 2;case NewsType.IMG:return 3;case NewsType.BOLD_TITLE:return 4;}return -1;}@Overridepublic int getViewTypeCount(){return 5;}@Overridepublic boolean isEnabled(int position){switch (mDatas.get(position).getType()){case NewsType.IMG:return true;default:return false;}}@Overridepublic View getView(int position, View convertView, ViewGroup parent){News news = mDatas.get(position); // 获取当前项数据Log.e("xxx", news.toString());ViewHolder holder = null;if (null == convertView){holder = new ViewHolder();switch (news.getType()){case NewsType.TITLE:convertView = mInflater.inflate(R.layout.news_content_title_item, null);holder.mTextView = (TextView) convertView.findViewById(R.id.text);break;case NewsType.SUMMARY:convertView = mInflater.inflate(R.layout.news_content_summary_item, null);holder.mTextView = (TextView) convertView.findViewById(R.id.text);break;case NewsType.CONTENT:convertView = mInflater.inflate(R.layout.news_content_item, null);holder.mTextView = (TextView) convertView.findViewById(R.id.text);break;case NewsType.IMG:convertView = mInflater.inflate(R.layout.news_content_img_item, null);holder.mImageView = (ImageView) convertView.findViewById(R.id.imageView);break;case NewsType.BOLD_TITLE:convertView = mInflater.inflate(R.layout.news_content_bold_title_item, null);holder.mTextView = (TextView) convertView.findViewById(R.id.text);break;}convertView.setTag(holder);} else{holder = (ViewHolder) convertView.getTag();}if (null != news){switch (news.getType()){case NewsType.IMG:imageLoader.displayImage(news.getImageLink(), holder.mImageView, options);break;case NewsType.TITLE:holder.mTextView.setText(news.getTitle());break;case NewsType.SUMMARY:holder.mTextView.setText(news.getSummary());break;case NewsType.CONTENT:holder.mTextView.setText("\u3000\u3000"+Html.fromHtml(news.getContent()));break;case NewsType.BOLD_TITLE:holder.mTextView.setText("\u3000\u3000"+Html.fromHtml(news.getContent()));default:// holder.mTextView.setText(Html.fromHtml(item.getContent(),// null, new MyTagHandler()));// holder.content.setText(Html.fromHtml("<ul><bold>加粗</bold>sdfsdf<ul>",// null, new MyTagHandler()));break;}}return convertView;}private final class ViewHolder{TextView mTextView;ImageView mImageView;}}

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

最后就是图片展示的Activity:

package com.zhy.csdndemo;import android.app.Activity;import android.graphics.Bitmap;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.widget.ProgressBar;import android.widget.Toast;import com.polites.android.GestureImageView;import com.zhy.csdndemo.util.FileUtil;import com.zhy.csdndemo.util.Http;public class ImageShowActivity extends Activity{private String url;private ProgressBar mLoading;private GestureImageView mGestureImageView;private Bitmap mBitmap;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_image_page);// 拿到图片的链接url = getIntent().getExtras().getString("url");mLoading = (ProgressBar) findViewById(R.id.loading);mGestureImageView = (GestureImageView) findViewById(R.id.image);new DownloadImgTask().execute();}/** * 点击返回按钮 *  * @param view */public void back(View view){finish();}/** * 点击下载按钮 *  * @param view */public void downloadImg(View view){mGestureImageView.setDrawingCacheEnabled(true);if (FileUtil.writeSDcard(url, mGestureImageView.getDrawingCache())){Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show();} else{Toast.makeText(getApplicationContext(), "保存失败", Toast.LENGTH_SHORT).show();}mGestureImageView.setDrawingCacheEnabled(false);}class DownloadImgTask extends AsyncTask<Void, Void, Void>{@Overrideprotected Void doInBackground(Void... params){mBitmap = Http.HttpGetBmp(url);return null;}@Overrideprotected void onPostExecute(Void result){mGestureImageView.setImageBitmap(mBitmap);mLoading.setVisibility(View.GONE);super.onPostExecute(result);}}}
好了,省略了一些辅助类的方法和布局文件。下面看下效果。

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



源码点击此处下载







25 0
原创粉丝点击