安卓基础第三天(Sqlite,ListView)

14 篇文章 0 订阅

(SQLite)数据库

特点
  • 轻量型的数据库
  • 多用于嵌入式开发中
  • 存储数据时不区分类型(除非是主键被定义为Integer这时只能存储64 位整数)
  • 创建数据库可以不指定数据类型
CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20))
CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT, name)
  • SQLite 与MySql 的不同之处
    主键自增长
    1.SQLite 是autoincrement
    2.MySql 是auto_increment
    主键: SQLite 主键一般定义为_id,在做查询时要求主键列名必须是_id(本身不是_id,可以起别名),不然拿不到主键值。
创建数据库
public class PersonOpenHelper extends SQLiteOpenHelper {
    /**
     * 
     * @param context
     * 上下文对象
     * @param name
     *  数据库名称
     * @param factory
     *            游标结果集工厂,如果需要使用则需要自定义结果集工 厂,null 值代表使用默认结果集工厂
     * @param version
     *            数据库版本号,必须大于等于1
     */
    public PersonOpenHelper(Context context, String name,
            CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    /**
     * 数据库第一次被创建时调用该方法,这里面主要进行对数据库的初始化 操作
     */
    public void onCreate(SQLiteDatabase db) {
        // 数据库第一次被创建的时候执行如下sql 语句创建一个person 表
        db.execSQL("create table person(id integer primary key autoincrement,name varchar(20), phone varchar(20), money integer(20),age integer(10));");
    }

    /**
     * 数据库更新的时候调用该方法
     * 
     * @param db
     *            当前操作的数据库对象
     * @param oldVersion
     *            老版本号
     * @param enwVersion
     *            新版本号
     */

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 数据库的版本更新的时候执行
        if (oldVersion == 1 && newVersion == 2) {
            db.execSQL("alter table person add column balance integer");
        }
    }
}

创建一个PersonOpenHelperTest 类,用于测试上面的代码:

    public class PersonOpenHelperTest extends AndroidTestCase {
        public SQLiteDatabase getDataBase() {
            PersonOpenHelper helper = new PersonOpenHelper(getContext(),
                    "person.db", null, 1);
            SQLiteDatabase writableDatabase = helper.getWritableDatabase();
            return writableDatabase;
        }
    }

执行完上面代码,通过DDMS查看
/data/data/包名/databases目录产生了两个文件
person.db:数据库文件
person.db-journal:临时的日志文件,用于事务回滚

数据库并不是初始化MyHelper 时创建
调用getWritableDatabase() 或者getReadableDatabase()时:
- 如果数据库不存在,创建数据库文件,执行onCreate()方法,并获取数据库对象
- 如果数据库存在,版本号没有发生改变,直接获取数据库对象
- 如果数据库存在,版本号提升,先执行onUpgrade()方法,再获取数据库对象

操作数据库(SQLiteDatabase)
  • 和JDBC 访问数据库不同,操作SQLite 数据库无需加载驱动,不用获取连接,直接可以使用
  • 数据库对象缓存,getWritableDatabase()方法最后会使用一个成员变量记住这个数据库对象,下次打开时判断是否重用
  • 常用方法
    1.执行SQL语句
    sqliteDatabase.execSQL() :可以执行insert、delete、update 和CREATETABLE
    sqliteDatabase.rawQuery() :用于执行select 查询语句。
    2.SQLiteDatabase 封装了insert()、delete()、update()、query()四个方法
  • 游标结果集Cursor
    Cursor与JDBC中的ResultSet作用很相似
    moveToNext(): 将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。
//插入
        public void insert(View v){

                db.execSQL("insert into person (name)values(?)", new String[]{"lisi"});
                Toast.makeText(this, "插入数据成功", 0).show();
            }
//查询            
        public void query(View v){

          Cursor cursor = db.rawQuery("select * from person",null);
          //移动游标,返回值为true表示没有移动到数据集的最后(空),如果为false已经数据集的最后(没有数据了)
          while(cursor.moveToNext()){
             int id = cursor.getInt(0);
             String name = cursor.getString(1);

             System.out.println("id="+id+"; name="+name);
          }

          Toast.makeText(this, "查询数据成功", 0).show();
        }
//更新
      public void update(View v){

            db.execSQL("update person set name='wangwu' where id=?", new Object[]{1});
            Toast.makeText(this, "更新数据成功", 0).show();

        }
