Android应用开发-小巫程序员宅基地client之显示博文具体内容-程序员宅基地

技术标签: java  ui  移动开发  

Android应用开发-小巫程序员宅基地客户端之显示博文具体内容

上篇博文给大家介绍的是怎样嵌入有米广告而且获取收益,本篇博客打算讲讲关于怎样在一个ListView里显示博文的具体信息。这个可能是童鞋们比較困惑的,由于一篇博客可能有标题、摘要、图片、代码等等元素组成,我们要怎么在一个界面中显示这些内容而且依照自己的指定的方式显示呢,别急,以下会告诉大家。

   又一次整理一下一篇博文可能有以下元素:
  • 标题
  • 摘要
  • 文本内容
  • 图片
  • 粗标题
  • 代码块

在UI篇小巫已经介绍了,博文具体内容的主要控件就是一个ListView,每一个元素就是ListView中的一项item,每一项都有自己的布局用于显示特定的元素。效果图例如以下:





关于UI就不说了。主要来看一下内容适配器:

/BlogClient/src/com/xiaowu/blogclient/adapter/BlogDetailAdapter.java
package com.xiaowu.blogclient.adapter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
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.xiaowu.blogclient.R;
import com.xiaowu.blogclient.model.Blog;
import com.xiaowu.blogclient.util.Constants;
import com.xiaowu.blogclient.util.FileUtil;
import com.xiaowu.blogclient.util.MyTagHandler;

/**
 * 博客内容适配器
 * 
 * @author wwj_748
 * @date 2014/8/10
 */
public class BlogDetailAdapter extends BaseAdapter {
	private ViewHolder holder;
	private LayoutInflater layoutInflater;
	private Context context;
	private List<Blog> list;

	private SpannableStringBuilder htmlSpannable;
	private ImageLoader imageLoader = ImageLoader.getInstance();
	private DisplayImageOptions options;

