您的位置:首页 > 其它

安卓中五种数据存储方式

2016-11-14 23:41 204 查看
分别是:

--SharedPreferences存储;

--文件存储;

--SQLite数据库存储;

--ContentProvider存储;

--网络存储;

1.1. SharedPreferences存储:

应用场景

适用于存储一些键值对,一般用来存储配置信息。

存储位置:

/data/data/包名/shared_prefs 目录下,以xml格式进行保存。

可存储的数据类型:

boolean float int long string

存储步骤:

1.根据上下文获取SharedPreferences对象。

2.利用edit()方法获取Editor对象。

3.通过Editor对象来存储key-value键值对数据。

4.通过commit()方法提交数据。

好处:

SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。

弊端:

1.只能存储五种简单的数据类型

2.无法进行条件查询

 

示例代码:

sp存储数据:

//参数1:文件名,没有则创建。参数2:文件权限
SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);
//获取编辑器
Editor editor = sp.edit();
//存入姓名与密码     
editor.putString("name", name);     
editor.putString("pwd", pwd);
//提交
editor.commit();
这段代码执行后,会在/data/data/<包名>/shared_prefs目录下生成了一个info.xml文件,一个应用可以创建多个这样的xml文件。

 

从sp中获取数据:

 String name = sp.getString("name", "");    
String pwd = sp.getString("pwd", "");
 

 

1.2. 文件存储:

应用场景:

存储一些简单的文本数据或者二进制数据

存储在内存:

当应用安装到 Android 后,系统会根据每个应用的包名创建一个/data/data/包名/的文件夹,默认是私有的。

 

注意:如果直接File file = new File(“info.txt”);

这样就报文件找不到的异常,因为这样写会被创建到手机内部存储的根目录里面,但是内部存储根目录是只读不可写的。

优化:File file = new File(getFileDir,”info.txt”);

 

目录:

/data/data/<包名>/files/info.txt--->getFileDir()+”info.txt”

 

权限:

访问自己包名下的目录是不需要权限

 

方便api:

 getCacheDir(); //方法用于获取/data/data/cache目录,缓存目录,当存储空间不足,系统会自动将之清除。 
 
 getFilesDir(); //方法用于获取/data/data/files目录,保存重要的数据信息
 

保存

File file = new File("/data/data/com.qq.file/info.txt");

FileOutputStream fos = new FileOutputStream(file);

fos.write((username+"##"+pwd).getBytes());//用##将username和pwd分隔开

fos.close();

Toast.makeText(MainActivity.this,"数据保存成功",Toast.LENGTH_SHORT).show();
 

回显

//File file = new File("/data/data/com.qq.file/info.txt");
File file = new File(getFileDir,”info.txt”);

if(file.exists()&&file.length()>0){

     try {

         FileInputStream fis = new FileInputStream(file);

         BufferedReader br = new BufferedReader(new InputStreamReader(fis));

         String info = br.readLine();

         String username = info.split(info)[0];

         String pwd = info.split(info)[1];

         etUsername.setText(username);

         etPwd.setText(pwd);

     } catch (Exception e) {

         e.printStackTrace();

     }

}
 

 

存储在sd卡:

目录:

mnt/sdcard/info.txt--->Envitonment.getExternalStorageState()+”info.txt”

 

权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 

方便api:

获取SD卡根目录

Environment.getExternalStorageDirectory()
获取SD卡的挂载状态

Environment.getExternalStorageState()
获取SD卡可用空间大小

Environment.getExternalStorageDirectory().getFreeSpace()
 

保存:

String qq = et_qq.getText().toString().trim();
String pwd = et_password.getText().toString().trim();

    if (cb_remember.isChecked()) {// 记住密码

        Log.i(TAG, "记住密码");

        try {

        // 检查sd是否存在,是否可用.

        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {

        Toast.makeText(this, "sd卡不可用,请检查sd卡的状态", 0).show();

        return;

        }

        // 检查sd卡的可用空间.

        long size = Environment.getExternalStorageDirectory().getFreeSpace();

        String info = Formatter.formatFileSize(this, size);

        Toast.makeText(this, "可用空间:" + info, 0).show();
//将文件存储在sd卡

        File file = new File(Environment.getExternalStorageDirectory(),"info.txt");

        FileOutputStream fos = new FileOutputStream(file);

        // 10000##abc

        fos.write((qq + "##" + pwd).getBytes());

        fos.close();

        Toast.makeText(this, "数据保存成功", 0).show();

        } catch (Exception e) {

        e.printStackTrace();

        Toast.makeText(this, "数据保存失败", 0).show();

        }

} else {// 不需要记住密码

        Log.i(TAG, "不需要记住密码");

        }
 

