您的位置:首页 > 移动开发

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

2017-02-27 20:34 766 查看
今天给大家带来CSDN的完结篇,即加入文章的查看和文章中图片的保存~

今天的目标:



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

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

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



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

首先是封装的对象:

[java] view
plain copy







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;

}

}

[java] view
plain copy






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对象:

[java] view
plain copy







/**

* 根据文章的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;

}

测试代码:

[java] view
plain copy







@org.junit.Test

public void test02()

{

//NewsItemBiz biz = new NewsItemBiz();
NewsDto biz = new NewsDto();


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:

[java] view
plain copy







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页面:

[java] view
plain copy







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

[java] view
plain copy







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();

}
<
20000
li class="alt" style="border-left-width:3px; border-style:none none none solid; border-left-color:rgb(108,226,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important">

@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:

[java] view
plain copy







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,没办法录太多。


源码点击此处下载

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