Android 中的数据存储

分类

  • 共享参数存储
  • File存储(内部,外部)
  • SQLite数据库
  • Content Provider
  • 网络存储

1 共享参数存储 Shared Preferences

1.1 特点

  • 存放轻量级的数据
  • 本质上xml的格式存数据,通过键值对的方式对数据进行读写
  • 应用程序被卸载后,文件也会被删除

1.2 存储数据的类型

boolean int String long float

1.3 路径

data/data/包名/shared_preds/名字.xml

1.4 存储数据


SharedPreferences sPreferences=getSharedPreferences(name,mode)//得到SharedPreferences对象

Editor editor = sPrefences.edit();//得到共享参数的编辑对象

editor.putString(key,value);//向共享参数中存入数据

editor.commit();//别忘记提交

1.5 读取数据


SharedPreferences sPreference=getSharedPreferences(name,mode);//得到SharedPreferences对象

String msg=sPreference.getString(key,defValue);//根据key读取数据defValue为默认值

1.6 SharedPreferences源码


public interface SharedPreferences {
  
        void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
    }
   
    public interface Editor {
      //存数据,需要定义Editer
        Editor putString(String key, @Nullable String value);

        Editor putStringSet(String key, @Nullable Set<String> values);
 
        Editor putInt(String key, int value);
           
        Editor putLong(String key, long value);
           
        Editor putFloat(String key, float value);
             
        Editor putBoolean(String key, boolean value);

        Editor remove(String key); 
  
        Editor clear();  

        boolean commit();    

        void apply();
    }
  //取数据
    Map<String, ?> getAll();
 
    @Nullable
    String getString(String key, @Nullable String defValue);
 
    @Nullable
    Set<String> getStringSet(String key, @Nullable Set<String> defValues);
     
    int getInt(String key, int defValue);

    long getLong(String key, long defValue);
 
    float getFloat(String key, float defValue);
     
    boolean getBoolean(String key, boolean defValue);
 
    boolean contains(String key);
   
    Editor edit();
   
    void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
    
    void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}

2 File存储

2.1内部存储 Internal Storage

2.1.1 特点

  • 文件只能被当前应用程序访问,其他应用程序不能访问
  • 文件卸载后,其中的数据也会随之清除

2.1.2路径

data/data/包名/files/xxx.xxx(名字.类型)

2.1.3 存入数据


FileOutputStream fos=openFileOutput(fileName,mode);//打开文件输出流

fos.write(byte[]);//写入数据

fos.close();//关闭流
</pre>
####取出数据####
<pre>
FileInputStream fis=openFileInput(fileName);//打开文件输入流

byte[] buffer=new byte[fis.avaiable()];//读取数据
fis.read(buffer);
//这儿可以根据要读取的数据类型,定义相应的接收

fis.close()//关闭流

2.2 外部存储 External Storage

2.2.1 特点

  • sdcard分为两个部分,一个为公共目录,一个是私有目录
  • 公共目录下的文件可以被其他目录访问,私有目录的只能被本应用程序访问
  • 卸载应用程序后,sd公共目录中的文件不会比清除,私有目录中的文件会被清除

2.2.2 路径

  • 公有:storage/sdcard
  • 私有:storage/sdcard/Android/data/包名/files/

2.2.3 权限问题

  • WRITE_EXTERNAL_STORAGE 写sd卡权限
  • READ_EXTERNAL_STORAGE 读sd卡权限
  • 注意:有时用studio自带的模拟器,加了权限,在运行时,却不能存入,提示FileNotFound及权限问题,这是模拟器的问题,用手机或者换个模拟器就行了

2.2.4 sd卡的状态

sd卡的状态可以用Environment.getExternalStorageState()判断
MEDIA_MOUNTED为挂载状态,表示可以使用

2.2.5 获得目录路径

  • Environment.getExternalStoragePublicDirectory();//公共目录
  • Environment.getExternalStorageDirectory();//私有目录

