实现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);
- }
- }
- /**
- * 点击返回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<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("\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;
- @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<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。没办法录太多。
源代码点击此处下载
实现app上对csdn的文章查看,以及文章中图片的保存 (制作csdn app 完结篇)的更多相关文章
- [iOS基础控件 - 5.2] 查看大图、缩放图片代码(UIScrollView制作)
原图: 900 x 1305 拖曳滚动: 缩放: 主要代码: // // ViewController.m // ImageZoom // // Created by ...
- 实现app上对csdn的文章列表上拉刷新下拉加载以及加入缓存文章列表的功能 (制作csdn app 四)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23698511 今天继续对我们的csdn客户端未完成的功能进行实现,本篇博客接着客 ...
- 客户端上显示csdn上的各类别下的的文章列表 (制作csdn app 三)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/23597229 今天将在Android 使用Fragment,ViewPagerI ...
- 抓取csdn上的各类别的文章 (制作csdn app 二)
转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/23532797 这篇博客接着上一篇(Android 使用Fragment,View ...
- 巨高兴,偶的文章 “如何在服务器上配置ODBC来访问本机DB2for Windows服务器”被推荐至CSDN博客首页
非常高兴,偶的文章 "如何在服务器上配置ODBC来访问本机DB2for Windows服务器"被推荐至CSDN博客首页,截图留念. 文章被推荐在C ...
- “杀死” App 上的疑难崩溃
在移动应用性能方面,崩溃带来的影响是最为严重的,程序崩了可以打断用户正在进行的操作体验,造成关键业务中断.用户留存率下降.品牌口碑变差.生命周期价值下降等影响.很多公司将崩溃率作为优先级最高的技术指标 ...
- 关于app上页面和js的调试
不久前折腾了一晚上关于app上的页面和js的调试: 首先得准备几个比较比较常用的工具: 1.chrome(这个都没有你还干啥fe呀) 2.Fiddler(抓包神器,基本也是必备咯) 3.sublime ...
- Python+爬虫+xlwings发现CSDN个人博客热门文章
☞ ░ 前往老猿Python博文目录 ░ 一.引言 最近几天老猿博客的访问量出现了比较大的增长,从常规的1000-3000之间波动的范围一下子翻了将近一倍,粉丝增长从日均10-40人也增长了差不多一倍 ...
- APP上传
原文网址: http://blog.csdn.net/ayangcool 前言:作为一名IOS开发者,把开发出来的App上传到App Store是必须的.下面就来详细介绍下具体流程. 1.打开苹果开发 ...
随机推荐
- 四大主流云平台对比--CloudStack, Eucalyptus, vCloud Director和OpenStack。
我迟早可能都要进入的领域,提前温习... 还有KVM,ESXI,API,XEN之间的术语和关系,也要心中有数.. ~~~~~~~~~~~~~~~~~~~ 云计算在如今的IT界一直是一个最热门的话题,鉴 ...
- php smarty 配置四个存放目录
require("Smarty.class.php"); $smarty = new Smarty(); $smarty -> template_dir = "./ ...
- 【无聊放个模板系列】HDU 1269 (SCC)
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #inc ...
- 汇编中,BP,SP有何区别?分别怎么使用?
bp寄存器,跟其它什么BX,AX一样的用法, SP是用在栈上的,配合SS使用,像SS:SP SS上放段地址,SP上放偏移地址. 寻址时,像[bp],相当于SS:[bp] 就是说它默认使用SS 像BX默 ...
- USB (Universal Serial Bus)
USB歷史簡介 USB規格演變 標準 USB 2.0 介面 實體層 訊號傳輸 傳輸速率 網路層 USB 通訊模型 Endpoints 傳輸型態 USB 資料連結 Transaction Frame P ...
- Android 各个版本WebView
转载请注明出处 http://blog.csdn.net/typename/ powered by miechal zhao : miechalzhao@gmail.com 前言: 根据Googl ...
- LinearLayout按下(pressed)或获取焦点(focused)时背景设置不同颜色或图片
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id=&qu ...
- NoClassDefFoundError: javassist/util/proxy/MethodFilter
Caused by: java.lang.NoClassDefFoundError: javassist/util/proxy/MethodFilter at org.hibernate.byt ...
- 使用OLEDB读取不同版本Excel数据的连接字符串设置
摘要: 用OLEDB通过设置连接字符串可以像读取sqlserver一样将excel中的数据读取出来,但是excel2003和excel2007/2010的连接字符串是不同的/// summary // ...
- sql server 修改表的默认值, 需要先删除约束条件
---------增加是否发布订单 if not exists(select 1 from syscolumns where name='iIsRelease' and id=OBJECT_ID('M ...