本来这周想写三篇的,结果这第一篇就不知道该如何起笔。语言表达能力真的需要提高啊。其实有好多想写的,最近这几天又接触到了以前听过但是没有去考虑的一些点。这篇的起因曾经做过一道题,我当时很不理解,我看有评论还是很多跟我当时想法一样的,一直没来得及去追究,终于还是放心不下,去看了一下,发现我错了。原题如下:
使用SimpleAdapter作为 ListView的适配器,行布局中支持下列哪些组件?
其实看看这个题,人家说的是SimpleAdapter,想当然的把SimpleAdapter当作了最基本的Adapter了(至于其他的适配器,自己可以看一下),所以就感觉答案应该是没问题的,那这个SimpleAdapter到底是支持什么?这就要从SimpleAdapter的源码看了,我把重要的摘出来看,首先看一下这个SimpleAdapter的构造函数。
public SimpleAdapter(Context context, List extends Map> 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我们知道,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 ? "" : 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");
}
}
}
}
}
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
然后直接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> mData;
private Context mContext;
private LayoutInflater mInflater;
public MyAdapter(Context context,List> 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 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。