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對全局變量進行增刪改查操作
4類Storage方案(AS開發實戰第四章學習筆記)