MVC模式

MVC的基本原理就是通过Controller连接View和Model。当View中所显示的数据发生变化时,会通知Controller,然后由Controller调用Model中的相关方法执行相应的数据修改操作。反之,当Model中的数据发生变化时,也会通知Controller,由Controller通知View更新显示内容。如此一来,就使得数据部分与视图部分相分离,任何一方发生改变都不会影响到另一方。

而在android中,MVC的一个常见应用就是ListView显示数据。V代表的就是显示控件;M代表的是各种数据源,可以是自己定义的List或者数组,也可以是数据库,文件等;C代表的是Adapter类,android中比较常见的adapter有:BaseAdapter,ArrayAdapter,SimpleAdapter等。

ListView通过setAdapter方法实现了其和一个Adapter对象的绑定,Adapter一般通过getView()方法返回当前列表项所要显示的View对象,完成了对Model中数据的读取。

当Model发生变化时,会调用BaseAdapter.notifyDataSetChanged()方法通知组件数据已然变化,此时Adapter就会调用getView()方法重新显示组件内容。

ListView:间接继承自抽象类AdapterView

常见方法:

void  setOnItemClickListener(AdapterView.OnItemClickListener listener) 

void  setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) 

void  setAdapter(ListAdapter adapter) 

Adapter:是一个接口

主要的方法:

abstract int  getCount()  返回要显示的item总数

abstract Object  getItem(int position)  根据item索引返回该item

abstract long  getItemId(int position)  返回item的id。

abstract View  getView(int position, View convertView, ViewGroup parent)返回一个用来展示数据源中索引为position的View对象。

BaseAdapter是一个间接实现了Adapter接口的抽象类

自定义Adapter继承BaseAdapter时,需要提供上面四个方法的实现。主要要实现的是getCount()和geView()方法。

ArrayAdapter<T>, CursorAdapter, SimpleAdapter则直接继承自BaseAdapter,实现了其抽象方法。

ListView示例1:展示一个字符串数组中的各个字符串。

 main_layout.xml:

 <?xml version="1.0" encoding="utf-8"?>

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

     android:layout_width="match_parent"

     android:layout_height="match_parent"

     android:orientation="vertical" >

     <ListView

         android:id="@+id/listview"

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         />

 </LinearLayout>

MainActivity.java:

 public class MainActivity extends Activity {

       private String[] strs;

       @Override

       protected void onCreate(Bundle savedInstanceState) {

            // TODO Auto-generated method stub

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main_layout);

            strs = new String[]{"aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii"};

            ListView lv = (ListView) findViewById(R.id.listview);

            lv.setAdapter(new MyBaseAdapter());

       }

       class MyBaseAdapter extends BaseAdapter{

            @Override

            public int getCount() {

                  return strs.length;

            }

            @Override

            public Object getItem(int position) {

                  // TODO Auto-generated method stub

                  return null;

            }

            @Override

            public long getItemId(int position) {

                  return 0;

            }

            @Override

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

                  TextView tv = null;

                  tv = new TextView(MainActivity.this);

                  Log.i("listview", position+"get view");

                  tv.setText(strs[position]);

                  tv.setTextSize(40);

                  tv.setTextColor(Color.RED);

                  return tv;

            }

       }

 }

运行结果:

注意到,每次滚动屏幕显示新的item,或将滚出屏幕上方的item重新显示出来都会调用getItem()方法。而上面的代码中每次都会新建一个TextView,这样做是存在问题的。

getView(int position, View convertView, ViewGroup parent),其中参数convertView在允许的情况下,会保存旧的View实例,以便拿来复用。所以,可以利用该参数来优化上面的getView()实现。

代码修改如下:

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

                  TextView tv = null;

                  Log.i("listview", position+"get view");

                  if(convertView == null){
10
11 tv = new TextView(MainActivity.this);
12
13 }
14
15 else{
16
17 tv = (TextView) convertView;
18
19 }

tv.setText(strs[position]); tv.setTextSize(40); tv.setTextColor(Color.RED); return tv; }

其实,若只是显示数组中的内容,直接使用ArrayAdapter会比较方便:

MainActivity.java修改如下:

 private String[] strs;

       @Override

       protected void onCreate(Bundle savedInstanceState) {

            // TODO Auto-generated method stub

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main_layout);

            strs = new String[]{"aaa","bbb","ccc","ddd","eee","fff","ggg","hhh","iii"};

            ListView lv = (ListView) findViewById(R.id.listview);

            ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs);
18
19 lv.setAdapter(adapter);
}

运行结果:

其中android.R.layout.simple_list_item_1是系统自带的一个布局id。

