Android 数据存储详解(5种)

1.sharedpreference

简介:保存检索基本数据类型(boolean float int long string)的键值对(基于XML文件存储的“key-value”)

存储位置:data/data/程序包名/shared_prefs目录下 

数据读写:

//写入
SharedPreferences mySharedPreferences= getSharedPreferences("Test",Activity.MODE_PRIVATE);//实例化SharedPreferences对象
SharedPreferences.Editor editor = mySharedPreferences.edit();//实例化SharedPreferences.Editor对象
editor.putString("t", "要保存的数据");//用putString的方法保存数据
editor.commit();//提交
//取值
SharedPreferences settings = getSharedPreferences("Test",Activity.MODE_PRIVATE);
String get = settings.getString("t","");
//删除
SharedPreferences mSharedPreferences= getSharedPreferences("Test",Activity.MODE_PRIVATE);
SharedPreferences.Editor meditor = mSharedPreferences.edit();
meditor.remove("key");//下一次commit的时候会移除key对应的键值对
meditor.clear();//移除所有键值对
editor.commit();

应用范围:很轻量级的应用,使用起来也很方便,简洁。但存储数据类型比较单一(只有基本数据类型),无法进行条件查询,只能在不复杂的存储需求下使用,比如保存配置信息等


2.文件存储

2.1 内部存储

简介:文件被保存在内部存储中时,默认情况下,文件是应用程序私有的,其他应用不能访问。当用户卸载应用程序时这些文件也跟着被删除。

存储位置:data/data/程序包名/files/文件名

数据写入:

① 调用Context的openFileOutput()函数,填入文件名和操作模式,它会返回一个FileOutputStream对象。

② 通过FileOutputStream对象的write()函数写入数据。

③  FileOutputStream对象的close ()函数关闭流。

代码:

String FILENAME = "save.txt";
String string = "data";
/**
 name参数: 用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。
 mode参数:用于指定操作模式,分为四种:
 Context.MODE_PRIVATE =           为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容。
 Context.MODE_APPEND = 32768      该模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 
 Context.MODE_WORLD_READABLE = 1   表示当前文件可以被其他应用读取。
 MODE_WORLD_WRITEABLE             表示当前文件可以被其他应用写入。
 */
try {
    FileOutputStream fileOutputStream = openFileOutput(FILENAME, Context.MODE_PRIVATE);
    fileOutputStream.write(string.getBytes());
    fileOutputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}

数据读取:

① 调用openFileInput( ),参数中填入文件名,会返回一个FileInputStream对象。

  ② 使用流对象的 read()方法读取字节

  ③ 调用流的close()方法关闭流

代码:

//读取
String FILENAME1 = "save.txt";
try {
    FileInputStream inputStream = openFileInput(FILENAME1);
    int len = 0;
    byte[] buf = new byte[1024];
    StringBuilder sb = new StringBuilder();
    while ((len = inputStream.read(buf)) != -1) {
        sb.append(new String(buf, 0, len));
    }
    inputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}
/** * 附:常用的一些方法 getFilesDir(): 获取内存储文件的绝对路径 getDir():  在内存储空间中创建或打开一个已经存在的目录 deleteFile():  删除保存在内部存储的文件 fileList():  返回当前由应用程序保存的文件的数组(内存储目录下的全部文件) */

2.2 外部存储

简介:因为内部存储容量限制,有时候需要存储数据比较大的时候需要用到外部存储 存储位置:data/data/程序包名/files/文件名

添加权限:

 <!-- SDCard创建、删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- SDCard写入权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

检测外部存储是否可用

String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
    // 可读可写
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
    // 可读
} else {
    // 有很多其他状态,但只需要知道不能读写(不深究原理过程细节的话)
}


访问外部存储器中的文件

API>8:

//该方法打开一个外存储目录,此方法需要一个类型,指定你想要的子目录,如类型参数DIRECTORY_MUSIC和 DIRECTORY_RINGTONES(传null就是你应用程序的文件目录的根目录)
// 通过指定目录的类型,确保Android的媒体扫描仪将扫描分类系统中的文件(例如,铃声被确定为铃声)
// 如果用户卸载应用程序,这个目录及其所有内容将被删除。
getExternalFilesDir (String type);
File file = new File(getExternalFilesDir(null), "fanrunqi.jpg");

