1. 程式人生 > >Android資料儲存五種方式總結

Android資料儲存五種方式總結

SharePreferences是用來儲存一些簡單配置資訊的一種機制,使用Map資料結構來儲存資料,以鍵值對的方式儲存,採用了XML格式將資料儲存到裝置中。例如儲存登入使用者的使用者名稱和密碼。只能在同一個包內使用,不能在不同的包之間使用,其實也就是說只能在創建它的應用中使用,其他應用無法使用。

建立的儲存檔案儲存在/data/data/<package name>/shares_prefs資料夾下。

修改和儲存資料
  • 根據Context的getSharedPrerences(key, [模式])方法獲取SharedPreference物件;
  • 利用SharedPreference的editor()方法獲取Editor物件;
  • 通過Editor的putXXX()方法,將鍵值對儲存資料;
  • 通過Editor的commit()方法將資料提交到SharedPreference內。
demo示例:
package com.example.androidsharedpreferences;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

public class MainActivity extends Activity implements OnClickListener {
	private EditText keyET;
	private EditText valueET;
	private Button insertBtn;
	private Button deleteBtn;
	private Button modifyBtn;
	private Button queryBtn;
	private Button clearBtn;
	private TextView textView;
	public static final String DATABASE = "text";
	public static final String PATH = "/data/data/com.example.androidsharedpreferences//shared_prefs/text.xml";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		keyET = (EditText) findViewById(R.id.ed_jian);
		valueET = (EditText) findViewById(R.id.ed_zhi);
		insertBtn = (Button) findViewById(R.id.button1);
		deleteBtn = (Button) findViewById(R.id.button2);
		modifyBtn = (Button) findViewById(R.id.button3);
		queryBtn = (Button) findViewById(R.id.button4);
		clearBtn = (Button) findViewById(R.id.button5);
		// 用於顯示儲存檔案中資料
		textView = (TextView) findViewById(R.id.tv_jiegou);
		insertBtn.setOnClickListener(this);
		deleteBtn.setOnClickListener(this);
		modifyBtn.setOnClickListener(this);
		queryBtn.setOnClickListener(this);
		clearBtn.setOnClickListener(this);

	}

	@Override
	public void onClick(View v) {
		// 獲取SharedPreferences物件
		SharedPreferences sp = getSharedPreferences(DATABASE, Activity.MODE_PRIVATE);
		// 獲取Editor物件
		Editor editor = sp.edit();
		// 獲取介面中的資訊
		String key = keyET.getText().toString();
		String value = valueET.getText().toString();
		switch (v.getId()) {
		case R.id.button1:
			editor.putString(key, value);
			editor.commit();
			textView.setText(MainActivity.this.print());
			break;
		case R.id.button2:
			editor.remove(key);
			editor.commit();
			textView.setText(MainActivity.this.print());
			break;
		case R.id.button3:
			editor.putString(key, value);
			editor.commit();
			textView.setText(MainActivity.this.print());
			break;
		case R.id.button4:
			String result = sp.getString(key, "");
			textView.setText("key=" + key + ",value=" + result);
			break;
		case R.id.button5:
			editor.clear();
			editor.commit();
			textView.setText(MainActivity.this.print());
			break;
		default:
			break;
		}
	}

	/** 獲取儲存檔案的資料 */
	private String print() {
		StringBuffer buff = new StringBuffer();
		BufferedReader reader= null;
		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(PATH)));
			String str;
			while ((str = reader.readLine()) != null) {
				buff.append(str + "/n");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		Log.d("1111111", buff.toString());
		return buff.toString();
	}
}
2.檔案儲存

在介紹檔案儲存之前我們要先了解記憶體、外部儲存、內部儲存三個概念,我們先來考慮一個問題:

開啟手機設定,選擇應用管理,選擇任意一個App,然後你會看到兩個按鈕,一個是清除快取,另一個是清除資料,那麼當我們點選清除快取的時候清除的是哪裡的資料?當我們點選清除資料的時候又是清除的哪裡的資料?讀完本文相信你會有答案。

在android開發中我們常常聽到這樣幾個概念,記憶體,內部儲存,外部儲存,很多人常常將這三個東西搞混,那麼我們今天就先來詳細說說這三個東西是怎麼回事?

記憶體,我們在英文中稱作memory,內部儲存,我們稱為InternalStorage,外部儲存我們稱為ExternalStorage,這在英文中本不會產生歧義,但是當我們翻譯為中文之後,前兩個都簡稱為記憶體,於是,混了。

那麼究竟什麼是內部儲存什麼是外部儲存呢?

首先我們開啟DDMS,有一個File Explorer,如下:


這裡有三個資料夾需要我們重視,一個是data,一個是mnt,一個是storage,我們下面就詳細說說這三個資料夾。

