Android - SimpleAdapter适配器支持的组件及Listview模拟下载

本来这周想写三篇的,结果这第一篇就不知道该如何起笔。语言表达能力真的需要提高啊。其实有好多想写的,最近这几天又接触到了以前听过但是没有去考虑的一些点。这篇的起因曾经做过一道题,我当时很不理解,我看有评论还是很多跟我当时想法一样的,一直没来得及去追究,终于还是放心不下,去看了一下,发现我错了。原题如下:

使用SimpleAdapter作为 ListView的适配器,行布局中支持下列哪些组件?

  • TextView
  • ProgressBar
  • CompoundButton
  • ImageView

当时我毫不犹豫的就选了ABCD,后来就一个红红的× 。答案是ACD。SimpleAdapter并不支持ProgressBar,我当时就很纳闷儿,为啥?

其实看看这个题,人家说的是SimpleAdapter,想当然的把SimpleAdapter当作了最基本的Adapter了(至于其他的适配器,自己可以看一下),所以就感觉答案应该是没问题的,那这个SimpleAdapter到底是支持什么?这就要从SimpleAdapter的源码看了,我把重要的摘出来看,首先看一下这个SimpleAdapter的构造函数。

public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,int resource, String[] from, int[] to) {
        mData = data;
        mResource = mDropDownResource = resource;
        mFrom = from;
        mTo = to;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

这个SimpleAdapter只有一个构造函数,从参数可以看出,SimpleAdapter的数据资源类型还是比较固定的,List<? extends Map<String, ?>>。resource即每条记录的布局文件,from是data中Map的key ,而to 就是布局文件中的组件的id。

我们知道,Adapter的view显示或者view绑定是在getView函数里实现的,那么SimpleAdapter的getView函数,但是SimpleAdapter并没有直接重写getView,而是调用其他函数,最后调用了一个叫bindView的函数,从字面理解就是"绑定View"了,所以要看这个函数。

private void bindView(int position, View view) {
        final Map dataSet = mData.get(position);
        if (dataSet == null) {
            return;
        }

        final ViewBinder binder = mViewBinder;
        final String[] from = mFrom;
        final int[] to = mTo;
        final int count = to.length;

        for (int i = 0; i < count; i++) {
            final View v = view.findViewById(to[i]);
            if (v != null) {
                final Object data = dataSet.get(from[i]);
                String text = data == null ? "" : data.toString();
                if (text == null) {
                    text = "";
                }

                boolean bound = false;
                if (binder != null) {
                    bound = binder.setViewValue(v, data, text);
                }

                if (!bound) {
                    if (v instanceof Checkable) {
                        if (data instanceof Boolean) {
                            ((Checkable) v).setChecked((Boolean) data);
                        } else if (v instanceof TextView) {
                            // Note: keep the instanceof TextView check at the bottom of these
                            // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                            setViewText((TextView) v, text);
                        } else {
                            throw new IllegalStateException(v.getClass().getName() +
                                    " should be bound to a Boolean, not a " +
                                    (data == null ? "<unknown type>" : data.getClass()));
                        }
                    } else if (v instanceof TextView) {
                        // Note: keep the instanceof TextView check at the bottom of these
                        // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                        setViewText((TextView) v, text);
                    } else if (v instanceof ImageView) {
                        if (data instanceof Integer) {
                            setViewImage((ImageView) v, (Integer) data);
                        } else {
                            setViewImage((ImageView) v, text);
                        }
                    } else {
                        throw new IllegalStateException(v.getClass().getName() + " is not a " +
                                " view that can be bounds by this SimpleAdapter");
                    }
                }
            }
        }
    }

在bindView里有一长串的判断,就是我们要看的,

if (v instanceof Checkable) {
     //……
} else if (v instanceof TextView) {
     //……
} else if (v instanceof ImageView) {
     //……
} else {
      throw new IllegalStateException(v.getClass().getName() + " is not a " +
                                " view that can be bounds by this SimpleAdapter");
}

可以看到首先判断这个view是不是实现的checkable(接口),然后判断是不是TextView,然后判断是不是ImageView,然后就没有然后了,如果以上三种都不是,那就抛异常了,是一个Illegal异常,不合法!异常的内容是 将要绑定的这个view 不是一个可以被SimpleAdapter绑定的View。所以再会过去看题,A、TextView , 可以;B、ProgressBar,什么鬼?不可以。C、CompoundButton,这个view实现了checkable接口,可以。D、ImageView,没问题。

所以答案就很明显了。

其实,SimpleAdapter简单易用并且也可以实现比较不错的布局,如果使用SimpleAdapter,我写了一个非常简单的数据源获得方式,如下:

private List<Map<String, Object>> getData() {
<span style="white-space:pre">	</span>mData = new ArrayList<Map<String, Object>>();

	for (int i = 1; i < 11; i++) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("name", "name" + i + "\n" + "这里是该item的介绍");
		map.put("button", "download");
		map.put("image", R.drawable.ic_launcher);
		mData.add(map);
	}

	return mData;

}