回显:

File file = new File(Environment.getExternalStorageDirectory(),"info.txt");

if(file.exists()&&file.length()>0){

        try{

        FileInputStream fis=new FileInputStream(file);

        BufferedReader br=new BufferedReader(new InputStreamReader(fis));

        // 10000##abc

        String info=br.readLine();

        String qq=info.split("##")[0];

        String pwd=info.split("##")[1];

        et_qq.setText(qq);

        et_password.setText(pwd);

        }catch(Exception e){

        e.printStackTrace();

        }
}
 

 文件的权限

应用程序在data/data/<自己包名>/目录下创建的文件默认都是私有的,别的程序是不能访问的

在模拟器中我们能再看这个目录并导到桌面上打开,但是注意真实手机没有root权限,所以你根本打不开这个目录。

 

创建有权限的文件:

openFileOutput(“info.txt”,mode);

 

mode是文件访问权限:

Context.MODE_PRIVATE=0:默认为私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容。

Context.MODE_APPEND=32768:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。

MODE_WORLD_READABLE=1:表示当前文件可以被其他应用读取;

MODE_WORLD_WRITEABLE=2:表示当前文件可以被其他应用写入。

 

如果想创建可读可写的文件:

FileOutputStream fos =openFileOutput(“info.txt”,Context.MODE_WORLD_READBLE+Context.MODE_WORLD_WRITEBLE)

在cmd窗口下修改文件的权限

chmod 666 private.txt--->这样就将private.txt文件的权限修改成了可读可写的文件了

600:私有

662:可读

664:可写

666:可读可写

777:可读可写可执行

 

1.3. SQLite数据库存储

定义:

SQLiteOpenHelper 是 Android 提供的一个抽象工具类,负责管理数据库的创建、打开、升级工作。如果我们想创建数据库,就需要自定义一个类继承 SQLiteOpenHelper,然后重写其中的抽象方法

 

应用场景:

适用于存储一些复杂的关系型数据。

存储位置:

 data/<项目文件夹
>/databases/下。

好处:

   支持 SQL 语言

         效率高,利用很少的内存就有很好的性能

         十分适合存储结构化数据

   方便在不同的Activity,甚至不同的应用之间传递数据

 

示例代码

1.3.1. 创建数据库

1.继承SQLiteOpenHelper
public class mSQLiteOpenHelper extends SQLiteOpenHelper {
    Public mSQLiteOpenHelper (Context context){
       //上下文,数据库名称,默认游标工厂,数据库版本号
       Super(context,”test.db”,null,1);
}
2.在onCreate()里适合创建表结构
@Override
public void onCreate(SQLiteDatabase db) {
    System.out.println("数据库oncreate");
    db.execSQL("create table student (_id integer primary key autoincrement, name varchar(20), phone varchar(30))");
}
//3.升级数据库
当手机中数据库版本低于数据库中配置的版本时,会自动调用onUpdate()方法进行数据库升级
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    System.out.println("数据库要被更新了,onupgrade");
    //db.execSQL("alter table student add account varchar(20)");
}
}
 
 4.创建数据库实例
//这一句代码执行完,数据库是不会被创建的
mSQLiteOpenHelper helper = new mSQLiteOpenHelper(this);
//执行这两句中其中一句,数据库才被创建
helper.getWritableDatabase();
helper.getReadableDatabase();
 

1.3.2. 对数据库增删改查

1.sql语句


  insert into student (name, phone) values (‘张三’, ‘110’)

  delete from student where name=‘张三’

  update student set phone=‘119’ where name=‘张三’

  select * from student where name=‘张三’ 
