导语
数据库&弹框介绍
一、数据库
.mdf .access(微软) .db(Android)
1.1 一般数据库sql语句(如:MySQL)
- 数据库创建 - create table person ( _id integer primary key autoincrement, name varchar(20), age integer );
- 插入一条数据 - insert into person (name, age) values ('lisi', 23);
- 删除一条数据 - delete from person where name = 'lisi';
- 修改一条数据 
update person set age = 18 where name = 'zhangsan';
- 查询一条数据
select * from person where name = 'zhangsan';
- 查询多条数据 - select * from person;
##1.2 语言的发展:
机器语言 -> 汇编语言 -> c语言 -> c++ -> java(c+++) -> c#(c++++) -> 自然语言
##1.3 android下数据库:sqlite创建的步骤
- 1.类继承SQLiteOpenHelper(数据创建的帮助类,oncreate,onUpgrade)
- 2.重写oncreate()方法 ,数据库第一次被创建的时候调用的方法。适合数据库表结构的初始化. - create table info (_id integer primary key autoincrement, name varchar(20), phone varchar(20))
- 3.重写onUpgrade(),数据库被更新的时候调用的方法.数据库的版本号增加的时候调用。 
- 4.添加helper类的构造方法。 指定数据库的名称,版本号,游标工厂默认null
注意
    情况一: 用户第一次安装应用,只会走oncreate()方法,不走onUpgrade()方法,所以开发者需将所有的表创建都要放在oncreate()中,此时会记录当前数据库版本号(也就是最新的数据库版本号)
    情况二: 用户在第一次安装完成后,版本升级不会走oncreate()方法,去走onUpgrade()方法,并根据数据库版本号对数据库进行增删改查
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class PersonSQLiteOpenHelper extends SQLiteOpenHelper {
/**
 * 把已知的固定值写好(数据库名称,版本号), 外边只传一个Context进来就可以初始化该帮助类了
 * @param context
 */
public PersonSQLiteOpenHelper(Context context){
    // 转调4个参数的构造函数
    this(context, "itheima58.db", null, 3);
}
/**
 * 创建一个数据库帮助类, 去创建\ 打开\ 管理 数据库.
 * @param context 上下文.
 * @param name 设置数据库名称
 * @param factory  CursorFactory 定义一个结果集, 游标工厂. 
 *                     Cursor 游标(结果集, 保存了对数据库的引用, 指针)
 *                     设置为null表示使用系统默认游标工厂
 * @param version 数据库的版本, 从1开始 >= 1  
 */
public PersonSQLiteOpenHelper(Context context, String name,
        CursorFactory factory, int version) {
    super(context, name, factory, version);
}
/**
 * 当数据库第一次被创建时调用, 这里进行表结构的创建和初始化.
 */
@Override
public void onCreate(SQLiteDatabase db) {
    System.out.println("PersonSQLiteOpenHelper: onCreate");
    // 执行创建语句, 创建person表
    db.execSQL("create table person(_id integer primary key autoincrement, name varchar(20),age integer)");
}
/**
 * 数据库升级时调用, 在这里做表结构的更新,删除等操作.
 */
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    System.out.println("PersonSQLiteOpenHelper: onUpgrade " + "旧版本号: " + oldVersion + " 新版本号: " + newVersion);
    if(oldVersion == 2 && newVersion == 3){
        // 版本从2升级到3, 给person表添加一个balance余额字段
        db.execSQL("alter table person add column balance integer");
    }    
}
}
##1.4数据库文件创建的位置
- 数据库路径:- /data/data/包名/databases/itheima58.db
- 数据库在创建的时候不指定里面的内容,默认创建只有一张表 metadata保存系统语言环境。
 
- DAO (Databses Access Object)
##1.5 android下数据库增删改查
- 自己写sql语句查询- void - db.execSQL() 增删改
- cursor - db.rawQuery() 查询
- 灵活, 级联查询, 执行效率高
 
- 系统API查询 (重要)- 方便, 不易出错, 效率稍低
 
##1.6 两种增删改查方法的优缺点
- 自己写sql语句  - 灵活
- 资源占用小
- 可以实现表的级联查询
 
- google的现成API- 方便
- 资源开销比较大
- 有返回值
 