然后直接new一个SimpleAdapter就行了:

SimpleAdapter mAdapter = new SimpleAdapter(getApplicationContext(),
		getData(), R.layout.item, new String[] { "image", "name",
		"button" }, new int[] { R.id.id_item_image,
		R.id.id_item_text, R.id.id_item_btn });

至于布局文件就比较简单了。

这篇并不是多想说这个的,但是感觉已经说的很多了,还有好多废话。因为这个的原因,我很想模仿一下一些下载软件的app里的列表 下载的样式,其实就是把progress放在ListView里面,既然simpleAdapter不支持progressBar,那么就自己重写BaseAdapter。这次非常简单的重写了一下,在模拟下载时也没有使用service,也就是说并没有模拟后台下载,只是在当前activity里面模拟下载。

我重写的Adapter如下:

public class MyAdapter extends BaseAdapter {

	private List<Map<String, Object>> mData;
	private Context mContext;
	private LayoutInflater mInflater;

	public MyAdapter(Context context,List<Map<String, Object>> data) {

		this.mContext = context;
		this.mData = data;
		this.mInflater = LayoutInflater.from(context);

	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mData.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return mData.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		MyView mView = null;
		ButtonListener mListener = null;
		if(convertView == null){
			mView = new MyView();
			convertView = mInflater.inflate(R.layout.item, null);
			mView.imageView = (ImageView) convertView.findViewById(R.id.id_item_image);
			mView.textView = (TextView) convertView.findViewById(R.id.id_item_text);
			mView.button = (Button) convertView.findViewById(R.id.id_item_btn);
			mView.progressBar = (ProgressBar) convertView.findViewById(R.id.id_item_progress);
			mListener = new ButtonListener(position, mView.progressBar);
			convertView.setTag(mView);

		}else{
			convertView = (View) convertView.getTag();
		}

		Map<String , Object> map = mData.get(position);
		mView.imageView.setImageResource((Integer) map.get("image"));
		mView.textView.setText((CharSequence) map.get("name"));
		mView.button.setText((CharSequence) map.get("button"));
		mView.progressBar.setProgress(0);

		mView.button.setOnClickListener(mListener);

		return convertView;
	}

	class MyView{
		ImageView imageView;
		TextView textView;
		Button button;
		ProgressBar progressBar;
	}

	class ButtonListener implements OnClickListener{

		Button button;
		private int mPosition;
		private ProgressBar mProgressBar;
		private int mProgress = 0;
		Thread mThread = null;
		private boolean flag = true;
		Handler handler = new Handler(){
			public void handleMessage(android.os.Message msg) {
				button.setText("ok");
			};
		};

