4.1 共享参数SharedPreferences
SharedPreferences按照key-value对的方式把数据保存在配置文件中,该配置文件符合XML规范,文件路径是/data/data/应用包名/shared_prefs/文件名.xml,下面是一个共享参数的XML文件示例:
<?xml verson=’1.0’ encoding=’utf-8’ standalone=’yes’?>
<map>
<string name=”name”>Mr Lee</string>
<int name=”age” value=”30” />
<boolean name=”married” value=”true” />
<float name=”weight” value=”100.0” />
</map>
示例代码:
private SharedPreferences sps;
sps = getSharedPreferences(“share”, Context.MODE_PRIVATE);
getSharedPreferences的第一个参数是文件名,上面的share表示当前使用的共享文件名是share.xml,第二个参数是操作模式,一般都填MODE_PRIVATE表示私有模式
SharedPreferences.Editor editor = sps.edit();
editor.putString(“name”, “Mr Lee”);
editor.putInt(“age”, “30”);
editor.putBoolean(“married”, “true”);
editor.putFloat(“weight”, “100f”);
editor.commit();
String name = sps.getString(“name”, “”);
int age = sps.getInt(“age”, 0);
boolean married = sps.getBoolean(“married”, false);
float weight = sps.getFloat(“weight”, 0);
共享参数的get方法第二个参数表示默认值
(这里例程用了map,有待研究)
4.2 数据库SQLite
SQLite的基本用法:
(1)建表时为避免重复操作,应加上IF NOT EXISTS关键词,例如CREATE TABLE IF NOT EXISTS table_name
(2)删表时为避免重复操作,应加上IF EXISTS关键词,例如DROP TABLE IF EXISTS table_name
(3)添加新列时使用ALTER TABLE table_name ADD COLUMN …
(4)在SQLite中,ALTER语句每次只能添加一列,如果要添加多列,就只能分多次添加
(5)SQLite支持整型INTEGER,字符串VARCHAR,浮点数FLOAT,但不支持布尔类型,布尔类型数要使用整型保存,如果直接保存布尔数据,在入库时SQLite就会自动将其转为0或1
(6)SQLite建表时需要一个唯一标识字段,字段名为_id,每建一张新表都要例行公事加上该字段定义,具体属性定义为_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
(7)条件语句等号后面的字符串值要用单引号括起来,如果没有使用单引号括起来,在运行时就会报错
SQLiteDatabase是SQLite的数据库管理类,我们可以在活动页面代码或任何能取到Context的地方获取数据库示例,参考代码如下:
//创建数据库,如果已存在就打开
SQLiteDatabase db = getApplicationContext().openOrCreateDatabase(“test.db”, Context.MODE_PRIVATE, null);
//删除数据库
getApplicationContext().deleteDatabase(“test.db”);
SQLiteDatabase提供了若干操作数据表的API,常用的方法有3类,列举如下:
1.管理类,用于数据库层面的操作
openDatabase:打开指定路径的数据库
isOpen:判断数据库是否已打开
close:关闭数据库
getVersion:获取数据库的版本号
setVersion:设置数据库的版本号
2.事务类,用于事务层面的操作
beginTransaction:开始事务
setTransactionSuccessful:设置事务的成功标志
endTransaction:结束事务,执行本方法时,系统会判断是否已执行setTransactionSuccessful,如果之前已设置就提交,如果没有设置就回滚
3.数据处理类,用于数据表层面的操作
execSQL:执行拼接好的SQLite控制语句,一般用于建表、删表、变更表结构
delete:删除符合条件的记录
update:更新符合条件的记录
insert:插入一条记录
query:执行查询操作,返回结果集的游标
rawQuery:执行拼接好的SQL查询语句,返回结果集的游标
SQLiteOpenHelper
具体使用步骤如下:
(1)新建一个继承自SQLiteOpenHelper的数据库操作类,提示重写onCreate和 OnUpgrade两个方法,其中onCreate方法只在第一次打开数据库时执行,在此可进行表结构创建的操作;onUpgrade方法在数据库版本升高时执行,因此我们可以在onUpgrade函数内部根据新旧版本号进行表结构变更处理
(2)封装保证数据库安全的必要方法,包括获取单例对象,打开数据库连接,关闭数据库连接
(3)提供对表记录进行增加、删除、修改、查询的操作方法
Cursor的常用方法:
1.游标控制类方法,用于指定游标的状态
Close:关闭游标
isClosed:判断游标是否关闭
isFirst:判断游标是否在开头
isLast:判断游标是否在末尾
2.游标移动类方法,把游标移动到指定位置
moveToFirst:移动游标到开头
moveToLast:移动游标到末尾
moveToNext:移动游标到下一条记录
moveToPrevious:移动游标到上一条记录
move:往后移动游标若干条记录
moveToPosition:移动游标到指定位置的记录
3.获取记录类方法,可获取记录的数量、类型以及取值
getCount:获取结果记录的数值
getInt:获取指定字段的整型值
getFloat:获取指定字段的浮点数值
getString:获取指定字段的字符串值
getType:获取指定字段的字段类型
关于SQLiteOpenHelper的简单“封装”,见Database类的封装.rar
优化记住密码功能:
(1)声明一个UserDBHelper对象,然后在活动页面的OnResume方法中打开数据库连接,在onPause方法中关闭数据库连接,示例代码如下:
@Override
protected void onResume() {
super.onResume();
mHelper = UserDBHelper.getInstance(this, 2);
mHelper.openWriteLink();
}
@Override
protected void onPause() {
super.onPause();
mHelper.closeLink();
}
(2)在登录成功时,如果用户勾选了“记住密码”,就使用数据库保存手机号码与密码在内的登录信息,在loginSuccess函数中增加如下代码:
if(bRemember) {
UserInfo info = new UserInfo();
info.phone = et_phone.getText().toString();
info.update_time = DateUtil.getNowDateTime(“yyyy-MM-dd HH:mm:ss”);
mHelper.insert(info);
}
(3)再次打开登录页面,用户输入手机号完毕后点击密码输入框时,App到数据库中根据手机号查找登录记录,并将记录结果中的密码填入密码框
EditText比较特殊,点击后只是让其获得焦点,再次点击才会触发点击事件。也就是说,要连续点击两次EditText才会处理点击事件,这里提供一个解决办法:先给密码框注册一个焦点变更监听器,比如下面这行代码:
et_password.setOnFocusChangeListener(this);
这个焦点变更监听器要实现接口OnFocusChangeListener,对应的事件处理方法是onFocusChange,将数据库查询操作放在该方法中,详细代码如下:
@Override
public void onFocusChange(View v, boolean hasFocus) {
String phone = et_phone.getText().toString();
if(v.getId() == R.id.et_password) {
if(phone.length() > 0 && hasFocus == true) {
UserInfo info = mHelpler.queryByPhone(phone);
if(info != null) {
et_password.setText(info.password);
}
}
}
}
4.3 SD卡文件操作
获取手机上的SD卡信息通过Environment类实现,该类是App获取各种目录信息的工具,主要方法有以下7种:
getRootDirectory:获得系统根目录的路径
getDataDirectory:获得系统数据目录的路径
getDownloadCacheDirectory获得下载缓存目录的路径
getExternalStorageDirectory:获得外部存储(SD卡)的路径
getExternalStorageState:获得SD卡的状态
SD卡的存储状态取值说明
Environment类的存储状态常量名 |
常量值 |
常量说明 |
MEDIA_UNKNOWN |
unknown |
未知 |
MEDIA_REMOVED |
removed |
已经移除 |
MEDIA_UNMOUNTED |
unmounted |
未挂载 |
MEDIA_CHECKING |
checking |
正在检查 |
MEDIA_NOFS |
nofs |
不支持的文件系统 |
MEDIA_MOUNTED |
mounted |
已经挂载,且是可读写状态 |
MEDIA_MOUNTED_READ_ONLY |
mounted_ro |
已经挂载,且是只读状态 |
MEDIA_SHARED |
shared |
当前未挂载,但通过USB共享 |
MEDIA_BAD_REMOVAL |
bad_removal |
未挂载就被移除 |
MEDIA_UNMOUNTABLE |
unmountable |
无法挂载 |
MEDIA_EJECTING |
ejecting |
正在弹出 |
getStorageState:获得指定目录的状态
getExternalStoragePublicDirectory:获得SD卡指定类型目录的路径
SD卡的目录类型取值说明
Environment类的目录类型 |
常量值 |
常量说明 |
DIRECTORY_DCIM |
DCIM |
相片存放目录(包括相机拍摄的图片和视频) |
DIRECTORY_DOCUMENTS |
Documents |
文档存放目录 |
DIRECTORY_DOWNLOADS |
Download |
下载文件存放目录 |
DIRECTORY_MOVIES |
Movies |
视频存放目录 |
DIRECTORY_MUSIC |
Music |
音乐存放目录 |
DIRECTORY_PICTURES |
Pictures |
图片存放目录 |
为正常操作SD卡,需要在androidManifest.xml中声明SD卡的权限,具体代码如下:
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>
<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE”/>
<uses-permission android:name=”android:permission.MOUNT_UNMOUNT_FILESYSTEMS”>
示例:
desc =
Environment.getRootDirectory().getAbsolutePath());
desc = Environment.getDataDirectory().getAbsolutePath());
desc = Environment.getDownloadCacheDirectory().getAbsolutePath());
desc = Environment.getExternalStorageDirectory().getAbsolutePath());
desc = Environment.getExternalStorageState());
desc = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
//DIRECTORY_DOCUMENTS是Android4.4.2(SDK19)及以上版本才有的常量
//如果不做SDK版本判断,那么在低版本Android(例如4.2.2)上运行会报错
//java.lang.NoSuchFieldError: android.os.Environment.DIRECTORY_DOCUMENTS
//因此在获取DIRECTORY_DOCUMENTS时要加上判断条件if (VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) ,
其他的则不用,示例如下:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
文本文件读写&图片文件读写:工具类FileUtil.java
文本文件的读写一般借助于FileOutputStream和FileInputStream
Android的图片处理类是Bitmap,App读写Bitmap可以使用FileOutputStream和FileInputStream,不过在实际开发中,读写图片文件一般用性能更好的BufferedOutputStream和BufferedInputStream,保存图片文件时用到的Bitmap的compress方法,可指定图片类型和压缩质量,打开图片文件时使用BitmapFactory的decodeStream方法。
事实上,BitmapFactory还提供了其他方法:
decodeFile:该方法直接传文件路径的字符串,即可将指定路径的图片读取到Bitmap对象
decodeResource:该方法可从资源文件中读取图片信息,第一个参数一般传getResources(),第二个参数传drawable图片的资源id,如R.drawable.phone
4.4 Application基础
在App运行过程中有且仅有一个Application对象贯穿整个生命周期,activity节点的上级正是application
Application的生命周期覆盖App运行的全过程,不像短暂的Activity生命周期,只要进入别的页面,原页面就被停止或销毁,因此,通过利用Application的持久存在性可以在Application对象中保存全局变量,适合在Application中保存的全局变量主要有下面3类数据:
(1)会频繁读取的信息,如用户名,手机号等
(2)从网络上获取的临时数据,为节约流量、减少用户等待时间,想暂时放在内存中供下次使用,如logo、商品图片等
(3)容易因频繁分配内存而导致内存泄漏的对象,如Handler对象
要想通过Application实现全局内存的读写,得完成以下3项工作:
(1)写一个继承自Application的类MainApplication,该类要采用单例模式,内部声明自身类的一个静态成员对象,在创建app时把自身赋值给这个静态对象,然后提供该静态对象的获取方法getInstance
(2)在Activity中调用MainApplication的getInstance方法,获得MainApplication的一个静态对象,通过该对象访问MainApplication的公共变量和公共方法
(3)不要忘了在AndroidManifest.xml中注册新定义的Application类名,即在application节点中增加android:name属性,值为.MainApplication
样例类:MainApplication.java
(MainApplication类可以重写的方法主要有以下4个:
onCreate:在App启动时调用
onTerminate:在App退出时调用(该方法就是个摆设……)
onLowMemory:在低内存时调用
onConfigurationChanged:在配置改变时调用,例如从竖屏变为横屏)
完成自定义MainApplication类的代码后,Activity页面代码即可直接通过MainApplication.getInstance().mInfoMap对全局变量进行增删改查操作