Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

Android--SQLite适配器

$
0
0

如果大家看过我写的Android中SQLite的基本使用(二)这篇博客的话,应该知道,在实现数据库查询的时候,因为用了 rawQuery() 和 query(),而这两个方法返回的是一个 Cursor 的对象,我把 Cursor 转换成了我们熟悉的 list 集合,但这有些麻烦,其实 SQLite 给我们提供了 Cursor 中读取数据库数据的适配器,可以直接接收 Cursor 游标类型的数据源,分别是 SimpleCursorAdapter 和 CursorAdapter。这次我就来讲讲它们的使用。

数据库文件

关于数据库的创建,我在Android上SQLite的基本应用(一)中有详细的介绍,这里就不提了。

现在有一个数据库,里面有一张 PERSON 表,插入了30条数据,如下:

我们要在程序中使用它,自然得把它放到模拟器的 sdcard 目录下:

我们可以看到 info.db 确实被导入模拟器里了。当然我们也可以直接将文件拖进模拟器,这里只是讲下如何导入文件而已。

布局文件

因为我们要做的数据的适配,所以我们的 xml 中要有 listView:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

除此之外,既然是 listView,自然需要一个 item.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="horizontal">

    <TextView
        android:id="@+id/tv_id"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="_id"
        android:textColor="#aa0000"
        android:textSize="20sp"
        android:gravity="center_horizontal"/>

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="name"
        android:textColor="#00aa00"
        android:textSize="20sp"
        android:gravity="center_horizontal"/>

    <TextView
        android:id="@+id/tv_age"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:text="age"
        android:textColor="#0000aa"
        android:textSize="20sp"
        android:gravity="center_horizontal"/>

</LinearLayout>

常量类

Constant.java:

public class Constant {
    public static final String DATABASE_NAME = "info.db"; //数据库名称
    public static final int DATABASE_VERSION = 1; //数据库版本
    public static final String TABLE_NAME = "person"; //表名
    public static final String _ID = "_id";
    public static final String NAME = "name";
    public static final String AGE = "age";
}

SimpleCursorAdapter

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private ListView mListView;
    private SQLiteDatabase db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.lv);

        //1.获取数据库查询的数据源
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "info.db";

        db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
        Cursor cursor = db.rawQuery("select * from " + Constant.TABLE_NAME, null);

        //2.将数据源数据加载到适配器中
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item, cursor,
                new String[]{Constant._ID, Constant.NAME, Constant.AGE},
                new int[]{R.id.tv_id, R.id.tv_name, R.id.tv_age},
                SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

        //3.将适配器的数据加载到控件
        mListView.setAdapter(adapter);
    }
}

ListView 是一个适配器控件,使用适配器控件一共有三步:

  1. 从数据库得到数据源
  2. 把数据源的数据加载到适配器
  3. 把适配器的数据展示到控件中

第一步

既然要从数据库取数据,自然要有一个 SQLiteDatabase 的对象,在这里我用了 openDatabase() 这个方法。

openDatabase(String path, CursorFactory factory, int flags)

path:表示当前打开数据库存放路径。获取 sdcard 目录的方法相信大家都不陌生了吧,如果在其它目录,只要依样画葫芦找到路径即可。
factory:游标工厂,指定为空即可。
flags 表示打开数据库的操作模式,可读可写。这里只读即可。

打开了数据库,自然要获取数据,这里用 rawQuery 或者 query 都可以,这样我们就得到了 Cursor 游标。

第二步

有了数据源,就要把它放到适配器里。SimpleCursorAdapter 与 SimpleAdapter 原理相似。

SimpleAdapter 是一个 list 集合存放着 Map 键对,通过 key 将每个 Map 传入 ListView 的 item 里。

Cursor 我们可以看作一张表,把每行的数据放到 ListView 的每个 item 里去,SimpleCursorAdapter 就是这样的工作原理。

SimpleCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to, int flags)