	public BlogDetailAdapter(Context context) {
		super();
		this.context = context;
		layoutInflater = LayoutInflater.from(context);
		list = new ArrayList<Blog>();
		
		// 初始化imageLoader
		imageLoader.init(ImageLoaderConfiguration.createDefault(context));
		
		// imageloader配置
		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 setList(List<Blog> list) {
		this.list = list;
	}

	public void addList(List<Blog> list) {
		this.list.addAll(list);
	}

	public void clearList() {
		this.list.clear();
	}

	public List<Blog> getList() {
		return list;
	}

	public void removeItem(int position) {
		if (list.size() > 0) {
			list.remove(position);
		}
	}

	@Override
	public int getCount() {
		return list.size();
	}

	@Override
	public Object getItem(int position) {
		return list.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		Blog item = list.get(position);
		if (null == convertView) {
			holder = new ViewHolder();
			switch (item.getState()) {
			case Constants.DEF_BLOG_ITEM_TYPE.TITLE:// 显示标题
				convertView = layoutInflater.inflate(
						R.layout.article_detail_title_item, null);
				holder.content = (TextView) convertView.findViewById(R.id.text);
				break;
			case Constants.DEF_BLOG_ITEM_TYPE.SUMMARY: // 摘要
				convertView = layoutInflater.inflate(
						R.layout.article_detail_summary_item, null);
				holder.content = (TextView) convertView.findViewById(R.id.text);
				break;
			case Constants.DEF_BLOG_ITEM_TYPE.CONTENT: // 内容
				convertView = layoutInflater.inflate(
						R.layout.article_detail_item, null);
				holder.content = (TextView) convertView.findViewById(R.id.text);
				break;
			case Constants.DEF_BLOG_ITEM_TYPE.IMG: // 图片
				convertView = layoutInflater.inflate(
						R.layout.article_detail_img_item, null);
				holder.image = (ImageView) convertView
						.findViewById(R.id.imageView);
				break;
			case Constants.DEF_BLOG_ITEM_TYPE.BOLD_TITLE: // 加粗标题
				convertView = layoutInflater.inflate(
						R.layout.article_detail_bold_title_item, null);
				holder.content = (TextView) convertView.findViewById(R.id.text);
				break;
			case Constants.DEF_BLOG_ITEM_TYPE.CODE: // 代码
				convertView = layoutInflater.inflate(
						R.layout.article_detail_code_item, null);
				holder.code = (WebView) convertView
						.findViewById(R.id.code_view);
				// holder.code.getSettings().setUseWideViewPort(true);
				// holder.code.getSettings().setJavaScriptEnabled(true);
				// holder.code.getSettings().setSupportZoom(true);
				// holder.code.getSettings().setBuiltInZoomControls(false);
				// holder.code.getSettings().setLoadWithOverviewMode(true);
				break;
			}

			convertView.setTag(holder);
		} else {
			holder = (ViewHolder) convertView.getTag();
		}
		// System.out.println(item.getContent());

		if (null != item) {
			switch (item.getState()) {
			case Constants.DEF_BLOG_ITEM_TYPE.IMG: // 图片,异步载入
				imageLoader.displayImage(item.getContent(), holder.image,
						options);
				break;
			case Constants.DEF_BLOG_ITEM_TYPE.CODE: // 代码,格式显示

				// 读代替码文件和模板文件
				String code = item.getContent();
				// String code = FileUtil.getFileContent(context,
				// "AboutActivity.java");
				String template = FileUtil.getFileContent(context, "code.html");
				// 生成结果
				String html = template.replace("{
      {code}}", code);
				holder.code.getSettings().setDefaultTextEncodingName("utf-8");
				holder.code.getSettings().setSupportZoom(true);
				holder.code.getSettings().setBuiltInZoomControls(true);

				// holder.code.loadUrl("file:///android_asset/code.html");

				holder.code.loadDataWithBaseURL("file:///android_asset/", html,
						"text/html", "utf-8", null);

				break;
			default:
				holder.content.setText(Html.fromHtml(item.getContent(), null,
						new MyTagHandler()));
				break;
			}
		}
		return convertView;
	}

	@Override
	public int getViewTypeCount() {
		return 6;
	}

	@Override
	public int getItemViewType(int position) {
		switch (list.get(position).getState()) {
		case Constants.DEF_BLOG_ITEM_TYPE.TITLE:
			return 0;
		case Constants.DEF_BLOG_ITEM_TYPE.SUMMARY:
			return 1;
		case Constants.DEF_BLOG_ITEM_TYPE.CONTENT:
			return 2;
		case Constants.DEF_BLOG_ITEM_TYPE.IMG:
			return 3;
		case Constants.DEF_BLOG_ITEM_TYPE.BOLD_TITLE:
			return 4;
		case Constants.DEF_BLOG_ITEM_TYPE.CODE:
			return 5;
		}
		return 1;
	}

	@Override
	public boolean isEnabled(int position) {
		switch (list.get(position).getState()) {
		case Constants.DEF_BLOG_ITEM_TYPE.IMG:
			return true;
		default:
			return false;
		}
	}

	private class ViewHolder {
		TextView id;
		TextView date;
		TextView title;
		TextView content;
		ImageView image;
		WebView code;
	}
}


这里有一个ListView的优化策略,就是图片进行异步载入。小巫这里用到了优秀的开源项目universalimageloader。我们仅仅须要关联依赖项目,就能够在项目中使用它对网络图片进行异步载入,具体使用自己查看上面的代码实现。


/BlogClient/src/com/xiaowu/blogclient/BlogDetailActivity.java

package com.xiaowu.blogclient;

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.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.xiaowu.blogclient.adapter.BlogDetailAdapter;
import com.xiaowu.blogclient.util.Constants;
import com.xiaowu.blogclient.util.JsoupUtil;
import com.xiaowu.blogclient.util.HttpUtil;

/**
 * 博客具体内容界面
 * 
 * @author wwj_748
 * @date 2014/8/10
 */
public class BlogDetailActivity extends Activity implements IXListViewLoadMore {
	private XListView listView; // 列表控件
	private BlogDetailAdapter blogDetailAdapter; // 内容适配器

	private ProgressBar progressBar; // 进度条
	private ImageView reLoadImageView; // 又一次载入的图片

	private ImageView backBtn; // 回退button
	private ImageView commentBtn; // 评论button

	public static String url; // 博客地址
	private String filename; // 文件名称字

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		requestWindowFeature(Window.FEATURE_NO_TITLE);// 无标题
		super.onCreate(savedInstanceState);
		setContentView(R.layout.article_detail);

		init();
		initComponent();

		// 运行异步载入
		new MainTask().execute(url, Constants.DEF_TASK_TYPE.FIRST);
	}

	// 初始化
	private void init() {
		blogDetailAdapter = new BlogDetailAdapter(this);
		url = getIntent().getExtras().getString("blogLink");
		filename = url.substring(url.lastIndexOf("/") + 1);
		System.out.println("filename--->" + filename);
	}