2.2.6 Environment中对应源码


//其中一些对象Environment中内部类UserEnvironment定义的
public static String getExternalStorageState() {
        final File externalDir = sCurrentUser.getExternalDirs()[0];
        return getExternalStorageState(externalDir);
    }

public static File getExternalStorageDirectory() {
        throwIfUserRequired();
        return sCurrentUser.getExternalDirs()[0];
    }

public static File getExternalStoragePublicDirectory(String type) {
        throwIfUserRequired();
        return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
    }

3 数据库存储

3.1 一些数据库

Oracle SQLServier Mysql SQLite

3.2 SQLite

Android系统中集成的轻量级的数据库

3.2.1 特点

  • 轻量级:一个动态的数据库,以单个文件的方式进行存取
  • 零配置:无需安装
  • 跨平台:可以支持多个操作系统
  • 嵌入式:嵌入手机

3.2.2 存放的数据类型

  • NULL 空值
  • INTENGER 整型
  • VARCHAR 可变长度的字符数据
  • TEXT 文本字符串
  • BOOLEAN 布尔

3.2.3 sql语句


//创建
create table if not exists 表名(字段名 字段类型 primary key autoincrement,字段名 字段类型,...)

//插入
insert into 表名(字段)Values(值)

//修改
update 表名 set 字段名=值 where 条件

//查询
select(显示的字段) from 表名 where 条件

//删除
delete from 表名 where 条件

3.3 Sqlite数据库核心类

3.3.1 SQLiteDatabase 管理和操作数据库

3.3.1.1 特点

  • 提供了一个管理数据库的类
  • 提供了增删改查数据库的方法
  • 数据库的名称在当前应用程序中是唯一的, 而不是在所有应用程序值唯一

3.3.1.2 部分代码:


SQLiteDatabase db=openOrCreateDatabase(name,mode,factory);
//name,数据库名称;
//mode,数据库访问权限;
//factory,游标工厂.

//执行数据库操作的方式:

//1、直接:
String sql="insert into person(name,age) values('张三',21)";
//sql为数据库语言
db.execSQL(sql);

//2、使用SQLiteDatabase里封装好的一些方法:

//查
/**
 * distinct     去除重复
 * table        表名
 * columns      字段  new String[]{"_id","name","age"}   如果查询所有数据, 则null
 * selection        条件  where之后的内容
 * selectionArgs    占位符的取值
 * groupBy      分组
 * having       放在where之后再次筛选
 * orderBy      排序 
 * limit        区间
 */
db.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy,limit);

//删
/***
 * table        表名
 * whereClause  删除的条件 where之后的内容
 * whereArgs    占位符的取值
 */
db.delete(table, whereClause, whereArgs);

//改
/**
 * table    表名
 * values   ContentValues 
 * whereClause  条件 占位符 where 之后的内容
 * whereArgs    占位符对应的值  
 */
db.update(table, values, whereClause, whereArgs);

//增
/**
 * table            表名
 * nullColumnHack   null    insert into person (nullColumnHack) values(null)
 * values           ContentValues(key,value)
 */
db.insert(table, nullColumnHack, values);

//其中ContentValues(key,value)创建使用
//key  表中的字段名称, value  对应的数据内容
ContentValues values = new ContentValues();
values.put("name", "行文不及码如风");
values.put("age", 23);

Context类中部分代码:


    /**
     * Open a new private SQLiteDatabase associated with this Context's
     * application package.  Create the database file if it doesn't exist.
     */
    public abstract SQLiteDatabase openOrCreateDatabase(String name,
            int mode, CursorFactory factory);



    /**
     * Open a new private SQLiteDatabase associated with this Context's
     * application package.  Creates the database file if it doesn't exist.
     */
    public abstract SQLiteDatabase openOrCreateDatabase(String name,
            int mode, CursorFactory factory, DatabaseErrorHandler errorHandler);


    /**
     * Delete an existing private SQLiteDatabase associated with this Context's
     * application package.
     */
    public abstract boolean deleteDatabase(String name);


    /**
     * Returns the absolute path on the filesystem where a database created with
     */
    public abstract File getDatabasePath(String name);


    /**
     * Returns an array of strings naming the private databases associated with
     * this Context's application package.
     */
    public abstract String[] databaseList();

