上官网学android之七(Saving Data)

官网链接

http://developer.android.com/training/basics/data-storage/index.html

一、保存key-value集

key-value 对广大coder来说已经再熟悉不过了。

为了方便使用者快捷的存取数据在andorid中key-value保存在一个文件中的。1.1 获取SharedPreferences实例

在Activity中可以直接获得SharedPreferences实例,否则需要先得到Activity实例

SharedPreferences preferences = getPreferences(Context.MODE_PRIVATE);

SharedPreferences sharedPreferences = getSharedPreferences(
				"sharedFile", Context.MODE_PRIVATE);

 两种方式有区别,之前不是说这些key-value数据存放在文件中吗,所以getPreferences是当前Activity实例的一个文件,而getSharedPreference是新建一个文件来存,所以需要提供一个名字。

第二个参数是模式的选择的,简单说点,MODE_PRIVATE是私有的,不给其它使用,还有比如MODE_WORLD_WRITEABLE则可以全局访问,据官网介绍甚至其它APP都可以使用哦,这个没有尝试。

1.2 读和写

很简单的API所以放一起写了,直接上代码

SharedPreferences preferences = getPreferences(Context.MODE_PRIVATE);
preferences.edit().putString("key", "test").commit();
String ret0=preferences.getString("key", "default");
System.out.println("key -------------- " + ret0);

SharedPreferences sharedPreferences = getSharedPreferences(
				"sharedFile", Context.MODE_PRIVATE);
sharedPreferences.edit().putString("key", "testShare").commit();
String ret = sharedPreferences.getString("key", "default");
System.out.println("shared key ------------- " + ret);

 注意到了吗,是写System.out来输出的,通常android不用这种输出方式,因为文章还没有介绍到如何利用android的Log API来现实日志,所以先用着吧。

二、保存文件

2.1 选择内部还是外部的存储介质

 所谓内存储是指机器本来的内存,我们通常叫机身内存。外部存储介质比如SD卡之类的。

为什么分为两部分呢,因为

在内部存储:

1.总是可用的

2.保存的文件通常只能它自己的APP可以访问

3.卸载APP的时候会连带删除APP的文件

外部存储

1.不总是肯定,因为在某些时候你可能取出SD卡

2.因为是全局可读的,所以保存在这里的文件可能会在你的控制之外。

3.卸载APP的时候,系统会删除你用getExternalFilesDir()保存的文件,其它方式保存的不会删除。

 2.2 为外部存储设置权限

我们通过在Manifest 文件中设置外部存储的权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.tang.test"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ......
</manifest>
 这是写的权限,如果是读权限 WRITE_EXTERNAL_STORAGE

2.3 在内部存储中保存文件

可以通过以下两种方式来得到一个文件

getFilesDir()

getCacheDir() 临时的缓存文件,系统内存不够时,可能会删除

//context.getFilesDir()
File file = new File(context.getFilesDir(), filename);

//context.getCacheDir()
 File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    catch (IOException e) {
        // Error while creating file
    }
    return file;

 向文件写数据利用到了文件流

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}

2.4 在外部存储中保存文件

因为外部存储不一定总可用,所以我们需要判断可用的情况

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

尽管在外部存储中的文件可以被用户和其它APP修改,android提供了两种类型的文件。

Public files 卸载APP后文件不会删除,比如照片信息

private files 卸载之后文件被删除,比如说额外的下载的资源文件

//公有的文件
public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory. 
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}
//私有的文件
public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory. 
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

2.5 查询空闲空间

在程序运行时知道空闲空间在某些情况下可能会很有用,必须你下载一个较大文件的时候

android提供两个方法

getFreeSpace()

getTotalSpace()

2.6 删除一个文件

myFile.delete();
myContext.deleteFile(fileName);

当app被卸载的时候,系统会按照下面的逻辑删除文件

1. 删除internal storage(内部存储)中保存的文件

2. 删除extenal storage(外部存储)中使用getExternalFilesDir()保存的文件

三、保存到数据库中

android有内嵌的数据库sqlite。

官网的文档关于这方面写的感觉有点啰嗦了,可能想让大家养成一个好的习惯吧。其实有超级简单的例子,可能在现阶段有些人还不想搞那么复杂来个简单的吧,我直接在Activity中写一个方法,然后再onCreate中调用它测试了一下。

private void dbtest() {
		SQLiteDatabase db = openOrCreateDatabase("my.db", Context.MODE_PRIVATE,
				null);
		db.execSQL("drop table if exists test");
		db.execSQL("create table test(id varchar,name varchar)");
		db.execSQL("insert into test values(?,?)", new Object[] { "id_1", "name_1" });

		Cursor cursor = db.rawQuery("select * from test where name =?",
				new String[] { "name_1" });
		while (cursor.moveToNext()) {
			String id = cursor.getString(cursor.getColumnIndex("id"));
			System.out.println("id =========== " + id);
			Log.i("db_target", "id \t" + id);
		}
		cursor.close();

		db.close();
	}
 爽了一下之后开始跟着官网慢慢来吧。