一般来说,在ListView中显示的东西可能更加复杂点,只靠一个TextView肯定解决不了,这时,就可以为ListView中的item根据需要编写一个布局文件。

如:item_layout.xml:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

     android:layout_width="match_parent"

     android:layout_height="match_parent"

     android:orientation="horizontal" >

     <ImageView

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         android:src="@drawable/hero"

         />

     <TextView

         android:id="@+id/tv_name"

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         android:textSize="35sp"

         />

 </LinearLayout>

用于在线性布局中水平显示一个图片和一个字符串。

修改MyAdapter内部类的getView():

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

                  View view = null;

                  Log.i("listview", position+"get view");

                  if(convertView == null){

                       view = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_layout, null);

                  }

                  else{

                       view =  convertView;

                  }

                  TextView tv = (TextView) view.findViewById(R.id.tv_name);

                  tv.setText(strs[position]);

                  return view;

            }

运行结果:

另一种可能常用的Adapter是SimpleAdapter。

构造函数:SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)

context指定上下文

data指定存放数据的list对象,list中存放的是Map对象。

resource指定item的布局文件id

from和to是有序的,两者中的元素必须一一对应,from中存放的是list中每个map对象中的key值,to存放的是显示对应key获取的值的控件的id。

如:item_layout.xml:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

     android:layout_width="match_parent"

     android:layout_height="match_parent"

     android:orientation="horizontal" >

     <ImageView

         android:id="@+id/iv"

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         />

     <TextView

         android:id="@+id/tv_name"

         android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         android:textSize="35sp"

         />

 </LinearLayout>

MainActivity.java中修改如下:

 protected void onCreate(Bundle savedInstanceState) {

            // TODO Auto-generated method stub

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main_layout);

            ListView lv = (ListView) findViewById(R.id.listview);

            List<Map<String,Object>> data = new ArrayList<Map<String,Object>>();

            Map<String,Object> map = new HashMap<String, Object>();

            map.put("img", R.drawable.hero);

            map.put("str", "aaa");

            data.add(map);

            map = new HashMap<String, Object>();

            map.put("img", R.drawable.hero);

            map.put("str", "bbb");

            data.add(map);

            map = new HashMap<String, Object>();

            map.put("img", R.drawable.hero);

            map.put("str", "ccc");

            data.add(map);

            map = new HashMap<String, Object>();

            map.put("img", R.drawable.hero);

            map.put("str", "ddd");

            data.add(map);

            map = new HashMap<String, Object>();

            map.put("img", R.drawable.hero);

            map.put("str", "eee");

            data.add(map);

            SimpleAdapter sa = new SimpleAdapter(this, data, R.layout.item_layout, new String[]{"img","str"}, new int[]{R.id.iv,R.id.tv_name});

            lv.setAdapter(sa);

 }

显示结果:

关于ListView的事件监听:

AdapterView中定义了几个设置事件监听的方法,如:

void  setOnItemClickListener(AdapterView.OnItemClickListener listener)

void  setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener)

ListView间接继承了AdapterView,所以,要处理事件监听时,可以调用ListView中相关的方法。

注:如果调用了ListView的setOnClickListener()方法,会报如下错误:

java.lang.RuntimeException: Don't call setOnClickListener for an AdapterView. You probably want setOnItemClickListener instead

setOnItemClickListener()方法示例:

 ListView lv = (ListView) findViewById(R.id.listview);

            lv.setOnItemClickListener(new OnItemClickListener() {

                  @Override

                  public void onItemClick(AdapterView<?> parent, View view,

                             int position, long id) {

                       Log.i("listview","onClick");

                       Log.i("listview",view.toString());

                       Log.i("listview",position+"");

                       Log.i("listview",id+"");

                       TextView tv = (TextView) view.findViewById(R.id.tv_name);

                       Toast.makeText(MainActivity.this, tv.getText(), Toast.LENGTH_LONG).show();

                  }

            });

运行结果:

ListView先学到这,等学了数据库操作,也许会用到CursorAdapter等,用到时再学。

