1、数据库介绍(SQLite)
什么情况下使用数据库?
在有大量相似的数据存储的时候,就需要用到数据库
File类在什么时候创建文件?
在调用输出流的时候创建
抽象类的做法:继承下,然后重写方法
2、数据库的创建
[1]、创建一个类继承SQLiteOpenHelper
/*
构造方法参数说明
context : 上下文
name : 数据库名称
factory : 相当于结果集ResultSet,为空就行
version : 数据库版本号,必须要大于等于1,并且只能升级不能降级使用
*/
public class MyOpenHelper extends SQLiteOpenHelper {
public MyOpenHelper(Context context) {
super(context, "pr.db", null, 1);
}
- //数据库第一次创建的时候调用,特别适合做表结构的初始化
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
}
- //数据库升级的时候调用,这个方法适合做表结构的更新
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
[2] 实例化MyOpenHelper,获取数据库对象
MyOpenHelper myOpenHelper = new MyOpenHelper(getApplicationContext());
//如果数据库未创建就会首先创建数据库,如果已经创建,那么就以读写方式打开
SQLiteDatabase writableDatabase = myOpenHelper.getWritableDatabase();
//如果数据库未创建就会首先创建数据库,如果已经创建,那么就以读写方式打开 和
//getWritableDatabase()相比, 如果磁盘满了的话,这个方法会返回一个只读对象
SQLiteDatabase readableDatabase = myOpenHelper.getReadableDatabase();
3、 数据库的onCreate()和onUpgrade()
onCreate()在数据库创建的时候调用,适合进行初始化,在SQLite中id一般写成_id,SQlite底层不区分数据类型,全部以String类型存储
意外收获:
[1] 添加数据库表的列 alter table table_name add column_name 类型
[2] 修改MySQL的密码
这种方式也需要先用root命令登入mysql,然后执行:
SET PASSWORD FOR root=PASSWORD('123456');
4、使用SQL语句对数据库进行增删改查
[1]添加一条数据 ,删除,修改操作都相似
readableDatabase.execSQL("insert into table info(name,phone)value(?,?)",new Object[]{"zhangsan","13888888"});
[2] 查找的方法
//查询会返回一个Cursor对象,这个对象很像ResultSet,使用moveToNext()进行移动,
Cursor cursor = readableDatabase.rawQuery("select * from info", null);
if(cursor != null && cursor.getCount() > 0){
while(cursor.moveToNext()){
//列标是从0开始的
Log.d("MainActivity",cursor.getString(1));
}
[3]
优点:灵活,适合多表查询
缺点:容易写错
[4] 打开sqlite数据库文件,控制台语句
sqlite3 数据库文件
[5] 改变dos的编码方式语句
chcp 936 改为gbk编码
chcp 65001 改为utf-8编码
5、使用谷歌封装好的api对数据库增删改查
[1]插入一条记录
//[1]获取数据库对象
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//[2]new一个ContentValues对象,用于传参
ContentValues contentValues = new ContentValues();
//[3]向ContentValues中添加数据
contentValues.put("name","王五");
contentValues.put("phone","110");
//[4]调用google封装的api进行插入数据
long info = db.insert("info", null, contentValues); //参数说明:1:表名,2:如果不添加数据,那么第二个参数就会用到,插入的数据
//[5]输出插入结果
if(info > 0)
Toast.makeText(this,"插入成功",Toast.LENGTH_SHORT).show();
else
Toast.makeText(this,"插入失败",Toast.LENGTH_SHORT).show();
//[6]关闭数据库
db.close();
[2]删除
//[1]获取数据库对象
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//[2]执行删除语句
int info = db.delete("info", "name=?", new String[]{"王五"});
if (info > 0)
Toast.makeText(this, "删除了"+info+"条记录", Toast.LENGTH_SHORT).show();
else
Toast.makeText(this,"删除失败",Toast.LENGTH_SHORT).show();
//[3]关闭数据库
db.close();
[3]修改数据
//[1]获取数据库对象
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//[2]new ContentValues存储需要升级的键值对
ContentValues contentValues = new ContentValues();
contentValues.put("name","张三");
contentValues.put("phone","114");
//[3]执行修改语句
int info = db.update("info", contentValues, "name=?", new String[]{"王五"});
//[4]查看修改结果
if(info > 0)
Toast.makeText(this,"修改了"+info+"条记录",Toast.LENGTH_SHORT).show();
else
Toast.makeText(this,"修改失败",Toast.LENGTH_SHORT).show();
//[4]关闭数据库
db.close();
[4]查询数据
//[1]获取数据库对象
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
//[2]获取Cursor
Cursor info = db.query("info", null, "name=?", new String[]{"王五"}, null, null, null);
//[3]遍历查看结果
if(info.getCount() > 0){
while(info.moveToNext())
{
Log.d("query",info.getString(1));
Log.d("query",info.getString(2));
}
}
//[4]关闭数据库
db.close();
6、两种增删改查的优缺点
[1]使用传统的SQL语句
优点:灵活,适合多表查询
缺点:容易写错
[2]使用google封装的api
优点:不容易写错sql语句
缺点:不容易进行多表查询
7、android中数据库事务的介绍
[1]数据库的事务指的是在同时进行多个任务的时候,要么同时成功,要么失败后回滚,
[2]android中的事务的标准写法
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
db.beginTransaction(); //开启事务
try {
db.execSQL("update account set money=money-100 where name=\"张三\""); //这两句代表要执行的逻辑
db.execSQL("update account set money=money+100 where name=\"王五\"");
db.setTransactionSuccessful(); //如果两个事件都完成了,那么就设置成功的标志
Toast.makeText(this,"转账成功",Toast.LENGTH_SHORT).show();
} catch(Exception e){
Toast.makeText(this,"服务器忙,请稍后再试",Toast.LENGTH_SHORT).show();
}finally {
db.endTransaction(); //结束事务
}
8、ListView入门
[1]在布局文件中定义ListView
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
[2]定义ListView的适配器 继承baseAdapter
private class MyAdapter extends BaseAdapter
[3]实现baseAdapter中的getCount()方法和getView()方法
//这个方法决定ListView一共有多少的item
@Override
public int getCount() {
return 6; //返回多少显示多少
}
//这个方法决定要显示的内容
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
Button btn = new Button(getApplicationContext()); //返回什么显示什么
btn.setText("点吧"+i);
return btn;
}
显示如下
9、ListView优化
[1] 为什么优化,对于应用内存的使用应该越少越好,并且安卓虚拟机为每个应用分配的内存也是一定的,如果大量消耗内存,唯一的结果就是用户等待,只到将无用资源释放掉才可以继续等待,那么怎么解决呢?
在getView里面有这个一个参数View view
public View getView(int i, View view, ViewGroup viewGroup)
[2] 这个view是一个old view,当一个item被滑出屏幕并不会被直接回收,而是进入了一个backStack栈中,而这个参数 代表的就是这个对象,所以是可以复用的
Button btn;
if(view == null){ //如果view为空,那么说明没有可复用的对象,那么创建
btn = new Button(getApplicationContext());
Log.d("view","创建对象");
}else{
btn = (Button) view; //如果view不为空,那么就存在可复用对象
Log.d("view","复用对象");
}
btn.setText("点吧"+i);
[3] 如果拖得快的话,几乎每一条都是在创建对象,但是
这样更改后,只是创建了第一屏的对象,然后就是复用,就像扶梯似的,每下去一个,就会从下面出现一个
[4] 如果在ListView中,高是wrap_content,那么android会进行多次校验,以保证内容正确的展示,这也是效率低的原因之一,所以在使用的时候,还是用match_parent比较好
10、ListView显示数据的原理
[1] MVC:Model View Controller
M层:处理数据和业务逻辑 (数据)
V层:处理界面的显示结果 (view)
C层:起到桥梁作用,来控制V层和M层通信 (adapter)
11、ListView显示复杂界面
由于在getView()方法中的返回值决定了显示的item的形式,如何返回一个复杂的item呢?
[1] 定义item要显示 的界面,再写一个布局文件
[2] 将item加载到item中
public View getView(int i, View view, ViewGroup viewGroup) {
View view1;
if(view == null){
//[1]加载复杂布局
view1 = View.inflate(getApplicationContext(),R.layout.item_layout,null);
}else{
view1 = view;
}
return view1;
}
[3给ListView设置适配器
//获取ListView实例
ListView listView = (ListView) findViewById(R.id.lv);
//设置适配器
listView.setAdapter(new MyAdapter());
12、获取打气筒常用api
//下面的这几种获取方式没有区别,使用其中的任何一种都能获取打气筒
- //[1]使用View的静态方法获取
view1 = View.inflate(getApplicationContext(),R.layout.item_layout,null);
//[2]使用布局资源加载器
view1 = LayoutInflater.from(getApplicationContext()).inflate(R.layout.item_layout,null);
//[3]使用获取打气筒服务获取
LayoutInflater systemService = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
systemService.inflate(R.layout.item_layout,null);
13、arrayAdapter使用
[1] 什么时候适合用ArrayAdapter?
在数据相似的时候,可以是普通文本,也可以是一些其他的对象,但是在item中不能存在多个控件,这种情况ArrayAdapter无法使用
[2] 使用方法
// [1] 创建ArrayAdapter对象
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.item_layout,R.id.test1,objects);
//参数一:上下文
//参数二:布局文件
//参数三:布局中的具体控件
//参数四:数据对象
//[2] 获取ListView对象
ListView lv = (ListView) findViewById(R.id.lv);
//[3] 设置适配器
lv.setAdapter(adapter);
14、权重
[1]为了大体的指定空间的位置,一般用在线性布局里面
android:layout_weight="1"
14、simpleAdapter使用
// [1] 获取ListView控件
ListView listView = (ListView)findViewById(R.id.lv);
// [2] 准备加载适配器需要的数据
List<Map<String, String>> data = new ArrayList<>();
Map<String,String> map1 = new HashMap<>();
map1.put("name","张三");
map1.put("phone","1388888");
Map<String,String> map2 = new HashMap<>();
map2.put("name","赵云");
map2.put("phone","1388888");
Map<String,String> map3 = new HashMap<>();
map3.put("name","关羽");
map3.put("phone","1388888");
Map<String,String> map4 = new HashMap<>();
map4.put("name","刘备");
map4.put("phone","1388888");
Map<String,String> map5 = new HashMap<>();
map5.put("name","貂蝉");
map5.put("phone","1388888");
Map<String,String> map6 = new HashMap<>();
map6.put("name","曹操");
map6.put("phone","1388888");
data.add(map1);
data.add(map2);
data.add(map3);
data.add(map4);
data.add(map5);
data.add(map6);
// [3] 加载适配器
/**
* 适配器的参数说明
* 参数一:上下文
* 参数二: List<Map<java.lang.String, ?>> data,
* 参数三:资源文件
* 参数四、五:对应显示的内容from to
*/
SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(),data,R.layout.item_layout,new String[]{"name","phone"},new int[]{R.id.tv_name,R.id.tv_phone});
// [4] 设置适配器
listView.setAdapter(adapter);
15、读出数据库中的数据,然后展示在ListView中