SQLiteDatabase中部分源码:


    public void execSQL(String sql) throws SQLException {
        executeSql(sql, null);
    }

    public Cursor query(String table, String[] columns, String selection,
            String[] selectionArgs, String groupBy, String having,
            String orderBy) {

        return query(false, table, columns, selection, selectionArgs, groupBy,
                having, orderBy, null /* limit */);
    }

    public long insert(String table, String nullColumnHack, ContentValues values) {
        try {
            return insertWithOnConflict(table, nullColumnHack, values, CONFLICT_NONE);
        } catch (SQLException e) {
            Log.e(TAG, "Error inserting " + values, e);
            return -1;
        }
    }

    public int delete(String table, String whereClause, String[] whereArgs) {
        SQLiteStatement statement =  new SQLiteStatement(this, "DELETE FROM " + table +
                (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
        try {
            return statement.executeUpdateDelete();
        } catch (SQLiteDatabaseCorruptException e) {
            onCorruption();
            throw e;
        } finally {
            statement.close();
        }
    }

    public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
        return updateWithOnConflict(table, values, whereClause, whereArgs, CONFLICT_NONE);
    }

3.3.2 SQLiteOpenHelper 用于数据库的创建和版本更新

3.3.2.1 作用

  • 初始化数据库
  • 升级数据库 (更新)
  • 打开数据库连接 (存在则打开,不存在则创建并打开连接)

3.3.2.2 使用


//定义一个类继承SQLiteDatabase

public class MySqliteHepler extends SQLiteOpenHelper{
    //提供一个构造方法
    public MySqliteHepler(Context context, String name, CursorFactory factory, int version) {
        super(context, name, factory, version);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub
        //第一次创建数据库时执行, 只会执行一次
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub
        //当数据库的版本号发生变化后, 执行此方法, 会执行多次
    }

}

MySqliteHepler helper=new MySqliteHepler(context);
SQLiteDatabase db = helper.getWritableDatabase();
SQLiteDatabase db = helper.getReadableDatabase();

3.4Cursor

默认游标的位置位于所有数据之上

3.4.1 移动


boolean move(offset)  //游标向上或者向下移动指定的条数,并且判断是否存在

boolean moveToNext()  //游标移动到下一条数据, 并且判断下一条数据是否存在

Boolean moveToPrevious()  //游标移动到上一条数据, 并且判断上一条数据是否存在

boolean moveToFirst()  //游标移动到第一条数据, 并且判断第一条数据是否存在

boolean moveToLast()  //游标移动到最一条数据, 并且判断最一条数据是否存在

boolean moveToPosition()  //游标移动到指定数据, 并且判断该数据是否存在

int getCount()    //得到游标中所以数据的数量

3.4.2 常用取值:


int getColumnIndex(String columnName); //根据列名获取列的位置(列的位置从0开始)

String getColumnName(int columnIndex); //获取列的位置获取列名

int getColumnCount(); //获取列的个数

String getString(int columnIndex); //根据列的位置获取内容

3.4.3 SimpleCursorAdapter

3.4.3.1 特点

  • 数据源中必须要包括一个"_id" 的字段
  • 刷新适配器, 没有效果

/** 
* context       上下文对象
* layout        每个Item显示的布局页面
* c         游标(数据源) 
* from          String[] cursor中所有字段名称的数组 
* to            int[]    布局页面中Id的数组
* flags         标记, 自动更新(观察者)
*/
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
        context,
        layout, 
        c, 
        from,
        to,
        flags);