內部儲存

data資料夾就是我們常說的內部儲存,當我們開啟data資料夾之後(沒有root的手機不能開啟該資料夾),裡邊有兩個資料夾值得我們關注,如下:


一個資料夾是app資料夾,還有一個資料夾就是data資料夾,app資料夾裡存放著我們所有安裝的app的apk檔案,其實,當我們除錯一個app的時候,可以看到控制檯輸出的內容,有一項是uploading .....就是上傳我們的apk到這個資料夾,上傳成功之後才開始安裝。另一個重要的資料夾就是data檔案夾了,這個資料夾裡邊都是一些包名,開啟這些包名之後我們會看到這樣的一些檔案:

1.data/data/包名/shared_prefs
2.data/data/包名/databases
3.data/data/包名/files

4.data/data/包名/cache

如果開啟過data檔案,應該都知道這些資料夾是幹什麼用的,我們在使用sharedPreferenced的時候,將資料持久化儲存於本地,其實就是存在這個檔案中的xml檔案裡,我們App裡邊的資料庫檔案就儲存於databases資料夾中,還有我們的普通資料儲存在files中,快取檔案儲存在cache資料夾中,儲存在這裡的檔案我們都稱之為內部儲存。

外部儲存

外部儲存才是我們平時操作最多的,外部儲存一般就是我們上面看到的storage資料夾,當然也有可能是mnt資料夾,這個不同廠家有可能不一樣。

一般來說,在storage資料夾中有一個sdcard資料夾,這個資料夾中的檔案又分為兩類,一類是公有目錄,還有一類是私有目錄,其中的公有目錄有九大類,比如DCIM、DOWNLOAD等這種系統為我們建立的資料夾,私有目錄就是Android這個資料夾,這個資料夾開啟之後裡邊有一個data資料夾,開啟這個data資料夾,裡邊有許多包名組成的資料夾。

說到這裡,我想大家應該已經可以分清楚什麼是內部儲存什麼是外部儲存了吧?好,分清楚之後我們就要看看怎麼來操作內部儲存和外部儲存了。

檔案的讀寫常用的是使用:FileOutputStream和FileInputStream下面我們來看demo
package com.example.androidfilestorage;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

import android.app.Activity;
import android.content.Context;

public class MainActivity extends Activity implements OnClickListener {
	private File json_file, file;
	private Button btn_write, btn_read;
	private EditText ed_write, ed_read;
	private FileOutputStream fos;
	FileInputStream inputStream;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		json_file = getFileDir(MainActivity.this, "thumb1");
		if (!json_file.exists()) {
			json_file.mkdirs();
		}
		// 建立快取json資料來源資料夾,在沒網路的情況下從這裡讀取資料
		file = new File(json_file + "/txt.json");
		if (!file.exists()) {
			file.getParentFile().mkdirs();
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Log.d("TestFile", "Create the file:" + file.getPath());
		btn_write = (Button) findViewById(R.id.btn_inset);
		btn_read = (Button) findViewById(R.id.btn_read);
		ed_write = (EditText) findViewById(R.id.ed_inset);
		ed_read = (EditText) findViewById(R.id.ed_read);
		btn_write.setOnClickListener(this);
		btn_read.setOnClickListener(this);
	}

	/**
	 * 判斷內部儲存還是外部儲存,帶SD卡使用外部儲存,不帶SD卡使用內部儲存。
	 */
	public File getFileDir(Context context, String uniqueName) {
		String cachePath;
		if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
				|| !Environment.isExternalStorageRemovable()) {
			cachePath = context.getExternalFilesDir(uniqueName).getPath();
		} else {
			cachePath = context.getFilesDir().getPath();
		}
		return new File(cachePath);
	}

	@Override
	public void onClick(View v) {
		String text = ed_write.getText().toString();
		switch (v.getId()) {
		case R.id.btn_inset:

			try {
				fos = new FileOutputStream(file);
				OutputStreamWriter osw = new OutputStreamWriter(fos);
				osw.write(text);
				osw.flush();
				osw.close();
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			break;
		case R.id.btn_read:
			try {
				inputStream = new FileInputStream(file);
				byte[] bytes = new byte[1024];
				ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
				while (inputStream.read(bytes) != -1) {
					arrayOutputStream.write(bytes, 0, bytes.length);
				}
				inputStream.close();
				arrayOutputStream.close();
				String content = new String(arrayOutputStream.toByteArray());
				ed_read.setText(content);
			} catch (Exception e) {
			}
			break;
		default:
			break;
		}
	}
}
檔案的讀寫需要的許可權:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
demo下載地址:http://download.csdn.net/detail/qq_31546677/9913232

文章參考地址:

3.sqlite資料庫儲存

