4类Storage方案(AS开发实战第四章学习笔记)

时间:2023-03-09 08:44:53
4类Storage方案(AS开发实战第四章学习笔记)

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对全局变量进行增删改查操作