zoukankan      html  css  js  c++  java
  • 实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇)

    转载请标明出处: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;
    	}
    
    	@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<News> newses = new ArrayList<News>();
    		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<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 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<News> 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<Void, Void, Void>
    	{
    
    		
    		
    		@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);
    		}
    
    	}
    	
    	/**
    	 * 点击返回按钮
    	 * @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);
    	}
    
    	@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("u3000u3000"+Html.fromHtml(news.getContent()));
    				break;
    			case NewsType.BOLD_TITLE:
    				holder.mTextView.setText("u3000u3000"+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;
    
    	@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();
    
    	}
    
    	/**
    	 * 点击返回按钮
    	 * 
    	 * @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>
    	{
    		@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,没办法录太多。



    源码点击此处下载





    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    打造属于自己的谷歌Maps版博客公告【演示+源码】
    CentOS 更改默认启动顺序
    VC的控制台程序,如何获取输入参数和环境变量
    如何同时提供ANSI和UNICODE函数
    VC工程需要注意字符集问题
    升级firefox到最新版
    VC工程需要注意字符集问题
    如何同时提供ANSI和UNICODE函数
    使C++ Builder编译程度独立运行
    安装谷歌浏览器
  • 原文地址:https://www.cnblogs.com/dingxiaoyue/p/4924979.html
Copyright © 2011-2022 走看看