转载请标明出处: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。没办法录太多。

      源代码点击此处下载

      查看原文