android菜鸟学习笔记14----Android控件(三) ListView的简单使用的更多相关文章

  1. Android开发学习笔记-自定义组合控件的过程

    自定义组合控件的过程 1.自定义一个View 一般来说,继承相对布局,或者线性布局 ViewGroup:2.实现父类的构造方法.一般来说,需要在构造方法里初始化自定义的布局文件:3.根据一些需要或者需 ...

  2. Android开发学习笔记-自定义组合控件

    为了能让代码能够更多的复用,故使用组合控件.下面是我正在写的项目中用到的方法. 1.先写要组合的一些需要的控件,将其封装到一个布局xml布局文件中. <?xml version="1. ...

  3. WPF-学习笔记 动态修改控件Margin的值

    原文:WPF-学习笔记 动态修改控件Margin的值 举例说明:动态添加一个TextBox到Grid中,并设置它的Margin: TextBox text = new TextBox(); t_gri ...

  4. android菜鸟学习笔记13----Android控件(二) 自定义控件简单示例

    有时候,可能觉得系统提供的控件太丑,就会需要自定义控件来实现自己想要的效果. 以下主要参考<第一行代码> 1.自定义一个标题栏: 系统自带的标题栏很丑,且没什么大的作用,所以我们之前会在o ...

  5. android菜鸟学习笔记12----Android控件(一) 几个常用的简单控件

    主要参考<第一行代码> 1.TextView: 功能与传统的桌面应用开发中的Label控件相似,用于显示文本信息 如: <TextView android:layout_width= ...

  6. Android学习笔记_30_常用控件使用

    一.状态栏通知(Notification): 如果需要查看消息,可以拖动状态栏到屏幕下方即可查看消息.发送消息的代码如下: public void sendNotice(View v){ int ic ...

  7. android 学习笔记四:控件

    1.android:gravity 指定控件的基本位置,比如居中.居右等位置 Top:顶部 bottom:底部 left:居左 right:居右 center_vertical:垂直居中 center ...

  8. android菜鸟学习笔记7----android布局(二)

    3.FrameLayout:帧布局 如同Flash或者photoshop中图层的概念,在上面的图层遮盖下面的图层,没被遮到的地方仍然显示出来. 右击res/layout,然后在弹出的菜单中选择new, ...

  9. android菜鸟学习笔记30----Android使用百度地图API(一)准备工作及在应用中显示地图

    1.准备工作: 百度地图API是免费开放的,但是需要申请API Key: 1)先注册一个百度开发者帐号 2)进入百度开放服务平台http://developer.baidu.com/ 3)进入LBS云 ...

随机推荐

  1. 交换机的MAC地址作用

    交换机的MAC地址在交换机进行数据交换时是没有作用的,因为交换机并不对转发的数据帧进行拆包重封装. 如果只是完成数据帧交换,则可以不要MAC地址(仅指二层交换机,三层交换机完成路由功能自然每个端口得有 ...

  2. Algorithm | Vector

    因为平常用的话只是vector的一些非常简单的功能,基本上把它当数组来用,现在也只是把这一部分写了一些. template<class T> class XVector { public: ...

  3. 转:浅析Collections.sort

    浅析Collections.sort 问题引入   在之前的一次Java上机实习中,老师布置了一道很简单的题: 从控制台输入10个整数,对它们进行升序排序并输出.   考虑到只有10个数,需要比较的次 ...

  4. Spring MVC的各种参数绑定方式(请求参数用基础类型和包装类型的区别)(转)

    1.基本数据类型(以int为例,其他类似): Controller代码: @RequestMapping("saysth.do") public void test(int cou ...

  5. 基于WPF系统框架设计(6)-整合MVVM框架(Prism)

    应用场景 我们基础的框架已经搭建起来了,现在整合MVVM框架Prism,在ViewModel做一些逻辑处理,真正把界面设计分离出来. 这样方便我们系统开发分工合作,同时提高系统可维护性和灵活性. 具体 ...

  6. ArcGIS 10.2 二次开发,兼容Visual Studio 2012二次开发,完美安装教程

    GIS 经常安装是常有的事,每次重装系统都要浪费大半天去安装这个.所以凑这一次安装,把这个软件重新安装的步骤整理了一下,希望对大家有所帮助.这次整理的内容的关键优点是,对常见的出错内容进行了归纳整理. ...

  7. Scut游戏服务器引擎6.0.5.1发布

    1. 修正缓存删除时不会更新到Redis的问题 2. 修正Model组合3个以上子类时Change事件未绑定的问题 3. 修正中间层MySql与MsSql数据库Sql语句分页问题

  8. Performing User-Managed Database-18.7、Performing Complete User-Managed Media Recovery

    18.7.Performing Complete User-Managed Media Recovery 完毕一致性备份,把数据库恢复到当前的scn是最好的结果.能够恢复整个数据库.恢复单个表空间.或 ...

  9. vue-cil 和 webpack 中本地静态图片的路径问题解决方案

    1.小于8K的图片将直接以base64的形式内联在代码中,可以减少一次http请求. 2.大于8k的呢?则直接file-loader打包, 这里并没有写明file-loader.但是确实是需要安装,否 ...

  10. js 原生方法获取所有兄弟节点

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...