//删除
      public void delete(View v){

            db.execSQL("delete from person where id=?", new Object[]{1});
            Toast.makeText(this, "删除数据成功", 0).show();

        }
  • 事务
    public void testTransaction() {
        // 这里的最后一个参数(数据库版本号)设置为2,那么会执行PersonOpenHelper 类中的onUpgrade 方法
        PersonOpenHelper helper = new PersonOpenHelper(getContext(), "person",
                null, 2);
        SQLiteDatabase database = helper.getWritableDatabase();
        try {
            // 开启事务
            database.beginTransaction();
            database.execSQL(
                    "update person set balance = balance-100 wherename=?",
                    new String[] { "lisi" });
            // 当把int a=1/0;放开的时候,发现抛出异常,那么事务就会回滚,上面的扣除lsii 的100 元钱不会被真正执行
            // 如果把int a = 1/0;注释掉才发现事务成功了,lisi 的钱被扣除了100 元,同时zhangsan 的钱也多了100元
            int a = 1 / 0;
            database.execSQL(
                    "update person set balance = balance+100 where name=?",
                    new String[] { "zhangsan" });
            // 设置事务成功,也就是只有当代码执行到此行,才代表事务已经成功
            database.setTransactionSuccessful();
        } finally {
            // 提交事务,如果setTransactionSuccessful()方法已经执行,则beginTransaction()后的语句执行成功

            // 否则,事务回滚到开启事务前的状态
            database.endTransaction();
        }
    }

TIPS:
在批量修改数据的时候,
由于事务是在进行事务提交时将要执行的SQL 操作一次性打开数据库连接执行,
其执行速度比逐条执行SQL 语句的速度快了很多倍。
因此当我们开发中遇到对数据库的批量操作那么,使用事务是提高效率的重要原则。

查看数据库
1.通过SQLite Expert 工具

在DDMS 视图中打开/data/data/包名/中,导出数据库文件
然后打开SQLite Expert 软件,将person 数据拖拽到如下图的左侧区域即可
这里写图片描述

2.通过Android sqlite3 工具

这里写图片描述

ListView控件

ListView 是我们Android 中最重要的控件之一,是用于对数据进行列表展示的件。

  • 屏幕上可以展示几个控件, ListView 就初始化几个,节省内存,防止内存溢出。
  • 通过使用convertView 对创建的视图对象进行复用ListView 始终保持创建的对象个数为: 屏幕显示的条目的个数+ 1。
  • ListView 自带ScrollView 的功能,可以实现界面滚动。
  • ListView 控件的设计遵循MVC 设计模式:
    mode 数据模型(数据) :要被显示到ListView 上的数据集合
    view 视图(展示数据) : ListView
    controller 控制层(把数据展示到空间上) : 适配器Adapter
使用

使用listview显示数据列表的步骤:
1、在布局文件中添加一个listview控件
2、在代码中找到这个listview控件
3、创建一个数据适配器为listview填充数据

ps:布局文件的名字必须全部都是小写字母!
1. 创建ListView 展示样式布局文件,文件名为listview_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <ImageView
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/ic_launcher" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/tv_username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="用户名" />

        <TextView
            android:id="@+id/tv_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="年龄" />

        <TextView
            android:id="@+id/tv_phone"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
</LinearLayout>

使用并修改该工程默认的Activity 类,MainActivity。该类的主要业务功能有:
(1)调用Dao 获取数据库的全部数据
(2)获取ListView 控件的实例
(3)自定义适配器,继承BaseAdapter,重写getCount 以及getView 方法
int getCount():用于获取要展示的数据的总条数,即ListView 的总长度view getView(int position,View convertView,ViewGroup parent)
参数:
第一个:position:当前要显示的项在ListView 的索引
第二个:convertView:就是被拖出去的View 对象,getView 的返回值,可以利用这个对象使得拖出去即将销毁的条目重用,即缓存对象。ListView 中创建对象的个数=屏幕显示的条目数+1,当滑动屏幕时,被隐藏的项会作为缓存对象,作为getView的参数传递进来。只需修改此缓存对象的内容,直接使用即可,而不需要再重新new一个新的对象出来,节省了内存,防止内存溢出
View view =convertView==null?View.inflate(MainActivity.this,R.layout.item,null):convertView;

public class MainActivity extends Activity {
    private ListView lv;
    private List<Person> persons;

    private PersonDao dao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.lv);
        dao = new PersonDao(this);
        persons = dao.queryAll();
        lv.setAdapter(new MyAdapter());
    }

    private class MyAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return persons.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view;
            if (convertView != null) {
                view = convertView;
            } else {
                view = View.inflate(MainActivity.this, R.layout.listview_item,
                        null);
            }
            TextView tv_username = (TextView) view
                    .findViewById(R.id.tv_username);
            TextView tv_age = (TextView) view.findViewById(R.id.tv_age);
            TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone);
            Person person = persons.get(position);
            tv_age.setText("年龄:" + person.getAge() + "");
            tv_phone.setText("电话:" + person.getPhone());
            tv_username.setText("姓名:" + person.getName());
            return view;
        }
    }
}
Listview优化

1.复用旧的convertView
2.利用ViewHolder 减少findviewByid 的时间
3.如果只涉及到一个Item 的某一个控件的更改, 不应该去刷新整个ListView(notifyDataSetChanged())而是给这个控件使用setTag(Position)的方式设置不同的tag,然后使用ListView.findViewByTag,找到这个对应的控件进行更改(什么时候需要使用notifyDataSetChanged,当有一个条目添加或者删除,这个时候就必须刷新)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值