4.ContentProvider儲存

適用範圍

對於什麼情況下才會用到自定義的ContentProvider,官方文件的Dev Guide是這樣描述的:

如果你想要提供以下的一種或幾種特性的時候你才需要構造一個ContentProvider:

  • 你想要為其它的應用提供複雜的資料或者檔案;
  • 你想允許使用者從你的應用中拷貝複雜的資料到其它的應用中;
  • 你想要使用搜索框架來提供自定義的搜尋策略。

你完全不需要ContentProvider來呼叫一個SQLite資料庫,如果這種呼叫完全在你自己的應用之中。

也就是說,ContentProvider的作用是為別的應用呼叫本應用中的資料或者檔案提供介面,而它也是唯一的跨應用資料傳遞的介面。如果僅僅是同一個應用中的資料傳遞,則完全沒有必要使用到自定義的ContentProvider。

另一方面,雖然ContentProvider也能組織檔案資料或者SharedPreferences(其實也是檔案資料)這種資料,但大多數情況下ContentProvider是作為SQLite資料庫的呼叫介面來被繼承的。其原因大概是在於重寫的query()方法始終需要返回Cursor,而Cursor作為資料庫資料的容器,並沒有提供直接往Cursor中寫入資料的方法。

大體實現步驟

1.      建立一個數據源,例如繼承SQLiteOpenHelper建立一個SQLite資料庫;

2.      建立一個繼承自ContentProvider的類,並重寫insert、delete、query、update、getType、onCreate方法,在這些方法中實現對資料來源的操作;

3.      在AndroidManifest.xml檔案中新增<provider>標籤,兩個必寫的屬性是android:name和android:authorities;

4.      在本應用或者其它應用的Activity、Service等元件中使用ContentResolver通過對應的URI來操作該自定義ContentProvider。

名詞解釋

URL

Android各種型別的URI基本上都是有固定格式的,對於ContentProvider而言,一般形如

content://com.test.cp.MyProvider/phone/1

的URI,其中:

content://是固定欄位,必需;

com.test.cp.MyProvider表示authority,是AndroidManifest.xml檔案中<provider>標籤的android:authorities屬性值,或者是遠端資料來源的主機名,必需;

phone/1表示path,是資料來源路徑,非必需,其中的phone對於資料庫來說可以視為表名,1表示的是該條資料的編號,如果沒有則一般認為是返回當前路徑(當前表)中的所有資料。

另外還可以根據自己的需要來進一步定義後續的欄位。

UriMatch物件

1.        通過new  UriMatcher(UriMatcher.NO_MATCH); 例項化,常量NO_MATCH作為引數表示不匹配任何URI;

2.        例項化後呼叫addURI方法註冊URI,該方法有三個引數,分別需要傳入URI字串的authority部分、path部分以及自定義的整數code三者;

3.        在其它地方呼叫match方法匹配相應的URI,需要傳入Uri作為唯一的引數,返回上述自定義的code值。

至於其初始化的位置,如前所述,網上絕大多數示例都將其放入靜態域中例項化,原因不明。實際上放到onCreate方法中也沒什麼問題。

getType方法

ContentProvider必須重寫的6個方法中,除了初始化方法onCreate以及資料操作的4個方法以外,還有一個getType方法。它的作用是根據URI返回該URI所對應的資料的MIME型別字串。這種字串的格式分為兩段:“A/B”。其中A段是固定的,集合型別(如多條資料)必須是vnd.android.cursor.dir,非集合型別(如單條資料)必須是vnd.android.cursor.item;B段可以是自定義的任意字串;A、B兩段通過“/”隔開。這個MIME型別字串的作用是要匹配AndroidManifest.xml檔案<activity>標籤下<intent-filter>標籤的子標籤<data>的屬性android:mimeType。如果不一致,則會導致對應的Activity無法啟動。

demo示例主要程式碼

package com.example.androidcustomcontentprovider;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;

public class MainActivity extends Activity implements OnClickListener {

	private Button btnadd, btnqueryall, btndel, btnupdate;
	private EditText edtname, edtage;

