分类
- 共享参数存储
- 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