3.1 定义Schema 和 Contract

所谓schema和Contract 其实是你的数据库和表的定义,他们叫的比较专业,我等通常叫创建数据库和表。

哎,谁谁谁,给创建的sql语句给我发一份....

public final class FeedReaderContract {

	public FeedReaderContract() {}
	
	public static abstract class FeedEntry implements BaseColumns {
        public static final String TABLE_NAME = "entry";
        public static final String COLUMN_NAME_ENTRY_ID = "entryid";
        public static final String COLUMN_NAME_TITLE = "title";
        public static final String COLUMN_NAME_SUBTITLE = "subtitle";
    }
}
 理解为常量类,类中定义了一些数据库定义方面的常量。

3.2 使用SQL Helper 创建数据库

android提供了一个叫做SQLiteOpenHelper的类来帮助我们使用SQLite.

public class FeedReaderDbHelper extends SQLiteOpenHelper {
	public static final int DATABASE_VERSION = 1;
	public static final String DATABASE_NAME = "FeedReader.db";

	public FeedReaderDbHelper(Context context) {
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(SQL_CREATE_ENTRIES);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		db.execSQL(SQL_DELETE_ENTRIES);
        onCreate(db);
	}

	private static final String TEXT_TYPE = " TEXT";
	private static final String COMMA_SEP = ",";
	private static final String SQL_CREATE_ENTRIES = "CREATE TABLE "
			+ FeedEntry.TABLE_NAME + " (" + FeedEntry._ID
			+ " INTEGER PRIMARY KEY," + FeedEntry.COLUMN_NAME_ENTRY_ID
			+ TEXT_TYPE + COMMA_SEP + FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE
			+ COMMA_SEP + " )";

	private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS "
			+ FeedEntry.TABLE_NAME;

}
 根据以前的常量值,在这个类中,拼写了一些常用的SQL语句,为了方便看我放在了最后面。继承SQLiteOpenHelper之后,需要实现onCreate()和onUpdate()方法,这两个方法分别在第一次使用数据库时,和版本号改变后调用,所谓版本号改动就是DATABASE_VERSION值改变了,如果你的APP数据库表发生改变了,修改下这个版本号,系统在下次启动的时候会调用onUpdate()方法,然后我们在方法中做一些适应性的改变,上面例子中比较暴力,直接把以前的表删除了,建的新表。(对于这种情况我表示有点害怕,出问题别怪我,官网上就这么写的)

3.3 put/read/delete/update

增删该查,数据库四大神兵,必须得知道的

private void dbOperationTest() {
		FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(this);
		SQLiteDatabase wdb = mDbHelper.getWritableDatabase();
		SQLiteDatabase rdb = mDbHelper.getReadableDatabase();

		// put
		ContentValues values = new ContentValues();
		values.put(FeedEntry.COLUMN_NAME_ENTRY_ID, "id_" + 0);
		values.put(FeedEntry.COLUMN_NAME_TITLE, "title_" + 0);

		long newRowId;
		newRowId = wdb.insert(FeedEntry.TABLE_NAME, null, values);

		// query
		Cursor cursor = rdb.query(FeedEntry.TABLE_NAME, // The table to query
				new String[] { FeedEntry.COLUMN_NAME_ENTRY_ID,
						FeedEntry.COLUMN_NAME_TITLE }, // The columns to return
				FeedEntry.COLUMN_NAME_TITLE +"=?", // The columns for the WHERE clause
				new String[]{"title_"+0}, // The values for the WHERE clause
				null, // don't group the rows
				null, // don't filter by row groups
				FeedEntry.COLUMN_NAME_TITLE+" DESC" // The sort order
				);
		while (cursor.moveToNext()) {
			String id = cursor.getString(cursor.getColumnIndex(FeedEntry.COLUMN_NAME_ENTRY_ID));
			Log.i("db_target", "id \t" + id);
		}
		cursor.close();
		
		//delete
		String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
		String[] selectionArgs = { "id_"+0 };
		wdb.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);
		
		//udpate
		ContentValues updateValues = new ContentValues();
		values.put(FeedEntry.COLUMN_NAME_TITLE, "title_2");

		int count = wdb.update(
			    FeedEntry.TABLE_NAME,
			    updateValues,
			    selection,
			    selectionArgs);
		
		//close
		rdb.close();
		wdb.close();
	}
       

猜你喜欢

转载自tangmingjie2009.iteye.com/blog/2029610