Android基础第三天
1. SharedPreference
SharedPreference的基本操作代码
使用步骤:
1. 获取到 sp =this.getSharedPreferences("config", 0);
2. 获取编辑器 Editor editor = sp.edit();
3. editor.putString(key,value) putInt()putDouble()
4. editor.commit();
5. 获取数据 sp.getString(key,dafvalue); sp.getInt()...
注意:SharedPreference保存数据在data/data/<包名称>/…
案例+代码
界面上有一个checkbox的勾选框以及一个可以拖动的进度条,记录勾选框的状态值以及进度条的进度值,当下次进入应用的时候回显上次的状态值。通过该案例可以学习到两个新的控件:CheckBox和Seekbar,以及巩固sharedprefrence的使用。
1. 界面布局实现:
<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="vertical"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="65dip">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="8dip"
android:text="是否开启音效"
android:textSize="22sp"/>
<CheckBox
android:id="@+id/cb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="8dip"/>
</RelativeLayout>
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="#11000000">
</View>
<SeekBar
android:id="@+id/seekBar1"
android:max="100"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
2. 初始化控件和sp,最好做成成员变量,方便使用。
private CheckBox cb;
private SeekBar seekbar;
private SharedPreferences sp;
@Override
protectedvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cb = (CheckBox) findViewById(R.id.cb);
seekbar = (SeekBar) findViewById(R.id.seekBar1);
sp =getSharedPreferences("config", 0);
//回显控件的状态
boolean isChecked = sp.getBoolean("isChecked", false);
cb.setChecked(isChecked);
int progress = sp.getInt("progress", 0);
seekbar.setProgress(progress);
3. 给checkbox注册一个勾选状态变化的监听器以及给seekbar注册一个拖动变化的监听器:
//给checkbox注册一个勾选状态变化的监听器
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
publicvoid onCheckedChanged(CompoundButtonbuttonView, boolean isChecked) {
//勾选状态发生变化调用的方法
Log.i(TAG,"当前状态:"+isChecked);
Editoreditor = sp.edit();
editor.putBoolean("isChecked", isChecked);
editor.commit();
}
});
//注册一个拖动变化的监听器
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
//停止拖动调用的方法
@Override
publicvoid onStopTrackingTouch(SeekBarseekBar) {
int progress = seekBar.getProgress();
Log.i(TAG,"当前进度:"+progress);
Editoreditor = sp.edit();
editor.putInt("progress", progress);
editor.commit();
}
//开始拖动调用的方法
@Override
publicvoid onStartTrackingTouch(SeekBarseekBar) {
}
//在拖动的过程中调用的方法
@Override
publicvoid onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});
4. 当进入应用的时候,在activity的oncreate方法中取出sp的值回显checkbox的状态值以及seekbar的拖动值。注意在初始化控件后面去操作。
//回显控件的状态
boolean isChecked = sp.getBoolean("isChecked", false);
cb.setChecked(isChecked);
int progress = sp.getInt("progress", 0);
seekbar.setProgress(progress);
注意:第一次进入应用的时候sp中没有存储值,所以取的是第二个参数我们设置的默认值比如false和0,代表没有勾选,进度条进度为0.
2. Xml格式数据的生成和解析
使用xml 作为数据交互的载体是Android 中非常重要的功能,比如天气预报数据、短信备份数据、讯录数据都可以以xml 的格式通过网络传输。
Xml生成:
Android为我们提供了一个专门用于生成XML数据的API:XmlSerializer, 该api 内部已经实现了对特殊字符的处理,代码如下:
try {
// 采用Android的api面向对象的生成xml文件.
// 1.得到xml文件的序列化器
XmlSerializer serializer =Xml.newSerializer();
// 2.指定序列化器的一些初始参数
File file = new File(getFilesDir(), name + ".xml");
FileOutputStream os = new FileOutputStream(file);
serializer.setOutput(os, "utf-8");
// 3.写xml文件.
serializer.startDocument("utf-8", true);//写开头
serializer.startTag(null, "student");//开始标签
serializer.startTag(null, "name");
serializer.text(name);//文本标签
serializer.endTag(null, "name");//结束标签
serializer.startTag(null, "number");
serializer.text(number);
serializer.endTag(null, "number");
serializer.startTag(null, "sex");
serializer.text(sex);
serializer.endTag(null, "sex");
serializer.endTag(null, "student");
serializer.endDocument();//写结尾
os.close();
Toast.makeText(this, "保存数据成功", 0).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "保存数据失败", 0).show();
}
Xml的解析
解析XML文件有三种方式:
1. DOM解析 是一种基于对象的API,它会将XML文件的所有内容以文档树方式存放在内存中,然后允许使用DOM API遍历XML树、检索所需的数据,这样便能根据树的结构以节点形式来对文件进行操作。
由于DOM需要将整个XML文件以文档树的形式存放在内存中,消耗内存比较大,在Android下不介意使用该种方式进行解析。
2. SAX解析 会逐行扫描XML文档,当遇到标签时触发解析处理器,采用事件处理的方式解析XML。它在读取文档的同时即可对XML进行处理,不必等到文档加载结束,相对快捷,而且也不需要将整个文档加载进内存,因此不存在占用内存的问题,可以解析超大XML。但是,SAX解析只能用来读取XML的数据,无法进行增删改。
3. PULL解析 跟SAX解析类似,也是基于事件处理的方式。PULL解析器是一个开源的Java项目,既可以用于Android应用,也可以用与JavaEE程序。Android已经集成了PULL解析器,因此,在android中最常用的解析方式就是PULL解析。
SAX和PULL解析对比:
Pull 解析器的运行方式与SAX 解析器相似,都属于事件驱动模式。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch 对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text 类型元素的值。
SAX 解析器的工作方式是自动将事件推入事件处理器进行处理,因此你不能控制事件的处理主动结束;而Pull 解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析。
Android下使用PULL方式解析XML文件的代码如下:
try {
//学生信息的xml文件存在
//1.获取到一个xml解析器
XmlPullParser parser =Xml.newPullParser();
//2.设置解析器的初始化参数
FileInputStreaminputStream = new FileInputStream(file);
parser.setInput(inputStream,"utf-8");
//3.解析xml文件
int type = parser.getEventType(); //得到第一个事件的类型.
System.out.println("type:"+type);
StringBuilder sb = new StringBuilder();
//当事件类型不是文档的结尾则一直遍历每一个节点
while(type!=XmlPullParser.END_DOCUMENT){
if(type==XmlPullParser.START_TAG){
//开始节点
//判断节点的名称
if("name".equals(parser.getName())){
StringnameStr = parser.nextText();
System.out.println("姓名:"+nameStr);
sb.append("姓名:"+nameStr+"\n");
}elseif("number".equals(parser.getName())){
StringnumberStr = parser.nextText();
System.out.println("学号:"+numberStr);
sb.append("学号:"+numberStr+"\n");
}elseif("sex".equals(parser.getName())){
StringsexStr = parser.nextText();
System.out.println("性别:"+sexStr);
sb.append("性别:"+sexStr+"\n");
}
}
type =parser.next();//获取下一个事件类型
System.out.println("type:"+type);
}
inputStream.close();//浪费资源造成内存泄漏!
tv_result.setText(sb.toString());
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "解析学生信息失败", 0).show();
}
3. Sqlite数据库
SQLite 是一款内置到移动设备上的轻量型的数据库, SQLite 数据库是无类型的,Android 系统内置了SQLite,并提供了一系列API 方便对其进行操作。
使用SQLiteOpenHelper创建数据库
SQLiteOpenHelper是Android 提供的一个抽象工具类,负责管理数据库的创建、升级工作。如果我们想创建数据库,就需要自定义一个类继承SQLiteOpenHelper,然后覆写其中的抽象方法。
代码:
/**
* 定义一个我们自己的数据库创建的帮助类
*
*/
publicclass MyDataBaseOpenHelper extends SQLiteOpenHelper {
/**
* @param context
* 上下文
* @param test
* .db 数据库文件的名称
* @param null 默认游标工厂从数据库文件的头部开始的
* @param 1 version 数据库的版本号最小是1
*/
public MyDataBaseOpenHelper(Contextcontext) {
super(context, "test.db", null, 2);
}
/**
* 当数据库第一次被创建的时候调用的方法.这个方法只会执行一次, 一般在这个方法里面初始化数据的表结构.
*/
@Override
publicvoid onCreate(SQLiteDatabase db) {
System.out.println("数据库 oncreate");
db.execSQL("create table student (_idinteger primary key autoincrement, name varchar(20), phone varchar(30))");
}
/**
* 当数据库需要被更新的时候调用的方法数据库只能升级不能降级
*
* @param oldVersion
* 旧的数据库的版本
* @param newVersion
* 新的数据库的版本
*/
@Override
publicvoid onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
System.out.println("数据库要被更新了,onupgrade");
// db.execSQL("alter tablestudent add account varchar(20)");
}
}
注意:
上面的代码我们只是定义了一个MySQLiteOpenHelper类继承了SQLiteOpenHelper 类。在onCreate()方法中通过执行sql 语句实现表的创建。onUpgrade()方法只有在数据库版本发生变化的情况下才会执行。
如果只是创建出来该类并不会真正的去创建数据库,而是需要通过执行helper.getWritableDatabase()或者hepler.getReadableDatabase():
publicclass MainActivity extends Activity {
@Override
protectedvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//这一句代码执行完毕数据库是不会被创建的.
MyDataBaseOpenHelper helper= new MyDataBaseOpenHelper(this);
//下面这一行代码执行了数据库才会被创建
helper.getWritableDatabase();
}
}
上面的代码如果第一次执行,则会创建一个数据库文件,创建的数据库文件位于/data/data/包名/databases/目录中。如果数据库已经创建,则只是打开数据库而不会再去创建。
数据库的增删改查
刚才创建了MySQLiteOpenHelper类,通过该类可以获取SQLiteDatabase 对象。而SQLiteDatabase对象则可实现对数据库的增删改查操作。
使用纯SQL语句实现
增 (db.execSQL(sql,Object[]{}))
sql-->insertinto tableName(columnName1,columnName2,...) values (?,?,...)
删 (db.execSQL(sql,Object[]{}))
sql-->deletefrom tableName where columnName=?
改 (db.execSQL(sql,Object[]{}))
sql-->updatetableName set columnName1 = ? where columnName2 = ?
查 (db.rawQuery(sql,Object[]{}))
sql-->select* from tableName where columnName = ?
表中增加列 (db.execSQL(sql))
sql-->altertable tableName columnName type
注意:
使用纯SQL 语句操作适合SQL 比较熟练的程序员。如果SQL掌握的不好,没关系,Android 提供了一套API 可以帮助我们完成以上操作。
使用Android下的API实现
增
ContentValuesvalues = new ContentValues();
values.put(columnName,value);
db.insert(tableName,null,values); //第一个参数表名; 第二个参数:如果ContentValues 为空,那么默认情况下是不允许插入空值的,但是如果给该参数设置了一个指定的列名,那么就允许ContentValues 为空,同时给该列插入null 值。第三个参数:要插入的数据
删
//第一个参数:表名;第二个参数:删除条件;第三个参数:用于替换第二个参数的?; 返回值:删除成功的个数
db.delete(tableName,"name=?", new String[]{value});
改
ContentValuesvalues = new ContentValues();
values.put(columnName,value
db.update(tableName,values, "name=?", new String[] { value });
查
Cursorcursor = db.query(tableName, 需要查询的列, "name=?", newString[]{value},null,null, 排序);
注意:
1. contentValues该类底层是Map数据结构 values.put(key,values): key 对应数据库表中字段 value是想插入的值
2. tableName 是表名,不是数据库名
3.使用db进行增删改查的时候注意用完进行db.close()释放资源
4.cursor对象是数据库查询完毕后封装的一个结果集,可以通过moveToNext判断是否还有下一个可获取的值,通过cursor.getString(index)获取对应的值;
这里的index对应的是查询的时候查询的哪一列:0对应columName1;1对应columNmae2……
两种SQLiteDatabase的不同
SQLiteOpenHelper 有两个方法均可返回SQLiteDatabase对象:
1.getWritableDatabase()
该方法返回的对象和另外一个方法返回的对象没有任何差异,返回的对象对数据库都可以进行读、写操作,当磁盘已满或者权限不足的情况下该方法会抛出异常。
2.getReadableDatabase()
跟另外一个方法相比,在磁盘已满的情况下,该方法不会抛出异常,而是返回一个只读的数据库操作对象。根据这两种方法返回对象的差异,如果需要对数据库进行查询操作则推荐使用后者,如果添加、修改、删除数据则推荐使用前者。
数据库的升级
在创建MySQLiteOpenHelper对象的时候需要传递一个int 类型的version 参数,代表数据库的版本号,数值从1 开始。如果在new MySQLiteOpenHelper 对象的时候传递的version 大于先去创建的version,那就会导致系统回调onUpgrade方法,从而实现了数据库的升级。
一旦对象被new出来实例化发现版本变大则会调用onUpgrade方法进行更新;
Sqlite工具的使用
sqlite3 是Android 内置的操作数据库工具,使用该工具可以直接对SQLite 数据库进行操作。
操作步骤:
1、在命令行界面使用adbshell 命令进入linux 内核
2、使用cd 命令进入数据库所在目录(数据库的路径为”/data/data/应用包名/databases/数据库”)
3、使用”sqlite3 数据库名”进入数据库操作模式
学生客户端的实现步骤