对于熟悉 SQL 的开发人员来时,在Android
开发中使用SQLite
相当简单。但是,由于JDBC
会消耗太多的系统资源,所以JDBC
对于手机这种内存受限设备来说并不合适。因此,Android提供了一些新的
API来使用
SQLite数据库,Android开发中,程序员需要学使用这些
API。

 

2.用api
public class StudentDao {
private StudentDBOpenHelper helper;
    public StudentDao(Context context) { //在构造方法中传入helper
        helper = new StudentDBOpenHelper(context);
    }
//增
   
public long add(String name,String sex){
    SQLiteDatabase  db = helper.getWritableDatabase();
    //db.execSQL("insert into student (name,sex) values (?,?)", new    
    Object[]{name,sex});
    ContentValues values =new ContentValues();
    values.put("name", name);
    values.put("sex", sex);
    long result = db.insert("student", null, values); //组拼sql语句实现的.带返回值
    db.close(); //释放资源
    return result; //添加到哪一行,-1添加失败
 }
//删
    public int delete(String name){
        SQLiteDatabase  db = helper.getWritableDatabase();
        //db.execSQL("delete from student where name=?",new Object[]{name});
        int result = db.delete("student", "name=?", new String[]{name});
        db.close(); //释放资源
        return result; //result是删除了几行,0代表删除失败
    }
//改

    public int update(String name,String newsex){
        SQLiteDatabase  db = helper.getWritableDatabase();
        //db.execSQL("update student set sex =? where name=?",new
        Object[]{newsex,name});
        ContentValues values = new ContentValues();
        values.put("sex", newsex);
        int result = db.update("student", values, "name=?", new String[]{name});
        db.close(); //释放资源
        return result; //result是更新了几行,0代表更新失败
//查
 public String find(String name){
        String sex = null;
        SQLiteDatabase  db = helper.getReadableDatabase();
        //结果集 游标
        //Cursor cursor = db.rawQuery("select sex from student where name=?", new
         String[]{name});
        Cursor cursor = db.query("student", new String[]{"sex"}, "name=?", new
        String[]{name}, null, null, null);
        boolean result = cursor.moveToNext();
        if(result){
            sex = cursor.getString(0);
        }
        cursor.close(); //释放资源
        db.close();
        return sex; //学生性别,null代表学生不存在
    }
//获取学生全部信息
 public List<Student> findAll(){
        List<Student> students =new ArrayList<Student>();
        SQLiteDatabase  db = helper.getReadableDatabase();
        //Cursor cursor = db.rawQuery("select name, sex from student", null);
        Cursor cursor =  db.query("student", new String[]{"name","sex"}, null, null, null,
        null, null);
        while(cursor.moveToNext()){
            String name = cursor.getString(0);
            String sex = cursor.getString(1);
            Student student = new Student();
            student.setName(name);
            student.setSex(sex);
            students.add(student);
        }
        cursor.close();
        db.close();
        return students;
    }
}
 
在MainActivity中修改增加、删除功能

1)修改增加功能
// 判断是否有重复的数据
long rowid = dao.add(name, sex);
if (rowid != -1) {
    Toast.makeText(this, "数据添加成功,在数据库的" + rowd + "行",
0).show();
        refreshData();
} else {
    Toast.makeText(this, "数据添加失败", 0).show();
}
2)修改删除功能
// 从数据库删除数据.
int count = dao.delete(name);
if (count > 0) {
    Toast.makeText(MainActivity.this, "数据被删除了" + count + "个", 0).show();
    // 更新ui界面.
    refreshData();
} else {
    Toast.makeText(MainActivity.this, "数据删除失败", 0).show();
}
 

1.3.3. 数据库的事务

private String s;
BankDBOpenHelper helper = new BankDBOpenHelper(this);
SQLiteDatabase db = helper.getWritableDatabase();
db.beginTransaction();//1.开启事务
try {
    // 模拟转账的操作
    db.execSQL("update account set money=money-100 where name='zhangsan'");
    s.endsWith("haha");
    db.execSQL("update account set money=money+100 where name='lisi'");
    db.setTransactionSuccessful();//2.设置事务执行成功
} finally {
    db.endTransaction();
//3.结束事务
}
db.close();