	// 初始化组件
	private void initComponent() {
		progressBar = (ProgressBar) findViewById(R.id.blogContentPro);
		reLoadImageView = (ImageView) findViewById(R.id.reLoadImage);
		reLoadImageView.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View view) {
				reLoadImageView.setVisibility(View.INVISIBLE);
				progressBar.setVisibility(View.VISIBLE);

			}
		});

		backBtn = (ImageView) findViewById(R.id.backBtn);
		backBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				finish();
			}
		});

		commentBtn = (ImageView) findViewById(R.id.comment);
		commentBtn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View view) {
				Intent i = new Intent();
				i.setClass(BlogDetailActivity.this, BlogCommentActivity.class);
				i.putExtra("filename", filename);
				startActivity(i);
				overridePendingTransition(R.anim.push_left_in, R.anim.push_no);
			}
		});

		listView = (XListView) findViewById(R.id.listview);
		listView.setAdapter(blogDetailAdapter);
		listView.setPullLoadEnable(this);

		listView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				// 获取点击列表项的状态
				int state = blogDetailAdapter.getList().get(position - 1)
						.getState();
				switch (state) {
				case Constants.DEF_BLOG_ITEM_TYPE.IMG: // 点击的是图片
					String url = blogDetailAdapter.getList().get(position - 1)
							.getImgLink();
					Intent i = new Intent();
					i.setClass(BlogDetailActivity.this, ImageActivity.class);
					i.putExtra("url", url);
					startActivity(i);
					break;
				default:
					break;
				}
			}
		});
	}

	@Override
	public void finish() {
		super.finish();
	}

	private class MainTask extends AsyncTask<String, Void, Integer> {

		@Override
		protected Integer doInBackground(String... params) {
			// 通过http请求url地址,获取html文档
			String temp = HttpUtil.httpGet(params[0]);
			if (temp == null) {
				if (params[1].equals(Constants.DEF_TASK_TYPE.FIRST)) {
					return Constants.DEF_RESULT_CODE.FIRST;
				} else {
					return Constants.DEF_RESULT_CODE.ERROR;
				}
			}
			// 加入解析出来的数据
			blogDetailAdapter.addList(JsoupUtil.getContent(url, temp));
			if (params[1].equals(Constants.DEF_TASK_TYPE.FIRST)) {
				return Constants.DEF_RESULT_CODE.REFRESH;
			}
			return Constants.DEF_RESULT_CODE.LOAD;
		}

		@Override
		protected void onPostExecute(Integer result) {
			if (result == Constants.DEF_RESULT_CODE.FIRST) {
				Toast.makeText(getApplicationContext(), "网络信号不佳",
						Toast.LENGTH_LONG).show();
				reLoadImageView.setVisibility(View.VISIBLE);
			} else if (result == Constants.DEF_RESULT_CODE.ERROR) {
				listView.stopLoadMore();
			} else if (result == Constants.DEF_RESULT_CODE.REFRESH) {
				blogDetailAdapter.notifyDataSetChanged();
			} else {
				blogDetailAdapter.notifyDataSetChanged();
				listView.stopLoadMore();
			}
			progressBar.setVisibility(View.INVISIBLE);
			super.onPostExecute(result);
		}

	}

	// 载入很多其它
	@Override
	public void onLoadMore() {
		if (!JsoupUtil.contentLastPage) {
			new MainTask().execute(url, Constants.DEF_TASK_TYPE.NOR_FIRST);
		} else {
			// 在底部显示“--THE END0--"文本
			listView.stopLoadMore(" -- THE END --");
		}
	}

}


假设研读了我提供源代码的童鞋都会发现,我这里使用AsyncTask来进行网络请求操作,童鞋们也能够使用Thread+Handler的方式来实现异步请求,须要注意的是,耗时操作和网络操作都不能放在主线程,这是Android开发的规范。
这里还提一个技巧,我们更新ListView的数据的时候,并不须要又一次new一个adapter,能够像我一样,在适配器类中提供addList的方法。加入数据到adapter中,然后在适当的位置调用notifyDataSetChanged()方法就能够更新数据,不会出现数据反复和效率低下的情况。



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33691817/article/details/85785011

智能推荐

Non-resolvable parent POM for com.example:demo:0.0.1-SNAPSHOT: Cannot access alimaven (网址xxxxx)_xxxxx网站_诸葛斩龙的博客-程序员宅基地

修改了maven 的 xml文件 添加的镜像文件导致解决办法:删除配置的镜像文件即可,网速也没用慢,反而很多问题都没了感觉只需要配置一个本地仓库的位置就行了折腾了一下午,删除了就行了,还不如多此一举设置镜像,原始的xml文件挺好!<?xml version="1.0" encoding="UTF-8"?><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://ww_xxxxx网站

CentOs 关机注意事项_centos终端关闭时应注意什么-程序员宅基地

观察系统的使用状态 要看网络的联机状态, netstat -a 要看背景执行的程序 pas -aux通知在线使用者关机的时刻关机命令 shutdown poweroff halt 关机 reboot[重启]_centos终端关闭时应注意什么

java之IO流学习(一)-程序员宅基地

IO流用来控制设备(比如硬盘、内存)之间的数据传输。学习IO流从哪边入手呢,文本文件、图片文件、视频文件等都是我们平时接触比较多的文件类型。IO流体系中刚好就有一对流对象用来对文本文件进行读和写。他们分别是FileReader和FileWriter,通过看他们的后缀就知道,父类分别是Reader和Writer。那么父类的读写方法儿子当然就可以使用了。 通过FileReader和FileWri...