API<8:

//通过该方法打开外存储的根目录,你应该在以下目录下写入你的应用数据,这样当卸载应用程序时该目录及其所有内容也将被删除
getExternalStorageDirectory ();
/Android/data/<package_name>/files/


数据写入:

① 调用Context的openFileOutput()函数,填入文件名和操作模式,它会返回一个FileOutputStream对象。

② 通过FileOutputStream对象的write()函数写入数据。

③  FileOutputStream对象的close ()函数关闭流。

代码:

数据读取:

① 调用openFileInput( ),参数中填入文件名,会返回一个FileInputStream对象。

  ② 使用流对象的 read()方法读取字节

  ③ 调用流的close()方法关闭流

代码:


if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录  "/sdcard"

            File saveFile = new File(sdCardDir,"save.txt");

            //写数据
            try {
                FileOutputStream fos= new FileOutputStream(saveFile);
                fos.write("happy".getBytes());
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            //读数据
            try {
                FileInputStream fis= new FileInputStream(saveFile);
                int len =0;
                byte[] buf = new byte[1024];
                StringBuffer sb = new StringBuffer();
                while((len=fis.read(buf))!=-1){
                    sb.append(new String(buf, 0, len));
                }
                fis.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
//亦可在 /Android/data/package_name/cache/目录下做外部缓存。


3.SQLite数据库存储

Activites 可以通过 Content Provider 或者 Service 访问一个数据库。

数据库创建:

Android 不自动提供数据库。

在 Android 应用程序中使用 SQLite,必须自己创建数据库,然后创建表、索引,填充数据。

Android 提供了 SQLiteOpenHelper 帮助创建数据库,只要继承 SQLiteOpenHelper 类根据开发应用程序的需要,封装创建和更新数据库使用的逻辑就行了。 

自己写一个DataBaseHelper类:

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * Created by THF on 17/4/5.
 */

public class DataBaseHelper extends SQLiteOpenHelper {
    /**
     * @param context  上下文环境(例如,一个Activity)
     * @param name     数据库名字
     * @param factory  一个可选的游标工厂(通常是 Null)
     * @param version  数据库模型版本的整数
     * 会调用父类 SQLiteOpenHelper的构造函数
     */
    public DataBaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }
    /**
     *在数据库第一次创建的时候会调用这个方法
     *根据需要对传入的SQLiteDatabase 对象填充表和初始化数据。
     */
    @Override
    public void onCreate(SQLiteDatabase db) {

    }
    /**
     * 当数据库需要修改的时候(两个数据库版本不同),Android系统会主动的调用这个方法。
     * 一般我们在这个方法里边删除数据库表,并建立新的数据库表.
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //三个参数,SQLiteDatabase 对象,旧版本号,新版本号
    }
    @Override
    public void onOpen(SQLiteDatabase db) { // 每次成功打开数据库后首先被执行
        super.onOpen(db);
    }
}

继承SQLiteOpenHelper之后就拥有了以下两方法:

  • getReadableDatabase()  创建或者打开一个查询数据库
  • getWritableDatabase()   创建或者打开一个可写数据库

/**
 * 这段代码会返回一个 SQLiteDatabase 类的实例,使用这个对象可以查询、修改数据库
 */
DatabaseHelper database = new DatabaseHelper(context);//传入上下文参数
SQLiteDatabase sqLiteDatabase = null;
sqLiteDatabase = database.getWritableDatabase();

SQLiteDatabase类常用的方法:

/**
 * 各参数说明: 
 table:表名称 
 colums:列名称数组 
 selection:条件子句,相当于where 
 selectionArgs:条件语句的参数数组 
 groupBy:分组 
 having:分组条件 
 orderBy:排序类 
 limit:分页查询的限制 
 Cursor:返回值,相当于结果集ResultSet
 */
添加数据行:
( long) insert(String table,String nullColumnHack,ContentValues values)
更新数据行:
( int) update(String table, ContentValues values, String whereClause, String[] whereArgs)

删除数据行:
(int) delete(String table,String whereClause,String[] whereArgs)
关闭数据库:
(void) close()

执行一个SQL语句,可以是一个select或其他的sql语句:

(void) execSQL(String sql)
查询指定的数据表返回一个带游标的数据集:
(Cursor) query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)


创建表和索引

/**
         为了创建表和索引,需要调用 SQLiteDatabase 的 execSQL() 方法来执行 DDL 语句。如果没有异常,这个方法没有返回值。
         例如,你可以执行如下代码:
         这条语句会创建一个名为 user的表,表有一个列名为 _id,并且是主键,这列的值是会自动增长的整数。
	 另外还有两列:username( 字符 ) 和 password( 字符 )。 SQLite 会自动为主键列创建索引。
         通常情况下,第一次创建数据库时创建了表和索引。要 删除表和索引,需要使用 execSQL() 方法调用 DROP INDEX 和 DROP TABLE 语句。
         */

        sqLiteDatabase.execSQL("CREATE TABLE user(_id INTEGER PRIMARY KEY
                AUTOINCREMENT, username TEXT, password TEXT);");

增:(2种)

 	//1.可以使用 execSQL() 方法执行 INSERT, UPDATE, DELETE 等语句来更新表的数据。execSQL() 方法适用于所有不返回结果的 SQL 语句。
        String sql = "insert into user(username,password) values ('smile','88888888');//插入操作的SQL语句
        sqLiteDatabase.execSQL(sql);//执行SQL语句
    
        //2.使用 SQLiteDatabase 对象的 insert()
        ContentValues cv = new ContentValues();
        cv.put("username","smile");//添加用户名
        cv.put("password","88888888"); //添加密码
        sqLiteDatabase.insert("user",null,cv);//执行插入操作

删:

	//1.使用SQLiteDatabase 对象的delete()方法。
        String whereClause = "username=?";//删除的条件
        String[] whereArgs = {"smile"};//删除的条件参数
        sqLiteDatabase.delete("user",whereClause,whereArgs);//执行删除
        //2.使用execSQL方式的实现
        String sql = "delete from user where username=\"smile\""; //删除操作的SQL语句
        sqLiteDatabase.execSQL(sql);//执行删除操作

改:

//1.使用SQLiteDatabase 对象的 update()方法。
        ContentValues cv = new ContentValues();
        cv.put("password","666888");//添加要更改的字段及内容
        String whereClause = "username=?";//修改条件
        String[] whereArgs = {"smile"};//修改条件的参数
        sqLiteDatabase.update("user",cv,whereClause,whereArgs);//执行修改
        /**
         *  该方法四个参数: 
           表名;
           列名和值的 ContentValues 对象; 
           可选的 WHERE 条件; 
           可选的填充 WHERE 语句的字符串,这些字符串会替换 WHERE 条件中的“?”标记,update() 根据条件,更新指定列的值. 
         */
        //2.使用execSQL方式的实现
        String sql = "update [user] set password = '666888' where username=\"smile\"";//修改的SQL语句
        sqLiteDatabase.execSQL(sql);//执行修改

查:

 	/**
         * 这段代码会返回一个 SQLiteDatabase 类的实例,使用这个对象可以查询、修改数据库
         */
        DatabaseHelper database = new DatabaseHelper(context);//传入上下文参数
        SQLiteDatabase sqLiteDatabase = null;
        sqLiteDatabase = database.getWritableDatabase();

        //1.使用 rawQuery() 直接调用 SELECT 语句

        Cursor cursor = sqLiteDatabase.rawQuery("select * from user where username=?",new String[]{"smile"});
        if(cursor.moveToFirst()) {
            String password = cursor.getString(cursor.getColumnIndex("password"));
        }
        /**
         * 返回值是一个 cursor 对象,这个对象的方法可以迭代查询结果。
         * 如果查询是动态的,使用这个方法就会非常复杂。
         * 例如,当你需要查询的列在程序编译的时候不能确定,这时候使用 query() 方法会方便很多。
         */
        
        //2.通过query实现查询

        /**
         *  query() 方法用 SELECT 语句段构建查询。
           SELECT 语句内容作为 query() 方法的参数,
            比如:要查询的表名,要获取的字段名,WHERE 条件,包含可选的位置参数,去替代 WHERE 条件中位置参数的值,GROUP BY 条件,HAVING 条件。
           除了表名,其他参数可以是 null。所以代码可写成:
         */

        Cursor cursor = sqLiteDatabase.query("user",null,null,null,null,null,null);//查询并获得游标
        if(cursor.moveToFirst()){//判断游标是否为空
            for(int i=0;i<c.getCount();i++){
                cursor.move(i);//移动到指定记录
                String username = cursor.getString(c.getColumnIndex("username");
                String password = cursor.getString(c.getColumnIndex("password"));
            }
        }

游标:

执行查询时都会返回一个 Cursor,此为 Android 的 SQLite 数据库游标,使用此游标可以:

getCount() 方法得到结果集中有多少记录; 

moveToFirst(), moveToNext(), 和 isAfterLast() 方法遍历所有记录;

getColumnNames() 得到字段名;

getColumnIndex() 转换成字段号;

getString(),getInt() 等方法得到给定字段当前记录的值;

requery() 方法重新执行查询得到游标;

close() 方法释放游标资源;

	//代码遍历 user表:
        Cursor result= sqLiteDatabase.rawQuery("SELECT _id, username, password FROM user");
        result.moveToFirst();
        while (!result.isAfterLast()) {
            int id=result.getInt(0);
            String name=result.getString(1);
            String password =result.getString(2);
            // do something useful with these
            result.moveToNext();
        }
        result.close();


4.ContentProvider

ContentProvider(内容提供者)是Android的四大组件之一,管理android以结构化方式存放的数据,以相对安全的方式封装数据(表)并且提供简易的处理机制和统一的访问接口供其他程序调用。  

有时候我们需要操作其他应用程序的一些数据,就会用到ContentProvider。而且Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。

但注意ContentProvider它也只是一个中间人,真正操作的数据源可能是数据库,也可以是文件、xml或网络等其他存储方式。


URI  android中:content://(schema)   主机名(Authority)     对象集合  特定的记录(path)

1Android 两个操作URI的工具类

1.1 ContentUris

  追加id

        Uri uri = Uri.parse("content://cn.sdu.demo/user");
Uri resultUri = ContentUris.withAppendedId(uri, 6);

获取id

Uri uri = Uri.parse("content://cn.sdu.demo/user/6");
long personid = ContentUris.parseId(uri);

1.2 UriMatcher

UriMacher 是一个文本过滤器,用在contentProvider中帮助过滤 分辨出查询者想要查询哪个数据表

a. 初始化

//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);

b. 注册需要的Uri

//USERUSER_IDint型数据
matcher.addURI("cn.sdu.demo", "user", USER);
matcher.addURI("cn.sdu.demo", "user/#",USER_ID);

c.与已经注册的Urip进行匹配

/*
 *
如果操作集合,则必须以vnd.android.cursor.dir开头
 *
如果操作非集合,则必须以vnd.android.cursor.item开头
 * */
   
@Override
   
public String getType(Uri uri) {
        Uri uri = Uri.parse("content://" + "cn.sdu.demo" + "/user");
        switch(matcher.match(uri)){
            case USER:
                return "vnd.android.cursor.dir/user";
            case USER_ID:
                return "vnd.android.cursor.item/user";
        }
    }

2. ContentProvider的主要方法

/**
 ContentProvider
创建后 或 打开系统后其它应用第一次访问该ContentProvider时调用。
 public boolean onCreate()
 
 
外部应用向ContentProvider中添加数据。增
 public Uri insert(Uri uri, ContentValues values)
 
 
外部应用从ContentProvider删除数据。删
 public int delete(Uri uri, String selection, String[] selectionArgs)
 
 
外部应用更新ContentProvider中的数据。改
 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)


 
供外部应用从ContentProvider中获取数据。
 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
 

 
该方法用于返回当前Url所代表数据的MIME类型。
 public String getType(Uri uri)
 */


3.ContentResolver

ContentResolver通过URI查询ContentProvider提供数据

除了URI以外,还必须知道需要获取的数据段名称和数据类型

比如需要获取一个特定记录,必须知道当前记录的ID


ContentResolver的方法:


/**
 * public Uri insert(Uri uri, ContentValues values)
 增

 public int delete(Uri uri, String selection, String[] selectionArgs)
 删

 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
 改

 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

 */


4.ContentObserver

  ContentObserver(内容观察者),目的是观察特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它.



5.网络存储

















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值