1.4. ContentProvider存储

理解

一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URI来表示外界需要访问的“数据库”。 

Android提供了一些已经在系统中实现的标准Content Provider,比如联系人信息,图片库等等,你可以用这些Content
Provider来访问设备上存储的联系人信息,图片等等。

 

示例Uri:

content://media/internal/images 这个URI将返回设备上存储的所有图片

content://contacts/people/ 这个URI将返回设备上的所有联系人信息

content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)

 

这种查询字符串格式有点令人迷惑。为此,Android提供一系列的帮助类(在android.provider包下),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,参见下例:

MediaStore.Images.Media.INTERNAL_CONTENT_URI

Contacts.People.CONTENT_URI

 

因此,如上面content://contacts/people/45这个URI就可以写成如下形式:

Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);

然后执行数据查询: Cursor cur = managedQuery(person, null, null, null);

 

应用场景:

增删改查其他应用程序中私有数据。

Android系统中能实现所有应用程序共享的一种数据存储方式,由于数据通常在各应用间的是互相私密的,所以此存储方式较少使用,但是其又是必不可少的一种存储方式。例如音频,视频,图片和通讯录,一般都可以采用此种方式进行存储。

 

 

创建内容提供者编写的流程:
1.写一个类继承ContentProvider,实现增删改查的方法,声明uriMatcher匹配规则,来检查uri路径是否正确
2.清单文件配置:
<provider

        android:name="com.bank.BankDBBackdoor"

        android:authorities="com.bank.db"
  android:exported="true" />

    
3.在另一个程序里面通过contentResolver增删改查

1.4.1. 示例代码:银行行长从银行数据库搞钱:

一、银行数据库:

1.MyDBOpenHelper extends SQLiteOpenHelper

2.在activity里面创建出数据库实例

MyDBOpenHelper helper = new MyDBOpenHelper(this);

helper.getWritableDatabase();
 

二、内容提供者

1.在清单文件中配置内容提供者

<provider

    android:name="bank_provider.BankDBBackDoor"

    android:authorities="com.bank.db" //主机名,别的应用程序找到内容提供者靠主机名
android:exported="true"/>
 

2.设置uri检查的规则:

制定Uri规则:

  //过滤请求,检查uri的规则,如果uri匹配失败就返回-1。一般写UriMatcher.NO_MATCH,表示默认返回-1

static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

private static final int SUCCESS = 1;

static {//静态代码块的好处:创建这个类必定会执行里面的代码一次

     //三个参数:主机名,自己设置的暗号,返回码

     uriMatcher.addURI("com.bank.db","account",SUCCESS);

}

 

检查Uri规则:

