码迷,mamicode.com
首页 > 移动开发 > 详细

Android数据存储

时间:2015-07-29 12:14:14      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:android存储   chche   sharedpreferences   file   sd卡存储   

SharedPreferences与Editor

SharedPreferences保存的数据只要是类似于配置信息格式的数据,因此它保存的数据主要是简单的key-value对形式。下面关系图

技术分享

上图完全可以看出,存的时候用SharedPreferences的内部类Editor,取的时候用SharedPreferences。

SharedPreference是接口无法创建实例,Context提供下面方法创建实例 该实例只能有一个,也就是单例模式。

getSharedPreferences(String name,int mode);


存取例子

 public class MainActivity extends Activity {
	 SharedPreferences sp;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//获取SharedPreferences实例  Test是文件名,不要加后缀,默认为XML格式
		sp = getSharedPreferences("Test", Context.MODE_WORLD_WRITEABLE);
		//得到内部类写数据
		SharedPreferences.Editor editor = sp.edit();
		editor.putString("name", "value");
		//不提交则无法获得数据
		editor.commit();
		
	}
	public void btn(View view){
		String string = sp.getString("name", "null");
		Toast.makeText(this, string, 1).show();
	}
}
存储路径为:data/data/包名/shared_prefs/Test.xml

打开该文件看到

<?xml version="1.0" encoding="utf-8" standalone ="yes" ?>
<map>
<string name="name">value</string>
</map>

存储的放值的时候String对应XML文件里就是string节点,Int的时候对应int节点。

存储时长:卸载软件时包名所在的文件夹会消失,所以该文件无法同样会消失。


读写其他应用的SharedPreferences

上述是在本身的APP中玩耍,这次看如何读取其他应用,关键是获得其他应用的程序的Context(代表Android应用的全局信息的接口)又因为包名是Andoird应用的唯一标示,所以调用本APP的Context的方法

createPackageContext("android.example.homework", CONTEXT_IGNORE_SECURITY);

得到其他应用的Context对象并且其他应用SharedPreferences是可读状态(可写不行,必须可读)后就可以“为所欲为”了。

public class MainActivity extends Activity {
	SharedPreferences sp;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 获取SharedPreferences实例
		try {
			//通过包名得到该应用的Context对象
			Context context=createPackageContext("com.example.homework", CONTEXT_IGNORE_SECURITY);
			//用其他应用的Context创建SharedPreferences
			sp = context.getSharedPreferences("Test", Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);
		} catch (NameNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public void btn(View view) {
		String string = sp.getString("name", "null");
		Toast.makeText(this, string, 1).show();
	}
}

上述的读写并不是唯一的,程序员完全可以利用IO流来直接操作本应用和其他应用的SharedPreferences数据,只是Android将他封装好了,很简便。

无法存储自定义类型,主要存储的APP配置信息,例如(用户名,密码等)。

Chche存储

存储空间不够系统会删除Cache存储,但不要依赖系统删除

存:

		File dir = getCacheDir();
		File file = new File(dir,"test.txt");
		try {
			FileOutputStream fos = new FileOutputStream(file);
			fos.write("缓冲存储".getBytes());
			
		} catch (Exception e) {
			// TODO: handle exception
		}

取:

FileInputStream fis = new FileInputStream(file)

以上两种方式均为内部存储,卸载应用时数据都会丢失。


File存储

FIle存储就是Android继续使用Java中的IO流继续读写文件的一种方式

两个核心方法:

openFileInput(String name);

openFIleOutput(String name);

下面是简单读写的例子

public class MainActivity extends Activity {
	SharedPreferences sp;

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

	}

	public void readed(View view) {
		FileInputStream fis = null;
		StringBuffer sb=null;
		try {
			//打开文件输入流     files文件名,这里系统不给添加后缀,不写无后缀
			fis = openFileInput("files");
			byte[] buff = new byte[1024];
			int len = 0;
			sb = new StringBuffer();
			while ((len = fis.read(buff)) != -1) {
				sb.append(new String(buff, 0, len));
			}
			//关流
			fis.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Toast.makeText(this, sb, 0).show();
	}

	public void writer(View view) {
		FileOutputStream fos = null;
		try {
			// 以追加模式打开文件输出流
			fos = openFileOutput("files", MODE_APPEND);
			// 将流包装成PrintStream
			PrintStream printStream = new PrintStream(fos);
			printStream.print("内容啦啦啦啦");
			Toast.makeText(this, "写入成功", 0).show();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (fos != null)
				try {
					fos.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
}

该文件无后缀,系统默认不添加后缀,存放路径为data/data/包名/file/文件夹下

该文件依然存放在包名下,所以卸载时依然会丢失数据。


SD卡存储

使用File存储和SharedPreferences存储的缺点是容量小,因为在应用程序的数据文件夹下。所以才有了SD卡存储。使用SD卡存储总共分为三步:

(1)判断应用是否有读写SD卡权限

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
(2)获得SD卡的目录

File dir = Environment.getExternalStorageDirectory();
(3)使用流读写数据


SD卡的权限

	<!-- 添加SD卡的创建与删除文件权限 -->
	<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
	<!-- 添加SD卡写入权限 -->
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

读写SD卡例子

public class MainActivity extends Activity {
	private final String FILE_NAME="test.txt";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
	}
	/**读取数据*/
	public void readed(View view) {
		BufferedReader bis=null;
		//当SD状态装备就绪时
		if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
			File dir = Environment.getExternalStorageDirectory();
			try {
				File file = new File(dir, FILE_NAME);
				FileInputStream fis = new FileInputStream(file);
				//将fis流包装成BufferedReader
				bis= new BufferedReader(new InputStreamReader(fis));
				String len = null;
				StringBuffer sb = new StringBuffer("");
				while((len=bis.readLine())!=null){
					sb.append(len);
				}
				Toast.makeText(this, "读到的数据是:"+sb, 0).show();
				
			} catch (Exception e) {
				e.printStackTrace();
			} 
			finally{
				if(bis!=null){
					try {
						bis.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		else Toast.makeText(this, "SD卡不可用", 0).show();
		
		
	}
	/**写入数据*/
	public void writer(View view) {
		RandomAccessFile raf = null;
		if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
			File dir = Environment.getExternalStorageDirectory();
			File file = new File(dir, FILE_NAME);
			//用指定文件创建RandomAccessFIle
			try {
				raf = new RandomAccessFile(file, "rw");
				//将文件记录指针移动到最后  防止再次写入覆盖之前的
				raf.seek(file.length()); 
				raf.write("来一个字符串玩玩".getBytes());
				Toast.makeText(this, "写入成功", 0).show();
			} catch (Exception e) {
				e.printStackTrace();
			}
			finally{
				if(raf!=null){
					try {
						raf.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

SQLite存储

SQLite是轻量级的数据库(底层就是一个数据库文件)一旦应用获得了代表指定数据库的SQLiteDatabase对象,接下来就可以通过该对象来管理,操作数据库了。

(1)获取SQLiteDatabase对象,它代表了与数据库的链接。

(2).调用SQLiteDatabase的方法来执行SQL语句。

(3).操作SQL语句的执行结果,比如用SimpleCursorAdapter封装Cursor

(4).关闭SQLiDatabase,回收资源。

常用方法

//创建(如果不存在)或打开数据库
static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory)
//打卡一个已经存在的数据库
static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags)

MainActivity.java

public class MainActivity extends Activity {
	private ListView listview;
	private SQLiteDatabase db;
	private EditText editText;
	private String TABLE_NAME="student";
	//创建表语句
	private String CREATE_TABLE = "create table "+TABLE_NAME+" (_id integer primary key autoincrement,name varchar(20),age integer)";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//初始化
		editText = (EditText) findViewById(R.id.et);
		listview=(ListView) findViewById(R.id.listivew);
		//打开或创建数据库(这里需要绝对路径)
		db=SQLiteDatabase.openOrCreateDatabase("/mnt/sdcard/my.db3", null);
		if(!exits(TABLE_NAME)){
			db.execSQL(CREATE_TABLE);
		}
	}
	@Override
	protected void onDestroy() {
		super.onDestroy();
		//关闭数据库
		if(db!=null&&db.isOpen())
			db.close();
	}
	public void btn(View view){
		switch (view.getId()) {
		case R.id.btn1://插入
			String str = editText.getText().toString();
			String sql = "insert into "+TABLE_NAME+" (name) values ('"+str+"') ";
			System.out.println(sql);
			db.execSQL(sql);
			break;
		case R.id.btn2://读取
			String sql2 = "select * from "+TABLE_NAME+"";
			Cursor cursor = db.rawQuery(sql2, null);
			inflateListView(cursor);
			break;
		}
	}
	public boolean exits(String table){
		String sql= "select * from sqlite_master where name="+"'"+table+"'";
		System.out.println(sql);
		Cursor cursor = db.rawQuery(sql, null);
		if(cursor.getCount()!=0){
			return true;
		}
		return false;
	}
	private void inflateListView(Cursor cursor){
		//构建Cursor适配器的同时就是对Cursor封装成为Adapter
		SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_expandable_list_item_1, cursor, new String[]{"name"}, new int[]{android.R.id.text1},CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
		listview.setAdapter(adapter);
	}
}


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="btn"
        android:text="插入 字符串数据" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="btn"
        android:text="取出数据" />


    <ListView
        android:id="@+id/listivew"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

效果图:

技术分享

由于是自定义的路径,所以卸载软件依然存在。这种直接使用SQLiteDatabase的方式使用的极少的。

注意:这里主键的列名必须为_id,因为SimpleCursorAdapter只能识别列名为_id的主键。


SQLiteOpenHelper

这种继承SQLiteOpenHelper方式用的还是比较多的。它是Android提供的一个管理数据库的工具类,可用于管理数据库的创建的版本和更新。

常用方法:

synchronized SQLiteDatabase getReadableDatabase();以只读方式打开对应SQLiteDatabase 对象

synchronized SQLiteDatabase getWritableDatabase();以写方式打开对应SQLiteDatabase 对象

abstract void Create(SQLiteDatabase db);第一次创建数据库时回调该方法。

abstract void Upgrade(SQLiteDatabase db,int oldVersion,int newVersion);当数据库版本更新时回调该方法。

在获得数据库实例时建议使用getReadableDatabase();如果用getWritableDatabase()一旦磁盘满了,打开数据库就会出错,而getReadableDatabase方法先只读方式打开,就算磁盘空间满了,也不会出错,而是继续使用只读方式。(getReadableDatabase调用时会包含getWritableDatabase)当调用getReadableDatabase()如果数据库不存在调用onCreate(SQLiteDatabase db);存在之后返回该实例

MyDB.java

public class MyDB extends SQLiteOpenHelper {
	public MyDB(Context context, String name,  int version) {
		super(context, name, null, version);
		// TODO Auto-generated constructor stub
	}
	public SQLiteDatabase db;
	
	final String CREATE_TABLE="create table student(_id integer primary key autoincrement,word varchar(20),detail varchar(20))";
	//第一次创建数据库的时候调用,当运行第二次时db==null
	@Override
	public void onCreate(SQLiteDatabase db) {
		this.db=db;
		db.execSQL(CREATE_TABLE);
	}
	//软件升级的时候更新表结构调用,当newVersion>oldVersion时,系统自动触发该方法。
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

	}

}

MainActivity.java

public class MainActivity extends Activity {
	String a;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		MyDB db = new MyDB(this, "mydb.db3", 1);
		SQLiteDatabase database = db.getReadableDatabase();

	}
}

存储路径data/data/包名/databases/mydb.db3

卸载时文件依然丢失。



版权声明:本文为博主原创文章,未经博主允许不得转载。

Android数据存储

标签:android存储   chche   sharedpreferences   file   sd卡存储   

原文地址:http://blog.csdn.net/u010829905/article/details/47028179

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!