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. Codeforces 898 B.Proper Nutrition

    B. Proper Nutrition   time limit per test 1 second memory limit per test 256 megabytes input standar ...

  2. 洛谷 P1426 小鱼会有危险吗【模拟/题意理解】

    题目描述 有一次,小鱼要从A处沿直线往右边游,小鱼第一秒可以游7米,从第二秒开始每秒游的距离只有前一秒的98%.有个极其邪恶的猎人在距离A处右边s米的地方,安装了一个隐蔽的探测器,探测器左右x米之内是 ...

  3. 身份识别协议枚举工具ident-user-enum

    身份识别协议枚举工具ident-user-enum   身份识别协议(Ident protocol,IDENT)是一种Internet协议,用于识别使用特定TCP端口的用户身份.服务器开启该服务后,会 ...

  4. Python 集成开发环境(IDE)

      DiscoverSDK网站进行了一次调查 - 什么是最好的Python IDE,这里是调查的结果 ​​​Python是一种非常流行的开源编程语言.得益于无尽的模块选项,Python今天广泛用于脚本 ...

  5. JetBrains软件开发框架下的类似于“.IntelliJIdea2018.1”的配置文件夹的移动

    JetBrains软件开发框架下几款软件,如: 会在C盘用户文件夹下生成很大的配置文件夹(IDE config folder),十分占空间,也影响电脑性能. 这些索引目录移动的原理相似,现在以Idea ...

  6. java中的堆、栈和常量池简介

    一.它们各自存放的数据类型: 堆:存放所有new出来的对象. 栈:存放基本类型的变量数据和对象的应用,对象(new出来的对象)本身并不存在栈中,而是存放在堆中或者常量池中(字符串常量对象存放在常量池中 ...

  7. UIView的任意圆角

    今天在做项目的时候,遇到一个问题,grouped类型的tableview 怎么样才能让他们的一个view 其中一个角圆角? 如上图所示,其实我是用UILabel,但是箭头的位置总是尖的不太好看.设置l ...

  8. Autolayout 03

    Debugging in Code 有两个调试layout问题的阶段. 1. Map from “this view is in the wrong place” to “this constrain ...

  9. Android中的多线程断点续传

    Android多线程断点下载的代码流程解析: 运行效果图: 实现流程全解析: Step 1:创建一个用来记录线程下载信息的表 创建数据库表,于是乎我们创建一个数据库的管理器类,继承SQLiteOpen ...

  10. linux查看端口状态相关命令

    netstat netstat 命令应用是比较频繁的,比如查看端口占用啦,查看端口进程啦,这些时候都是有必要的. netstat命令各个参数说明如下: -t : 指明显示TCP端口 -u : 指明显示 ...