##1.7 注意:
- 操作数据库 一定要记得把数据库给关闭掉。 
- cursor 用完后,也记得关闭`
- getReadableDatabase()
- getWriteableDatabase()返回的是同一个数据库的实例,
- 区别就是数据库返回的时候是否加锁。
##1.8 SQL 语句的注入问题及解决
String name = “lisi or 1 = 1”
delete from person where name = lisi or 1 = 1;
如何防止, 绑定参数防止注入, 利用占位符号 ?
##1.9 cmd命令行查看数据库流程:sqlite3
- adb shell 进入控制台
- # cd /data/data/com.itheima.aqlitedb/datebases 进入数据库文件夹
- # ls  展示数据库文件夹中的文件
- # sqlite3 itheima58.db  查看itheima58.db数据库,进入sqlite>模式
- sqlite> .table 查看所有表
- sqlite> select * from person; 查看person表的所有记录
- sqlite> .mode column 设置以列的形式格式化展示
- sqlite> select * from person; 查看person表的所有记录
- sqlite> .exit 退出 
sqlite3 itheima58.db 查看itheima58.db数据库,进入sqlite>模式
.table 查看所有表
.mode column 设置以列的形式格式化展示
.exit 退出
##1.10 如果出现中文乱码 需要修改cmd的编码集 65001 utf-8
chcp 65001 更改cmd窗口的编码,默认是gb2312
##1.11 自己写sql语句
- void - db.execSQL() 增删改
- cursor - db.rawQuery() 查询
-下面缩写的示例都是定义在dao(数据访问层)中,想用那个功能直接调用————–
- 插入一条数据, 指定名称和年龄 - public void insert(String name, int age) { // 获取可写数据库 SQLiteDatabase db = helper.getWritableDatabase(); db.execSQL("insert into person (name, age) values (?, ?)", new Object[]{name, age}); }
- 根据指定名称删除一条数据 - public void delete(String name) { - SQLiteDatabase db = helper.getWritableDatabase(); db.execSQL("delete from person where name = ?", new Object[]{name});- } 
- 修改一条数据, 修改指定人的年龄 - public void update(String name, int age) { - SQLiteDatabase db = helper.getWritableDatabase(); db.execSQL("update person set age = ? where name = ?", new Object[]{age, name});- } 
- 查询一条数据 - public void querySingleRecord(String nameArg) { - SQLiteDatabase db = helper.getReadableDatabase(); // ------------------------------------------------- 重点 ↓ // 游标, 对数据库的引用 Cursor cursor = db.rawQuery("select * from person where name = ?", new String[]{nameArg}); if(cursor != null && cursor.moveToFirst()){ // 是否能移动到第一个 int _id = cursor.getInt(0); String name = cursor.getString(1); int age = cursor.getInt(2); System.out.println("_id: " + _id + " name: " + name + " age: " + age); } // 关闭应用 cursor.close(); // ------------------------------------------------- 以上 ↑ }
- 查询所有数据 - public List - queryAll() { - SQLiteDatabase db = helper.getReadableDatabase(); Cursor cursor = db.rawQuery("select * from person", null); ArrayList<Person> persons = new ArrayList<Person>(); if(cursor != null && cursor.getCount() > 0){ // 循环遍历 // 获取列数 int columnCount = cursor.getColumnCount(); System.out.println("columnCount: " + columnCount); while(cursor.moveToNext()){ // 直到下一个没有数据, 返回false // cursor.getColumnIndex("_id")// 根据列名获取列的索引 int _id = cursor.getInt(cursor.getColumnIndex("_id")); String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); Person person = new Person(_id, name, age); System.out.println(person.toString()); persons.add(person); } } cursor.close(); return persons; }
##1.12 google的现成API操作数据库
- 插入一条数据 测试用例注意配置 - db.insert(“person”, “name”, values);
 
public class PersonDao3 {//dao封装插入功能
    // 通过构造函数 创建数据库 
    private PersonSQLiteOpenHelper helper;
    public PersonDao3(Context context){
        helper = new PersonSQLiteOpenHelper(context);
    }
    /**
     * 插入一条记录,指定姓名和年龄
     * @param name
     * @param age
     */
    public void insert(String name,int age){
        // 获取可写数据库
        SQLiteDatabase db = helper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("age",age);
        // nullColumnHack 第二个参数 任意指定表的一个列名, 用来插入一条内容是空的数据
        //若第二个参数填为null,当插入一条内容是空的数据时,会报错
        db.insert("person", "name", values);
        db.close();
    }
}
//测试用例-注意继承AndroidTestCase-----------------
public class TestCase3 extends AndroidTestCase{
    public void testInsert(){
        PersonDao3 dao = new PersonDao3(getContext());
        dao.insert("zhangsan", 24);
    }
}
- 删除一条数据 - db.delete(“person”, “name = ?”, new String[]{name}); - /** - 根据name字段删除一条记录
- @param name 
 */
 public void delete(String name){
 //获取可写的数据库
 SQLiteDatabase db = helper.getWritableDatabase();
 //根据name字段删除一条记录
 db.delete(“person”, “name=?”, new String[]{name});
 db.close();
 }- //测试Android系统API对数据库的删除功能 
 public void testDelete(){
 PersonDao3 dao = new PersonDao3(getContext());
 dao.delete(“zhangsan”);
 }
 
 
- 修改一条数据 - db.update(“person”, values ,”name = ?”, new String[]{name}); 
 (参数1:要修改的表,参数2:要修改的值,参数3:判断条件,参数4:条件的参数)
/**
 * 修改功能:根据表的name字段修改age字段
 * @param name
 * @param age
 */
public void updata(String name,int age){
    //获取可写的数据库
    SQLiteDatabase db = helper.getWritableDatabase();
    ContentValues values = new ContentValues();
    //若修改一条记录中多个字段,则对应字段名,传入对应参数
    values.put("age",age);
    db.update("person", values, "name=?", new String[]{name});
    db.close();
}
//测试Android系统API对数据库的修改功能
public void testUpdata(){
    PersonDao3 dao = new PersonDao3(getContext());
    dao.updata("zhangsan1",32);
}
- 查询一条数据 - Cursor cursor = db.query("person", // 指定表名 null, // 指定要获取的列 , null 所有列 "name = ?", // 选择条件 new String[]{nameArg}, // 条件的参数 null, // 分组 null, // 分组 null); // 排序
public void querySingleRecord(String nameArg){
    //获取可读的数据库
    SQLiteDatabase db = helper.getReadableDatabase();
    Cursor cursor = db.query("person",   //指定要查询的表明
            null,//指定要查询的列,null指查询所有字段
            "name=?",//判断的条件
            new String[]{nameArg}, //条件的参数
            null, //分组
            null, //分组
            null //排序
            );
    if (cursor!=null&&cursor.moveToFirst()) {// 是否能移动到第一个
        int _id = cursor.getInt(0);
        String name = cursor.getString(1);
        int age = cursor.getInt(2);
        System.out.println("_id: " + _id + " name: " + name + " age: " + age);
    } 
    //关闭应用
    cursor.close();
    db.close();
}
//测试Android系统API对数据库的查询单一记录功能
public void testQuerySingleRecord(){
    PersonDao3 dao = new PersonDao3(getContext());
    dao.querySingleRecord("zhangsan1");
}
- 查询多条数据 - Cursor cursor = db.query("person", null, null, null, null, null, "_id desc" // 按照_id倒叙排列 ); /** * 查询所有数据 */ public List<Person> queryAll(){ //获取可读的数据库 SQLiteDatabase db = helper.getReadableDatabase(); //查询person表,返回游标 Cursor cursor = db.query("person", null, null, null, null, null, null); //创建List集合 ArrayList<Person> persons = new ArrayList<Person>(); if (cursor!=null&&cursor.getCount()>0) { while (cursor.moveToNext()) {//直到下一个没有数据, 返回false int _id = cursor.getInt(cursor.getColumnIndex("_id")); String name = cursor.getString(cursor.getColumnIndex("name")); int age = cursor.getInt(cursor.getColumnIndex("age")); Person p = new Person(_id, name, age); persons.add(p); } } //关闭资源 cursor.close(); db.close(); return persons; } //测试Android系统API对数据库的查询所有功能 public void testQueryAll(){ PersonDao3 dao = new PersonDao3(getContext()); List<Person> persons = dao.queryAll(); }
数据库的事务
- Transaction
- 安全, 转账安全!!!
 
- 效率, 速度快!!!
 
流程:
// 1. 开启事务
db.beginTransaction();
try {
    ...
    处理业务逻辑
    ... 
    // 2. 设置回滚点/成功点 , (要么全成功, 要么全失败) 可以设置多个
    db.setTransactionSuccessful();
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    // 3. 结束事务
    db.endTransaction();
}
/**
 * 转账安全
 */
public void testTransaction(){
    PersonSQLiteOpenHelper helper = new PersonSQLiteOpenHelper(getContext());
    SQLiteDatabase db = helper.getWritableDatabase();
    // 转账1000
    // xiaozhang  10000 
    // 从xiaozhang账户转1000到xiaosan账户
    // ------------------------------------------------- 重点 ↓
    // 1. 开启事务
    db.beginTransaction();
    try {
        db.execSQL("update person set balance = balance - 1000 where name = 'xiaozhang'");
        // int result = 10 / 0;
        // xiaosan 0
        db.execSQL("update person set balance = balance + 1000 where name = 'xiaosan'");
        // 2. 设置回滚点/成功点 , (要么全成功, 要么全失败) 可以设置多个
        db.setTransactionSuccessful();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        // 3. 结束事务
        db.endTransaction();
    }
    // ------------------------------------------------- 以上 ↑
}
/**
 * 提高效率
 */
public void testTransaction1(){
    PersonSQLiteOpenHelper helper = new PersonSQLiteOpenHelper(getContext());
    SQLiteDatabase db = helper.getWritableDatabase();
    // ------------------------------------------------- 重点 ↓
    // 1. 开启事务
    db.beginTransaction();
    long start = System.currentTimeMillis();
    try {
        for (int i = 0; i < 50; i++) {
            db.execSQL("insert into person (name, age, balance) values ('wang"+i+"', "+i+", 100"+i+")");
        }
        // 2. 设置回滚点/成功点 , (要么全成功, 要么全失败) 可以设置多个
        db.setTransactionSuccessful();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        // 3. 结束事务
        db.endTransaction();
        long duration = System.currentTimeMillis() - start;
        System.out.println("插入10000条数据, 消耗时长: " + duration);
        //不开启事务: 插入10000条数据, 消耗时长: 22198
         //开启事务: 插入10000条数据, 消耗时长: 3655
    }
    // ------------------------------------------------- 以上 ↑
}
#二、数据库的内容同步显示到界面(ListView),重点。
##2.1、listview工作的原理
- mvc 设计模式。- model 数据模型 Person
- view 视图 ListView
- controller 控制器 Adapter 数据适配器, 将数据集合以特定的方式组织到界面上
 
##2.2、Listview 使用步骤
- 写ui界面 xml文件 ListView
- 寻找listview
- 实现listview的数据适配器 adapter
- 给listview设置adapter
##2.3、扩展内容(非常不重要): ScrollView 滚动视图/滚动界面
- (ScrollView写在布局文件中,滚动视图标签中写入线性布局标签,使整个视图可滚动)
        // 1. 查找布局控件
        LinearLayout ll_content = (LinearLayout) findViewById(R.id.ll_content);
        // 2. 准备数据
        PersonDAO3 dao = new PersonDAO3(this);
        List<Person> persons = dao.queryAll();
        // 3. 用代码new出来的控件,给界面添加TextView
        for (int i = 0; i < persons.size(); i++) {
            TextView textView = new TextView(this);
            textView.setText(persons.get(i).toString());
            textView.setTextSize(18);
            // 每次都要创建TextView  OOM
            ll_content.addView(textView);
        }
##2.4、开发的时候如何自定义数据适配器将数据库的内容同步显示到界面,实现复杂的ui界面。
- 1.定义listview布局 写ui界面 xml文件 ListView
- 2.查找listview
- 3.自定义一个复杂BaseAdapter,把listview数据适配器adapater需要的数据准备好
 定义一个xml文件- getCount();返回有多少个条目 List.SIZE() - getView();返回某个位置的View对象(返回每个条目的view对象) - int position 条目的位置 - View convertView 优化用的 - ViewGroup parent ==listview item的父容器,其实就是listview
 修改view对象里面子孩子显示的内容View view = View.inflate(MainActivity.this, R.layout.rl_item, null);view.findViewById();
- 4.把数据适配器设置给listview
##2.5、ListView 列表视图/列表界面 (写在布局文件中)此视图控件通过id获取
- 一旦定义ListView布局,就会出现一屏幕的视图条目,
- 根据每一个视图条目的字体大小不同和手机屏幕大小不同,一屏幕显示的条目个数也不相同,
- 在界面展示时, 一屏幕能放下几条数据, 生成几个View条目
- 在ListView布局下,屏幕能够自行上下滚动,但显示在屏幕上的条目数不变
- 视图条目的位置从零开始
- (如果一屏幕只显示6个视图条目,那么视图条目位置就是从0到5)
- 随着屏幕的上下移动,所显示的条目会变成位置是1到6的条目,2到7的条目
- 屏幕上的每一个条目,都会调用BaseAdapter实现类中的getView()方法。(自己理解的)
- 这是ListView自己完成的功能,
- 而我们要做的就是将每个视图条目都赋上我们从数据库取出来的内容,简单讲就是重写getView()方法。
- 给ListView列表视图设置数据适配器, ListView列表视图此时要向Adapter索取数据,并展示在界面上
-2.4示例——————————-
// 1. 查找ListView控件
ListView lv_content = (ListView) findViewById(R.id.lv_content);
// 2. 准备数据
PersonDAO3 dao = new PersonDAO3(this);
persons = dao.queryAll();//返回的是从数据库取出的一个List集合
System.out.println("persons: " + persons.size());
// 3. 给ListView设置数据适配器, ListView此时要向Adapter索取数据
lv_content.setAdapter(new MyAdapter());
//自定义一个复杂BaseAdapter
class MyAdapter extends BaseAdapter {
    /**
     * 返回有多少个条目
     */
    @Override
    public int getCount() {
        // 返回ListView总共要显示的个数
        return persons.size();
    }
    /**
     * 返回每个位置的条目(返回每个条目的view对象)
     * 一旦ListView设置了Adapter, 就会从这个方法索要View
     * int position 集合的每个位置
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        System.out.println("第" + position + "位置第一次初始化, 新建了一个TextView");
        // position, 条目的位置,要数据View的位置(位置从零开始)
        TextView textView = new TextView(MainActivity.this);
        // 设置文本内容
        textView.setText(persons.get(position).toString());
        // 设置字体大小
        textView.setTextSize(16);
        return textView;
    }
    @Override
    public Object getItem(int position) {
        return null;
    }
    @Override
    public long getItemId(int position) {
        return 0;
    }
}
##2.6、SimpleAdapter 简单数据适配器
- SimpleAdapter适配器 : 显示图片, 文本信息
- //3. 给ListView设置数据适配器, ListView此时要向Adapter索取数据 - lv_content.setAdapter(new SimpleAdapter(context, data, resource, from, to));
- SimpleAdapter适配器四个参数 - context参数 上下文
- data参数    - List
- 一个Map相当于一个条目,通过向Map中put键值对,使此条目好看 
 
- resource参数 布局资源的id 线性布局横向布置,ImageView+TextView
- from参数 new String[]{“图标”,”文本”} 数组里面就是Map集合的key值;
- to参数 new int[]{} 数组里面就是对应布局里面的ImageView的id和TextView的id
- 另外:from数组的每个值绑定to数组每个值,一一对应
 
-2.6示例——————————
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 设置界面布局
    setContentView(R.layout.activity_main);
    // 1. 查找控件
    ListView lv_content = (ListView) findViewById(R.id.lv_content);
    // 2. 准备数据
    List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
    // 填充数据
    data = fillData();
    // 3. 给ListView设置数据适配器, ListView此时要向Adapter索取数据
    lv_content.setAdapter(new SimpleAdapter(this, // 上下文
            data,   // 封装了数据的集合
            R.layout.item_listview, 
            new String[]{"图片内容", "文本内容"}, 
            new int[]{R.id.iv_header, R.id.tv_name}));
}
private List<Map<String, Object>> fillData() {
    ArrayList<Map<String, Object>> arrays = new ArrayList<Map<String, Object>>();
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("图片内容", R.drawable.f000);
    map.put("文本内容", "大笑");
    arrays.add(map);
    map = new HashMap<String, Object>();
    map.put("图片内容", R.drawable.f001);
    map.put("文本内容", "调皮");
    arrays.add(map);
    map = new HashMap<String, Object>();
    map.put("图片内容", R.drawable.f002);
    map.put("文本内容", "冷汗");
    arrays.add(map);
    map = new HashMap<String, Object>();
    map.put("图片内容", R.drawable.f003);
    map.put("文本内容", "偷笑");
    arrays.add(map);
    map = new HashMap<String, Object>();
    map.put("图片内容", R.drawable.f004);
    map.put("文本内容", "拜拜");
    arrays.add(map);
    return arrays;
}
还有两个layout布局文件没粘过来
1.activity_main.xml中定义ListView布局
2.item_listview.xml中定义LinearLayout布局,横向设置,添加ImageView,TextView视图
##2.7、ArrayAdapter 数组适配器
- ArrayAdapter : 只能设置文字 - //第一个参数 this 上下文 //第二个参数 layout布局 在tv_item.xml中定义textview //第三个 string数组 lv.setAdapter(new ArrayAdapter<String>(this, R.layout.tv_item, new String[]{"功能1","功能2","功能3","功能4"}));
##2.8 如何将Xml数据(Layout布局文件)转换成View对象?
- LayoutInflater (填充器, 打气筒)
- LayoutInflater 打气筒, 将一个xml的布局文件填充成一个View对象, 以便添加到其他View容器中.
-示例:将Xml数据(Layout布局文件)转换成View对象———————–
public class MainActivity extends Activity {
List<Person> persons;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 设置界面布局
    setContentView(R.layout.activity_main);
    // 1. 查找控件
    ListView lv_content = (ListView) findViewById(R.id.lv_content);
    // 2. 准备数据
    PersonDAO3 dao = new PersonDAO3(this);
    persons = dao.queryAll();
    System.out.println("persons: " + persons.size());
    // 3. 给ListView设置数据适配器, ListView此时要向Adapter索取数据
    lv_content.setAdapter(new MyAdapter());
}
class MyAdapter extends BaseAdapter {
    @Override
    public int getCount() {
        // 返回ListView总共要显示的个数
        return persons.size();
    }
    /**
     * 一旦ListView设置了Adapter, 就会从这个方法索要View
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // ------------------------------------------------- 重点 ↓
        LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
        // LayoutInflater 打气筒, 将一个xml的布局文件填充成一个View对象, 以便添加到其他View容器中. 
        // root 你想把这个View填充完之后, 添加到哪个ViewGroup(View容器, LinearLayout, RelativeLayout).
        // root就是这个容器
        //LinearLayout是View的子类
        LinearLayout layout = null;
        if(convertView != null){
            layout = (LinearLayout) convertView;
        }else {
            layout = (LinearLayout) inflater.inflate(R.layout.item_listview, null);
        }
        // ------------------------------------------------- 以上 ↑
        // 找到里边的控件
        // 设置数据
        ImageView iv_header = (ImageView) MainActivity.this.findViewById(R.id.iv_header);
        TextView tv_name = (TextView) layout.findViewById(R.id.tv_name);
        TextView tv_age = (TextView) layout.findViewById(R.id.tv_age);
        TextView tv_balance = (TextView) layout.findViewById(R.id.tv_balance);
        Person person = persons.get(position);
        tv_name.setText(person.getName());
        tv_age.setText(person.getAge() + "");
        tv_balance.setText(person.getBalance() + "");
        return layout;
    }
    @Override
    public Object getItem(int position) {
        return null;
    }
    @Override
    public long getItemId(int position) {
        return 0;
    }
}
}
还有两个layout布局文件没粘过来
1.activity_main.xml中定义ListView布局
2.item_listview.xml中定义LinearLayout布局,横向设置,添加ImageView+LinearLayout,LinearLayout中又添加3个TextView
- BaseAdapter : 最重要的Adapter!!!!!!!!!!!!!!!!!!!!
Android 对话框
- 通过Builder实现通知对话框,列表对话框,单选对话框
- 通知对话框 - /** * 显示通知对话框 示例:通过一个按钮点击,弹出通知对话框 * @param view */ public void showNotifyDialog(View view){ Builder builder = new AlertDialog.Builder(this); // 设置图标 builder.setIcon(android.R.drawable.ic_dialog_alert); // 设置标题 builder.setTitle("提醒:"); // 设置提醒内容 builder.setMessage("当前是移动网络数据, 建议在wifi下观看, 是否继续(土豪随意)"); builder.setPositiveButton("确认", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "确认", 0).show(); } }); builder.setNegativeButton("取消", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "取消", 0).show(); } }); builder.setCancelable(false); // 是否可以通过返回键 关闭 // 直接show(); builder.show();- } 
- 列表对话框 - /** * 显示列表对话框 * @param view */ public void showListDialog(View view){ Builder builder = new AlertDialog.Builder(this); builder.setTitle("选择语言"); String[] strs = new String[]{"java", "c++", "c" , "php", "c#", "c" , "php", "c#"}; builder.setItems(strs, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //点击之后自动跳回上一页,然后执行下面代码,参数2:表示点击了哪一个 System.out.println("which: " + which); } }); builder.show(); }
- 单选对话框 - /** * 显示单选框 * setSingleChoiceItems() * 参数1:字符串数组,要选择的选项 * 参数2:默认选择 * 参数3:点击监听 * @param view */ public void showSingleDialog(View view){ Builder builder = new AlertDialog.Builder(this); builder.setTitle("选择性别:"); final String[] items = new String[]{"男", "女", "中性", "以前男的女的", "以前是女的男的"}; builder.setSingleChoiceItems(items, -1, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { System.out.println("which: " + which); } }); builder.setPositiveButton("确认", null); builder.show(); }
- 多选对话框 - public void showMultiDialog(View view){ Builder builder = new AlertDialog.Builder(this); builder.setTitle("选择兴趣爱好:"); final String[] items = new String[]{"抽烟", "喝酒", "烫头", "编程", "泡妞"}; final boolean[] checkedItems = new boolean[]{true, false, true ,false, false}; builder.setMultiChoiceItems(items,checkedItems , new OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { System.out.println("which: " + which + " isChecked: " + isChecked); checkedItems[which] = isChecked; } }); builder.setPositiveButton("确认", null); builder.show(); }
ProgressDialog
- 进度对话框 - public void showProgressDialog(View view){ - // 显示一个加载的对话框 //ProgressDialog.show(this, "提示: ", "正在加载中,请稍后..."); final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setTitle("提示: "); progressDialog.setMessage("正在加载中..."); // 设置样式为 横向 的 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMax(100); // 显示的时候, 会把进度归零 progressDialog.show(); new Thread(){ public void run() { while(true){ SystemClock.sleep(50); //progressDialog.setProgress(i); progressDialog.incrementProgressBy(1); if(progressDialog.getProgress() >= progressDialog.getMax()){ progressDialog.dismiss(); break; } } }; }.start();- } 
##样式和主题
- 样式设置- res/values/styles.xml中将样式抽取出来
- 就是在styles.xml文件中将view的一些属性抽取出来定义在styles属性中,之后只要调用就行了
 
-样式示例:————————————————–
 <style name="text_style">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_margin">20dp</item>
    <item name="android:background">#660000FF</item>
    <item name="android:padding">15dp</item>
    <item name="android:textColor">#FFFFFF</item>
    <item name="android:textSize">20sp</item>
</style>
<style name="text_style_red" parent="text_style">
    <item name="android:background">#66FF0000</item>
</style>
-样式调用示例:———————————
  <TextView
    style="@style/text_style"
    android:text="功能1" />
<TextView
    style="@style/text_style_red"
    android:text="功能2" />
<TextView
    style="@style/text_style_red"
    android:text="功能3" />
<TextView
    style="@style/text_style"
    android:text="功能4" />
- 主题设置
- 在AndroidManifest.xml中设置
- 在application标签下的Android:theme=””修改值,可改变主题