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

xiaoxiao2021-02-28  68

(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,当有一个条目添加或者删除,这个时候就必须刷新)

转载请注明原文地址: https://www.6miu.com/read-2629154.html

最新回复(0)