		class DownloadThread extends Thread{
			@Override
			public void run() {
				while(mProgress<=100&&flag){
					mProgressBar.setProgress(mProgress);
					try {
						Thread.sleep(1000);
						mProgress += 2;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				if(mProgressBar.getProgress()==100){
					flag = false;
					handler.sendEmptyMessage(0);
				}
			}
		}

		public ButtonListener(int position,ProgressBar progressBar) {
			mPosition = position;
			mProgressBar = progressBar;

		}

		@Override
		public void onClick(View v) {
			button = (Button) v;
			if(button.getText().equals("download")){
				button.setText("pause");
				if(mThread==null){
					mThread = new DownloadThread();
				}
				mThread.start();

			}else if(button.getText().equals("pause")&&mProgressBar.getProgress()<100){
				mThread.interrupt();
				mThread = null;
				flag = false;
				button.setText("go on");
			}else if(button.getText().equals("go on")&&mProgressBar.getProgress()<100){
				flag = true;
				if(mThread == null){
					mThread = new DownloadThread();
				}
				mThread.start();
				button.setText("pause");
			}else{
				flag = false;
				mThread.interrupt();
				mThread = null;
				button.setText("ok");
			}

		}

	}

}

这里其实并不难,只是有几个点需要注意一下:

1、给每一个item中的button绑定监听事件,在Listener的构造函数里面,我传入了当前item的position,以及该item中的ProgressBar,这个position在这里貌似没有用到。

2、在onClick里面开启新线程,模拟下载。其实应该是开启一个service,在service里面再开启新线程模拟下载,这样就是back掉当前的activity,下载依然在进行,这里只是简单的前台模拟。

3、当下载完毕后按钮上的文字改变时需要回到UI 线程也就是mainThread,否则会crash。

4、当mThread停止时,请不要使用stop这个方法,这个方法并没有什么卵用,使用后不管怎么stop,你会看到你的progressbar依然在跑,其实stop方法是在run函数运行完后才执行的。就算没有运行完你就调用了,他还是需要把run函数运行完。这里使用了interrupt()这个方法,使用后将自己的线程置空。当开启时,再重新new一个。并且在while判断的条件里多添加了一个标志变量,辅助控制下载。

运行的效果图:

好吧,界面有点丑,至于UI什么的请让美工设计师做吧。

至于怎么复写Adapter我就不说了,这不是这篇关注的问题。

我的代码写的并不好,如果有更好的方式,请告诉我,跪谢。

至于ListView的优化,我以后还会写一篇的。

这周的另外两篇,一篇关于fragment,一篇关于自定义view。

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

时间: 2024-08-04 20:00:44

Android - SimpleAdapter适配器支持的组件及Listview模拟下载的相关文章

Android 快速开发系列 打造万能的ListView GridView 适配器

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自[张鸿洋的博客] 1.概述 相信做Android开发的写得最多的就是ListView,GridView的适配器吧,记得以前开发一同事开发项目,一个项目下来基本就一直在写ListView的Adapter都快吐了~~~对于Adapter一般都继承BaseAdapter复写几个方法,getView里面使用ViewHolder模式,其实大部分的代码基本都是类似的

Android UI组件----自定义ListView实现动态刷新

[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3910541.html 联系方式:[email protected] [正文] 一.具体步骤: (1)在activiy_main.xml中加一个ListView控件:再添加一个item的模板activity_main_item.xml,加一个底部加载的视图activity_main_load.xml

Android常见UI组件之ListView(一)

使用ListView显示一个长的项列表 1.新建一个名为"BasicView5"的Android项目: 2.修改BasicView5.java文件,修改后的程序如下: package com.example.basicview5; import android.os.Bundle; import android.app.Activity; import android.app.ListActivity; import android.view.Menu; import android.

Android常见UI组件之ListView(二)——定制ListView

Android常见UI组件之ListView(二)--定制ListView 这一篇接上篇,展示ListView中选择多个项及实现筛选功能~ 1.在位于res/values文件夹下的strings.xml文件中添加如下代码: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">BasicView5</strin

Android Api Component---翻译Fragment组件(一)

Fragment代表了在Activity中的一种或者一部分行为,你可以在单个的activity中连接多个fragment来构建一个多面板的UI,并且在多个activity中重复使用一个fragment,你可以把fragment想象成为activity的一个模块化片段,它有它自己的生命周期,接收它自己的输入事件,还有就是当activity运行的时候,你也能添加或者移除fragment. 一个frgment必须被嵌入在一个activit中,并且这个fragment的生命周期直接被它的主activit

Android图表日历控件组件

1.图表引擎 - AChartEngine AChartEngine是一款基于Android的图表绘制引擎,它为Android开发人员提供了非常多有用的图表绘制工具类,假设你须要在Android应用中加入可视化统计的功能,那么AChartEngine是一个不错的选择. 官方站点:https://code.google.com/p/achartengine/ 2.图表引擎 - MPAndroidChart MPAndroidChart是一款基于Android的开源图表库.MPAndroidChar

Android进阶笔记10:Android 万能适配器

1. Android 万能适配器      项目中Listview GridView几乎是必用的组件,Android也提供一套机制,为这些控件绑定数据,那就是Adapter.用起来虽然还不错,但每次都需要去继承一个BaseAdapter,然后实现里面的一大堆方法,而我们每次最关心的无非就是getView方法,其余的方法几乎都是相同代码.这里是不是就可以优化起来呢?在其次,我们在使用Adapter的时候,为了优化性能,常常会创建一个Holder.而Holder里面每次存放的都是View,对Hole

Android support library支持包常用控件介绍(二)

谷歌官方推出Material Design 设计理念已经有段时间了,为支持更方便的实现 Material Design设计效果,官方给出了Android support design library 支持库,让开发者更容易的实现材料设计的效果.顺便推荐官方的一个图标库:Material Icons 控件名称 NavigationView FloatingActionButton TextInputLayout Snackbar TabLayout AppBarLayout Coordinator

Android基础入门教程——2.4.2 ListView简单实用

Android基础入门教程--2.4.2 ListView简单实用 标签(空格分隔): Android基础入门教程 本节引言: 一口气把Android入门网络编程的章节写完了,本节我们来继续学习没有讲完的UI控件部分, 回顾上一节,我们介绍了Adapter适配器的概念,然后学习了三个最简单的适配器的使用: ArrayAdapter,SimpleAdapter和SimpleCursorAdapter,而本节给大家讲解的是第一个 需搭配Adapter使用的UI控件:ListView,不过在版本中被R