//例如:
SimpleCursorAdapter adapter = new SimpleCursorAdapter(
        this,
        R.layout.item, //子布局
        cursor, 
        new String[]{"name","age"},//两个属性名
        new int[]{R.id.name,R.id.age},//两个属性对应的子布局中控件id
        SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);

4 Content Provider

4.1 是什么

4.1.1 特点

  • 所有应用程序之间数据存储和检索的桥梁
  • 应用程序之间数据共享的唯一途径

4.1.2注意

  • 如果想访问内容提供者提供的数据,那么需要通过ContentResolver对象获取数据内容
  • 想要共享自己的数据,那么需要自定义一个内容提供者,把自己的数据共享出去

4.2做什么

  • 实现多个应用程序之间的共享

4.2.1 URI

  • content://应用程序包名.provider/表名 ---自定义

4.3 分析

  • ContentResolver 内容更解析器:负责解析ContentProvider暴露出来的数据
  • ContentProvider 内容提供者:负责暴露数据

4.4 实例

4.4.1 访问手机中提供的数据

访问短信记录


    private ListView listView;
    private Cursor cursor;
    private SimpleCursorAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listView=(ListView) findViewById(R.id.list_view);
        //得到数据源
        //得到内容解析器对象
        ContentResolver contentResolver=getContentResolver();
        //解析数据
       /**
         * uri              访问ContentProvider提供的路径
         * projection       查询数据库中的字段
         * _id, address     地址, data 日期, body 内容, type 短信类型
         * type         (1接收,2发送,3草稿箱,4未读的短信,5发送失败的短信 )
         * selection        查询的条件
         * selectionArgs    占位符的取值 
         * sortOrder        排序
         */
        Uri uri=Uri.parse("content://sms");
        String [] projection=new String[]{"_id","address","date","body","type"};
        cursor=contentResolver.query(uri, projection, null, null, null);
        adapter=new SimpleCursorAdapter(
        getApplicationContext(),
        R.layout.item,
        cursor,
        new String[]{"address","body"},
        new int[]{R.id.content_address,R.id.content_body},
        SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        listView.setAdapter(adapter);
    }

4.5 自定义ContentProvider

  • 定义一个类, 继承ContentProvider, 重写父类的6个方法

    onCreate()初始化工作

    query(Uri uri,....)  查询数据

    insert(Uri uri,....)  插入数据

    update(Uri uri,...)   修改数据

    delete(Uri uri,..)    删除数据

    getType()        只实现, 不处理

  • 声明ContentProvider的唯一标识 (内容只能为小写的字母,建议使用: 包名+数据库的名称)
  • 声明访问数据库的Code码 (在ContentProvider 暴露数据时使用)
  • 声明Uri的匹配器,并且实例化, 注册Uri

    private static  UriMatcher uriMatcher;

    static{
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCHER);
        uriMatcher.addUri(唯一标识, 路径<表名>, code码);
    }

  • 定义一个数据库的帮助类, 并且在Oncrate()方法中实例化
  • 在相应的增/删/改/查的方法中, 通过Uri的匹配器, 判断当前传入的Uri到底是操作哪一张表的
  • 在清单文件中注册

/***
*注册ContentProvider
*android:name    说明当前注册是哪个ContentProvider
*android:authorities    唯一标识, 必须要与ContentProvider中的唯一标识完全一直(复制过来)
*android:exported    声明当前的类, 可以被其他的应用程序访问
  */
  
< provider
    android:name="com.xwbjmrf.contentproviderdemo02.provider.MyContentProvider" 
    android:authorities="com.xwbjmrf.contentproviderdemo02.xwbjmrf"
    android:exported="true"
/>

5 网络存储

Android提供了通过网络来实现数据的存储和获取的方法。

我们可以调用WebService返回的数据或是解析HTTP协议实现网络数据交互。

具体需要熟悉Java.NET.* ,Android.Net.* 这两个包的内容,详细的类与方法的说明,请参考SDK

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容