机器学习(回归二)——线性回归-最小二乘-代码实现-程序员宅基地

本篇内容本来想在写在上篇博客中的,那样篇幅过长,就单独提出来了。本篇文章采用两种方式实现线性回归,一种是使用scikit-learn。而通过上篇博客,我们已经知道了最小二乘法求解线性回归参数,所以完全可以自己手动实现。

ADO.NET 2.0中的DataSet和DataTable -程序员宅基地

MSDN2005年11月刊登载了John Papa的一篇文章《DataSet and DataTable in ADO.NET 2.0》,详细介绍了ADO.Net 2.0的一些新功能和特性,对于利用ADO.NET开发的程序员来说,是值得关注的。现介绍如下: 一.功能增强的DataTable在ADO.NET1.x中,DataSet完全掩盖了DataTable的光芒,并非DataTable自身

手把手带你入门前端工程化——超详细教程(高级前端必备)_全栈修炼的博客-程序员宅基地

本文将分成以下 7 个小节:技术选型统一规范测试部署监控性能优化重构部分小节提供了非常详细的实战教程,让大家动手实践。另外我还写了一个前端工程化 demo 放在 github 上。这个 d..._手把手撸前端

随便推点

Focal Loss for Dense Object Detection论文阅读_focalloss论文-程序员宅基地

论文地址:https://arxiv.org/pdf/1708.02002.pdf 最近YOLO_V3版本刚刚出世,很强,下面一篇博客我们再介绍,这篇博客我们主要来读读大神何凯明的大作Focal Loss(焦点损失),其主要就是一个解决分类问题中类别不平衡、分类难度差异的一个 loss。Focal loss 这个损失函数在标准的交叉熵标准上添加了一个因子 。 目前目标检测的框..._focalloss论文

搭建FTP服务器--云主机使用的是内网地址(公有云上面搭建FTP)-程序员宅基地

搭建FTP服务器--云主机使用的是内网地址,ftp一般是被动模式,需要在ftp服务器上面开启被动模式的--请求数据里面--提供源地址的时候,提供公网ip地址,(默认提供的是自己出口网卡的内网地址)搭建FTP服务器--云主机使用的是内网地址,ftp一般是被动模式,需要在ftp服务器上面开启 被动模式的--请求数据里面--提供源地址的时候,提供公网ip地址,(默认提供的是自己出口网卡的内网...

发表还是灭亡?_publish or perish,全世界都在按着这条规矩来-程序员宅基地

当今的科学界流行一句话:Publish or Perish。这种文化现象兴起于美国七十年代初期,香港的大学九十年代起开始效仿,而今天中国内地的大学更是有过之无不及。对科研人员来说“发表还是灭亡”,意味着如果没有发表,就申请不到科研经费,没有机会晋升职称。对于学术期刊来说也同样承受着压力,要发表的论文越来越多,而能评审的人实在不够。唯一能从这种巨大的发表压力中获利的就是出版业。因此几乎每天都有新的..._publish or perish,全世界都在按着这条规矩来

linux设备驱动第一篇:基础知识点_linux设备驱动入门-程序员宅基地

首先,我们知道驱动是内核的一部分,那么驱动在内核中到底扮演了什么角色呢?设备驱动程序在内核中的角色:他们是一个个独立的“黑盒子”,使某个特定的硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设备的工作细节。(说白了,驱动程序除了对外提供特定的接口外,任何实现细节对应用程序都是不可见的。)用户的操作通过一组标准化的调用执行,而这些调用独立于特定的驱动程序。驱动程序的任务是把这些标准化调_linux设备驱动入门

从0开始学习spark(4)Spark Rdd常用算子和RDD必备知识!!!_非键值对rdd-程序员宅基地

Spark零基础入门第三课1. RDD1.1 什么是RDD1.2 RDD 的属性2. 创建 RDD3. RDD常见的算子介绍3.1 Transformation 类算子:3.2 action 类算子:3.3 WordCount 中的 RDD4. RDD的依赖关系4.1 窄依赖和宽依赖对比4.2、窄依赖和宽依赖总结4.3、Lineage5. DAG 生成6. RDD 缓存6.1 RDD 的缓存方式每日福利来一个,话不多说,我们直接开始今天的spark的学习,之前我们学习了Spark的基础原理,和概念,然后_非键值对rdd

ECC加密算法入门介绍 -程序员宅基地

>> 欢迎您,客人: 登录 | 注册 | 忘记密码 | 在线 | 搜索 | 帮助  看雪学院老论坛 初学者园地 [返回]   ECC加密算法入门介绍--5.3更新[完]  标记论坛所有内容为已读  >> 初学者园地欢迎您的到来    ◆您是本帖第 13083 个阅读者◆       * 贴子主题: ECC加密算法入门

推荐文章

热门文章

相关标签