博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇)
阅读量:5123 次
发布时间:2019-06-13

本文共 13887 字,大约阅读时间需要 46 分钟。

转载请标明出处: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
newses; private String nextPageUrl ; public List
getNewses() { return newses; } public void setNewses(List
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;	}	@Override	public 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
newses = new ArrayList
(); String htmlStr = DataUtil.doGet(urlStr); Document doc = Jsoup.parse(htmlStr); // 获得文章中的第一个detail Element 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.Test	public void test02()	{		NewsItemBiz biz = new NewsItemBiz();		try		{			NewsDto newsDto = biz.getNews("http://www.csdn.net/article/2014-04-17/2819363-all-about-ddos");						List
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 block e.printStackTrace(); } }
然后我们能够拿到这种结果数据:

好了,如今准备把解析完毕的数据用到我们的app上。

上一教程已经完毕了Xlist的显示。上拉与下拉。如今给它加入OnItemClickListener:

mXListView.setOnItemClickListener(new OnItemClickListener()		{			@Override			public 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
mDatas; private ProgressBar mProgressBar; private NewContentAdapter mAdapter; @Override protected 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() { @Override public 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(); } @Override public void onLoadMore() { } class LoadDataTask extends AsyncTask
{ @Override protected 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; } @Override protected void onPostExecute(Void result) { if(mDatas == null) return ; mAdapter.addList(mDatas); mAdapter.notifyDataSetChanged(); mProgressBar.setVisibility(View.GONE); } } /** * 点击返回button * @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
mDatas = new ArrayList
(); 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
datas) { mDatas.addAll(datas); } @Override public int getCount() { return mDatas.size(); } @Override public Object getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public 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; } @Override public int getViewTypeCount() { return 5; } @Override public boolean isEnabled(int position) { switch (mDatas.get(position).getType()) { case NewsType.IMG: return true; default: return false; } } @Override public 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("
    加粗
    sdfsdf
      ", // 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;	@Override	protected 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();	}	/**	 * 点击返回button	 * 	 * @param view	 */	public void back(View view)	{		finish();	}	/**	 * 点击下载button	 * 	 * @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
{ @Override protected Void doInBackground(Void... params) { mBitmap = Http.HttpGetBmp(url); return null; } @Override protected void onPostExecute(Void result) { mGestureImageView.setImageBitmap(mBitmap); mLoading.setVisibility(View.GONE); super.onPostExecute(result); } }}
好了,省略了一些辅助类的方法和布局文件。

以下看下效果。

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

转载于:https://www.cnblogs.com/zfyouxi/p/5327854.html

你可能感兴趣的文章
poj Going from u to v or from v to u? 强联通缩点+拓扑排序(或搜索)
查看>>
Hadoop源代码分析(二)
查看>>
Django中提供了6种缓存方式
查看>>
JDK安装与环境变量配置
查看>>
原生js实现缓动返回顶部
查看>>
1.4Activity保存现场状态
查看>>
关于mysql中GROUP_CONCAT函数的使用
查看>>
maven+springmvc下载excle文件——ie8可用
查看>>
Android中解析XML
查看>>
Fragment销毁时replace和add两个方法的区别
查看>>
android 多线程断点续传下载 三
查看>>
mongodb 2php 操作
查看>>
eclipse 断点调试快捷键
查看>>
Android 删除指定文件代码
查看>>
emctl start dbconsole OC4J_dbconsole*** not found
查看>>
Java进阶04 RTTI
查看>>
验证 Swarm 数据持久性 - 每天5分钟玩转 Docker 容器技术(104)
查看>>
python-if条件判断与while/for循环
查看>>
【leetcode】16 3Sum Closest
查看>>
为什么中国的程序员总被称为码农?
查看>>