context:上下文
layout:表示适配器控件中每项item对应的 id
cursor:表示cursor数据源
from:表示cursor中数据表字段的数组
to:表示展示字段对应值的控件资源 id
flags:设置适配器的标记,设置观察者模式,观察者模式就是有一个观察者观察适配器的数据是否改变,改变就提醒。

第三步

将适配器与 ListView 绑定,这里都是一样的。使用SimpleCursorAdapter 的时候有一个要注意的是,它只识别 _id 为主键,如果你要用 SImpleCursorAdapter 的话,你的主键得是 _id,否则会报错。

现在就可以运行了,不过我们当然不能忘记,我们既然访问了 SD 卡,读写的权限自然不能不加,这里就不写出来啦。大家也要注意如果你的是Android6.0 以上的机子你就要手动添加权限了。

CursorAdapter

写 CursorAdapter 在获取到数据源 Cursor 时都是一样的,因为 CursorAdapter 是抽象类,所以不能像 SimpleCursorAdapter 一样去 new 出实例,在这里我使用内部类来继承 CursorAdapter。

CursorAdapterActivity.java:

public class CursorAdapterActivity extends AppCompatActivity {

    private ListView lv;
    private SQLiteDatabase db;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.lv);

        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "info.db";

        db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
        Cursor cursor = db.rawQuery("select * from " + Constant.TABLE_NAME, null);
        MyCursorAdapter adapter = new MyCursorAdapter(this, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        lv.setAdapter(adapter);
    }

public class MyCursorAdapter extends CursorAdapter{

        public MyCursorAdapter(Context context, Cursor c, int flags) {
            super(context, c, flags);
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            View view = LayoutInflater.from(CursorAdapterActivity.this).inflate(R.layout.item, null);
            return view;
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            TextView tv_id = (TextView) view.findViewById(R.id.tv_id);
            TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
            TextView tv_age = (TextView) view.findViewById(R.id.tv_age);

            tv_id.setText(cursor.getInt(cursor.getColumnIndex(Constant._ID)) + "");
            tv_name.setText(cursor.getString(cursor.getColumnIndex(Constant.NAME)));
            tv_age.setText(cursor.getInt(cursor.getColumnIndex(Constant.AGE)) + "");

        }
    }
}

CursorAdapter 会让我们必须有三个函数,构造方法自不必说,需要我们重写的就是 newView() 和 bindView()。

newView:并不是每次都被调用的,它只在实例化的时候调用,数据增加的时候也会调用,但是在重绘(比如修改条目里的 TextView 的内容)的时候不会被调用。表示创建适配器控件中每个item对应的对象

View newView(Context context, Cursor cursor, ViewGroup parent)

context:上下文
cursor:数据源 cursor 对象
parent:当前 item 的父布局
最后返回每项的 item 的 view 对象。

bindView:在绘制 Item 之前一定会调用 bindView 方法,它在重绘的时候也同样被调用。通过newView()方法确定了每个item展示的view对象,在bindView中对布局中的控件进行填充。

void bindView(View view, Context context, Cursor cursor)

view:由 newView() 返回的每个 view 对象
context:上下文
cursor:数据源 cursor 对象

在这里稍微多提一下,CursorAdapter 还有一个重要的方法 changeCursor (Cursor cursor),调用此方法后会把当前的 Cursor 置为新传过来的 Cursor,把原来的 Cursor 返回去并关掉。

当我们的Cursor变化时调用此方法 adapter.changeCursor(cursor),它的功能类似于 adapter.notifyDataSetChanged() 方法。

我们在配置文件把 CursorAdapterActivity 换掉 MainActivity,再来运行一下。

因为这两种不过是适配器的不同,所以当然不会有什么问题。如果我们只是想要将数据库的数据展示出来,那就可以不用 Cursor 转 List 创建实体类的方法,用SimpleCursorAdapter 和 CursorAdapter,将 Cursor 获取后直接放到我们的适配器控件当中,这样就使我们的代码更简洁,使用起来也更方便。

结束语:本文仅用来学习记录,参考查阅。

作者:HardWorkingAnt 发表于2017/4/27 20:18:57 原文链接
阅读:25 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>