在内容提供者增删改查的方法里面检查传递过来的uri是否正确
public Uri insert(Uri uri, ContentValues contentValues) {

    int code = uriMatcher.match(uri);//检查uri规则是否正确

    if (code == SUCCESS) {//uri规则正确

        Log.e(TAG, "增加了一条数据");

    } else {

        //就抛出一个异常

        throw new IllegalArgumentException("uri规则不符合");

    }
 

3.在内容提供者代码里面提供增删改查方法

public class BankDbBackdoor
extends ContentProvider {

    private static final String TAG = "BankDbBackdoor";
private static final int SUCCESS = 1;

    

     //过滤请求,检查uri的规则是否正确,如果uri匹配失败就返回-1

     //一般写UriMatcher.NO_MATCH 表示默认返回-1

    static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    //静态代码块的好处就是程序必须走一遍静态代码块里面的内容

    static {

        //三个参数:主机名,自己设置的暗号,返回码

        uriMatcher.addURI("com.bank.db", "account", SUCCESS);

    }

    @Override

    public boolean onCreate() {

        return false;

    }

    @Nullable

    @Override

    public String getType(Uri uri) {

        return null;

    }

    @Nullable

    @Override

    public Uri insert(Uri uri, ContentValues contentValues) {//增

        int code = uriMatcher.match(uri); //检查uri规则是否正确

        if (code == SUCCESS) { //uri规则正确

            Log.e(TAG, "增加了一条数据");

            MyDBOpenHelper helper = new MyDBOpenHelper(getContext());

            SQLiteDatabase db = helper.getWritableDatabase();

            db.insert("account", null, contentValues);

            //利用内容提供者的解析器通知内容观察者数据发生了变化

            getContext().getContentResolver().notifyChange(uri,null);

        } else {

            //就抛出一个异常

            throw new IllegalArgumentException("uri规则不符合");

        }

        return null;

    }

    @Override

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

        int code = uriMatcher.match(uri);//检查uri规则是否正确

        if (code == SUCCESS) {//uri规则正确

            Log.e(TAG, "删除了一条数据");

            MyDBOpenHelper helper = new MyDBOpenHelper(getContext());

            SQLiteDatabase db = helper.getWritableDatabase();

            //参数:表名,删除的条件,

            db.delete("account", selection, selectionArgs);

        } else {

            //就抛出一个异常

            throw new IllegalArgumentException("uri规则不符合");

        }

        return 0;

    }

    @Override

    public int update(Uri uri, ContentValues values, String selection, String[] strings) {//改

        int code = uriMatcher.match(uri);

        if (code == SUCCESS) {

            Log.e(TAG, "改变了一条数据");

            MyDBOpenHelper helper = new MyDBOpenHelper(getContext());

            SQLiteDatabase db = helper.getWritableDatabase();

            db.update("account", values, selection, strings);

        } else {

            throw new IllegalArgumentException("uri规则不符合");

        }

        return 0;

    }

    @Nullable

    @Override

    public Cursor query(Uri uri, String[] colums, String selection, String[] selectionArgs,

                        String sortOrder) {
//查

        int code = uriMatcher.match(uri);

        if (code == SUCCESS) {

            Log.e(TAG, "查询了一条数据");

            MyDBOpenHelper helper = new MyDBOpenHelper(getContext());

            SQLiteDatabase db = helper.getReadableDatabase();

            //参数:表名,查询哪一列的内容,选择的条件语句,语句的参数,null,null,以什么样的规则排序

            return db.query("account", colums, selection, selectionArgs, null, null, sortOrder);//返回查询的结果

        } else {

            throw new IllegalArgumentException("uri规则不符合");

        }

    }

}

三、其他程序:

6.另外一个程序通过contentResolver对银行数据库进行增删改查

@OnClick(R.id.insert)

    public void insert(View view) { //增

        ContentResolver resolver = getContentResolver();

        Uri uri = Uri.parse("content://com.bank.db/account");

        ContentValues values = new ContentValues();

        values.put("name", "zhangsan");

        values.put("money", "100");

        resolver.insert(uri, values);

    }

    @OnClick(R.id.delete)

    public void delete(View view) { //删

        ContentResolver resolver = getContentResolver();

        Uri uri = Uri.parse("content://com.bank.db/account");

        resolver.delete(uri, "name=?", new String[]{"zhangsan"});

    }

    @OnClick(R.id.update)

    public void update(View view) { //改

        ContentResolver resolver = getContentResolver();

        Uri uri = Uri.parse("content://com.bank.db/account");

        ContentValues values = new ContentValues();

        values.put("money", 200);

        //修改zhangsan的money为200

        resolver.update(uri, values, "name=?", new String[]{"zhangsan"});

    }

    @OnClick(R.id.query)

    public void query(View view) { //查

        ContentResolver resolver = getContentResolver();

        Uri uri = Uri.parse("content://com.bank.db/account");

        //查询name和money这两列的内容

        Cursor cursor = resolver.query(uri, new String[]{"name", "money"}, null, null, null);

        while (cursor.moveToNext()) {

            Log.e(TAG, "进入了corsor循环");

            String name = cursor.getString(0);

            float money = cursor.getFloat(1);

            Log.e(TAG, "name" + name + "---------" + "money" + money);

        }

        cursor.close();//释放资源

    }
 

1.5. 网络存储

应用场景:

存储比较重要的数据,比如支付宝账号密码等等

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

权限:

<uses-permission android:name="android.permission.INTERNET" />
 

代码略。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: