zoukankan      html  css  js  c++  java
  • Android 五大存储方式具体解释

    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配置信息,比如(username,password等)。

    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的主键。

    android还为我们提供操作数据库的一些便捷方法

    insert方法

    不管第三个參数是否有数据,运行该方法都会加入一条数据。

            	//table插入的表名
            	//nullColumnHack强行插入为null列的列名 当values參数为null或不包括随意key-value对时该參数有效
            	//values代表一行记录的数据
            	insert(String table, String nullColumnHack, ContentValues values)
    实际insert方法底层依旧通过SQL语句来插入的。由于它生成的SQL语句总是形如以下的语句

    //ContentValue里的key-value对的数量决定了以下的key-value对。
    insert into <表名>(key1,key2...)values(value1,value2....)
    假设此时第三个參数为空

    insert into <表名>()values()


    updata方法

    该方法返回的数据库影响的行数

    //要更改数据库表名
    //更新完毕后的值
    //满足whereClaues字句的记录将会被更新
    //用于为whereClause字句传入參数
    update(String table, ContentValues values, String whereClause, String[] whereArgs)
    比如我们想更新person表中的全部主键大于20的人的人名。可调用例如以下方法:

    ContentValues values = new ContentValues();
    //存放更新之后的人名
    values.put("name", "新人名");
     db.update("person", values, "_id>?

    ", new Integer[]{20});

    相应SQL语句

    updata person set key1=value1,key2=value2...where _id>20


    delete方法

    返回值更改的行数

    //table表名。whereClause删除的条件 。whereArgs给whereClause传入删除的參数
    delete(String table, String whereClause, String[] whereArgs)
    比如:想删除person表中全部人名以王字开头的记录

    db.delete("person","name like?",new String[]{"王%"});
    相应SQl语句

    delete person where name like '王%'


    query方法

    //distinct指定是否去除反复记录
    //table 运行查询数据的表名
    //columns要查询出来的列名
    //selection查询条件的字句 相当于select语句wherekeyword后面的部分。
    //selectionArgs查询语句匹配的參数
    //groupBy用于控制分组,
    //having 对分组进行过滤
    //orderBy 排序,personid desc降序,age asc升序;
    //limit 进行分页  比如:5,10
    db.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit, cancellationSignal);


    db.query("person", new String[]{"_id,name,age"}, "name like ?", new String[]{"张%"}, null, null, "desc", null);

    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 {
    	//參数1:上下文
    	//參数2:数据库名字
    	//參数3:游标工厂(自己定义的时候才用,不须要自己定义null)
    	//数据库版本
    	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

    卸载时文件依旧丢失。


    查询的时候会用到Cursor:

    经常用法:

    isAfterLast()游标的指针是否指向了最后一条数据的后面

    moveToNext() 让游标的指针指向下一条数据

    moveToFirst() 让游标的指针指向第一条数据

    getString(int columnIndex) 获取当前行中指定列的String值。參数列索引

    getColumnIndex(StringcolumnName) 依据列名字获取列索引

    插入会用到:ContentValus 

    ContentValus的方法非常easy,键值对而已

    改动数据:

    //改动   參数1:被改动的表的名字   參数2:改动的成为的值    參数3:更新条件   參数4:更新条件中占位符的值

    db.update(DBHelper.TABLE_NAME, values,DBHelper.ENSCORE_NAME+" = ?", new String[]{"hanhan"});

     删除数据:

    //数据删除  參数1:要删除数据的表的名字   參数2:删除条件    參数3:删除条件中的占位符的值

            //返回值---》删除数据的行数

    db.delete(DBHelper.TABLE_NAME,DBHelper.ENSCORE_NAME+" = ?", new String[]{"zhangsan"})。






  • 相关阅读:
    从开心网的奴隶安抚与折磨想到员工积极性与人力成本的问题
    悲剧的做网站的,我们都没有认真的前行
    如何做生意
    Android Market中产品图标设计原则
    控制UpdataPanel中的GridView模板列控件同步刷新
    DataTable筛选
    IE6,7,8,FF兼容总结
    DevPress Grid 设置行样式
    SQL分组查询
    DevexPress checkedit 多选解决方案(原创)
  • 原文地址:https://www.cnblogs.com/mthoutai/p/6985983.html
Copyright © 2011-2022 走看看