	private ListView lvall;
	private int id;
	private Uri url;
	private String path="content://com.example.androidcustomcontentprovider.myprovider/person";
	private List<Person> persons;
	private SimpleAdapter simpleAdapter;
	private Handler handler = new Handler() {

		@Override
		public void handleMessage(Message msg) {

			List<Map<String, Object>> data = (List<Map<String, Object>>) msg.obj;

			Log.d("data", "---" + data.size());

			simpleAdapter = new SimpleAdapter(MainActivity.this, data, R.layout.list_item,
					new String[] { "id", "name", "age" }, new int[] { R.id.tvId, R.id.tvname, R.id.tvage });

			lvall.setAdapter(simpleAdapter);
			simpleAdapter.notifyDataSetChanged();

		}

	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		persons = new ArrayList<Person>();

		btnqueryall = (Button) this.findViewById(R.id.btnqueryall);
		btnadd = (Button) this.findViewById(R.id.btnadd);
		edtname = (EditText) this.findViewById(R.id.edtname);
		edtage = (EditText) this.findViewById(R.id.edtage);
		btndel = (Button) this.findViewById(R.id.btndel);
		btnupdate = (Button) this.findViewById(R.id.btnupdate);
		lvall = (ListView) this.findViewById(R.id.lvall);
		btnadd.setOnClickListener(this);
		btnqueryall.setOnClickListener(this);
		btndel.setOnClickListener(this);
		btnupdate.setOnClickListener(this);
		lvall.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
				Log.d("position:", "" + position);

				Person person = persons.get(position);
				Log.d("data_onitemClick",
						"id:" + person.getId() + "name:" + person.getName() + "age:" + person.getAge());
				edtname.setText(person.getName());
				edtage.setText("" + person.getAge());
			}
		});
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.btnadd:
			ContentResolver contentResolver = MainActivity.this.getContentResolver();
			url = Uri.parse(path);
			ContentValues values = new ContentValues();
			values.put("name", edtname.getText().toString());
			values.put("age", edtage.getText().toString());
			Uri result = contentResolver.insert(url, values);
			Log.d("result", result.toString());
			if (edtname.getText().toString().equals("") || edtage.getText().toString().equals("")) {
				Toast.makeText(MainActivity.this, "輸入內容為空", Toast.LENGTH_LONG).show();
			} else {
				Toast.makeText(MainActivity.this, "新增成功", Toast.LENGTH_LONG).show();
				getAllDate();
			}
			break;
		case R.id.btndel:
			
			ContentResolver contentResolver1 = MainActivity.this.getContentResolver();
			url = Uri.parse(path);

			Cursor cursor2 = MainActivity.this.getContentResolver().query(url, null, null, null, null);
			while(cursor2.moveToNext()){
				 id=cursor2.getInt(cursor2.getColumnIndex("_id"));
			}
			Log.d("result_delete", "" + id);
			// 構建Uri
			String url1 = "content://com.example.androidcustomcontentprovider.myprovider/person/"
					+ id;
			Uri uri = Uri.parse(url1);

			int result1 = contentResolver1.delete(uri, null, null);
			Log.d("result_delete", "" + result1);
			getAllDate();
			break;
		case R.id.btnupdate:
			ContentResolver contentResolver11 = MainActivity.this.getContentResolver();
			url = Uri.parse(path);

			Cursor cursor21 = MainActivity.this.getContentResolver().query(url, null, null, null, null);
			while(cursor21.moveToNext()){
				 id=cursor21.getInt(cursor21.getColumnIndex("_id"));
			}
			Log.d("result_delete", "" + id);
			// 構建Uri
			String url12 = "content://com.example.androidcustomcontentprovider.myprovider/person/"
					+ id;
			Uri uri1 = Uri.parse(url12);
			ContentValues values1 = new ContentValues();
			values1.put("name", edtname.getText().toString());
			values1.put("age",
					Integer.parseInt(edtage.getText().toString()));
			int result12 = contentResolver11.update(uri1, values1, null, null);
			Log.d("update result:" ,""+ result12);
			System.out.println("update result:" + result12);
			getAllDate();
			break;
		case R.id.btnqueryall:
			getAllDate();
			break;
		default:
			break;
		}
	}

	public void getAllDate() {
		persons.clear();
		lvall.setAdapter(null);
		url = Uri.parse(path);

		Cursor cursor = MainActivity.this.getContentResolver().query(url, new String[] { "_id", "name", "age" }, null,
				null, "_id");

		while (cursor.moveToNext()) {
			Person person = new Person();
			person.setId(cursor.getInt(cursor.getColumnIndex("_id")));
			person.setName(cursor.getString(cursor.getColumnIndex("name")));
			person.setAge(cursor.getInt(cursor.getColumnIndex("age")));
			persons.add(person);

		}

		cursor.close();

		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();

		Map<String, Object> map = null;
		for (int i = 0; i < persons.size(); i++) {

			map = new HashMap<String, Object>();

			map.put("id", persons.get(i).getId());
			map.put("name", persons.get(i).getName());

			map.put("age", persons.get(i).getAge());
			data.add(map);

		}
		if (data.size() >= persons.size()) {

		}
		Message msg = handler.obtainMessage();
		msg.obj = data;
		handler.sendMessage(msg);
	}
}
demo下載地址:http://download.csdn.net/detail/qq_31546677/9913234

5.網路儲存