安卓的五种存储方式

本文详细介绍了安卓的三种主要存储方式:SharedPreferences用于轻量级配置存储,SQLite用于数据库操作,包括增删改查,文件存储则分为内部存储和外部存储(SD卡)。文章详细阐述了每种存储方式的使用场景、操作步骤和注意事项,包括自定义帮助类和实际操作示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

安卓的存储方式有5种,分别为:

  1. SharedPrefences;
  2. SQLite数据库
  3. 文件存储
  4.  网络存储
  5.  ContentProvider

思维导图

 1. 数据存储的类型和存放位置

应用程序一般有一下几种类型:

file-普通的文件存储
database-数据库文件(.db文件)
sharedPreference-配置数据(.xml文件)
cache-图片缓存文件

应用数据的存放位置:

com.xxx.xxx 为自定义的包名

/data/data/com.xxx.xxx/cache - 应用内缓存(注:对应方法getCacheDir())
/data/data/com.xxx.xxx/databases - 应用内数据库
/data/data/com.xxx.xxx/shared_prefs - 应用内配置文件
/data/data/com.xxx.xxx/files - 应用内文件(注:对应方法getFilesDir())
SD卡的文件(开发者自定义的)

 

2. SharedPreferences存储数据

1)使用范围

Android 提供了一个轻量级的存储类 SharedPreferences使用 XML 格式保存一些键值对数据

当我们的应用想要保存用户的一些偏好参数,比如是否自动登陆,是否记住账号密码,是否在 Wifi 下才能 联网等相关信息,我们这些信息为用户的偏好 设置

 

2)SharedPrefences 的使用步骤

  1. 首先实例化一个 SharedPreferences 对象

    SharedPreferences sp = mContext.getSharedPreferences("filename", Context.MODE_PRIVATE);
    
    1. mContext 就是上下文,如果在 Activity 可以使用 Activity.this 或者 getApplicationContext() 方法获得

    2. filename 就是要保存的文件名,不要加上 .xml 扩展名,因为系统自己会加上

    3. Context.MODE_PRIVATE 私有的文件模式,一般都用 Context.MODE_PRIVATE

  2. 调用 sp.edit() 获取 sp 对象的写编辑器

    SharedPreferences.Editor editor = sp.edit();
    
  3. 调用 editor.putXxxx() 写数据操作 , Xxx 表示类型

    editor.putString("username","imyufei")
    
  4. 调用 editor.commit() 提交和保存数据

  5. 调用 sp.getXxxx() 去处 Xxx 类型的数据

  6. 调用 sp.remove(key) 可以删除 key 对应的数据

其中文件读取的模式有4种, 其中2 种是废弃的:

模式说明
Context.MODE_PRIVATE默认的操作模式,表示该文件是私有文件,只能够被应用本身访问,写入的内容会覆盖原有的数据
Context.MODE_APPEND会检查文件是否存在,如果存在则把内容追加到文件末尾,否则新建一个文件进行写
Context.MODE_WORLD_READABLE 废弃当前文件可以被其它 APP 读取
Context.MODE_WORLD_WRITEABLE废弃当前文件可以被其它 APP 写入

这些模式可以使用 竖线(|) 叠加,比如

openFileOutput("site.txt",Context.MODE_WORLD_READABLE|MODE_WORLD_WRITEABLE)

Editor有如下主要重要方法:

  1.                 SharedPreferences.Editor clear():清空SharedPreferences里所有数据
  2.                 SharedPreferences.Editor putXxx(String key , xxxvalue): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据
  3.                 SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项
  4.                 boolean commit(): 当Editor编辑完成后,使用该方法提交修改

 

3)具体实现例子

1. 自定义一个帮助读取的类

package com.example.newdemo.storagefile;

import android.content.Context;
import android.content.SharedPreferences;

public class SharedPrehelper {

    private Context context;

    public SharedPrehelper(Context context){
        this.context = context;
    }

    public void save(String key, String value){
        // 实例化一个 sp 对象
        SharedPreferences sharedPreferences = context.getSharedPreferences("my_sp", Context.MODE_PRIVATE);

        // 调用 sp.edit() 获取 sp 对象的写编辑器
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putString(key, value);
        editor.commit();
    }

    // 获取数据
    public String read(String key){
        SharedPreferences sharedPreferences = context.getSharedPreferences("my_sp", Context.MODE_PRIVATE);
        return sharedPreferences.getString(key, "");
    }

}

2. 设置主activity

package com.example.newdemo.storagefile;

import androidx.appcompat.app.AppCompatActivity;

import android.app.backup.SharedPreferencesBackupHelper;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.newdemo.R;
import com.example.newdemo.util.ToastManager;

public class SharedPreferencesActivity extends AppCompatActivity {

    private Button btn_sp;
    private EditText sp_edit;
    private Context context;
    private SharedPrehelper sharedPrehelper;
    private TextView sp_textview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shared_preferences);

        btn_sp = findViewById(R.id.btn_sp);
        sp_edit = findViewById(R.id.sp_edit);
        sp_textview = findViewById(R.id.sp_textview);
        context = getApplicationContext();
        sharedPrehelper = new SharedPrehelper(context);

        // 保存输入的数据
        btn_sp.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                String value = sp_edit.getText().toString();
                sharedPrehelper.save("name", value);
                ToastManager.showMsg(context, "数据已经保存了---");
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 获取
        String value = sharedPrehelper.read("name");
        sp_textview.setText(value);
        ToastManager.showMsg(context, "textView 在显示--");
    }
}

 

找到保存的文件:

在  /data/data/com.xxx.xxx/shared_prefs - 应用内配置文件

Android 4.2 以后已经不能读取其它 APP 的 SharedPreference,如需要读取其他app 文件,需使用ContentProvider

 

4)自定义一个帮助类

SharedPreference 都要自行实例化 SharedPreference 相关的类,会比较麻烦

import android.content.Context;
import android.content.SharedPreferences;

import java.util.Map;

public class SPHelper {
    /**
     * 保存在手机里的SP文件名
     */
    private String FILE_NAME;

    public SPHelper(String FILE_NAME){
        this.FILE_NAME= FILE_NAME;        
}


    /**
     * 保存数据
     */
    public static void put(Context context, String key, Object obj) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        if (obj instanceof Boolean) {
            editor.putBoolean(key, (Boolean) obj);
        } else if (obj instanceof Float) {
            editor.putFloat(key, (Float) obj);
        } else if (obj instanceof Integer) {
            editor.putInt(key, (Integer) obj);
        } else if (obj instanceof Long) {
            editor.putLong(key, (Long) obj);
        } else {
            editor.putString(key, (String) obj);
        }
        editor.commit();
    }


    /**
     * 获取指定数据
     */
    public static Object get(Context context, String key, Object defaultObj) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        if (defaultObj instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObj);
        } else if (defaultObj instanceof Float) {
            return sp.getFloat(key, (Float) defaultObj);
        } else if (defaultObj instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObj);
        } else if (defaultObj instanceof Long) {
            return sp.getLong(key, (Long) defaultObj);
        } else if (defaultObj instanceof String) {
            return sp.getString(key, (String) defaultObj);
        }
        return null;
    }

    /**
     * 删除指定数据
     */
    public static void remove(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        editor.commit();
    }


    /**
     * 返回所有键值对
     */
    public static Map<String, ?> getAll(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        Map<String, ?> map = sp.getAll();
        return map;
    }

    /**
     * 删除所有数据
     */
    public static void clear(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.commit();
    }

    /**
     * 检查key对应的数据是否存在
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        return sp.contains(key);
    }

}

3. SQLite存储数据

SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧

创建一个帮助类

public class MsDBOpenHelper extends SQLiteOpenHelper {

    public MsDBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
            int version) {super(context, name, factory, version); }

    @Override
    //数据库第一次创建时被调用
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE lang(id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(64))");

    }
    //软件版本号发生改变时调用
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

数据库的增删改查的例子实现:

xml文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".storagefile.SharedPreferencesActivity">


    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入编程语言"
        android:id="@+id/sql_edit"/>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入需要删除的id"
        android:id="@+id/sql_id"/>

    <LinearLayout
        android:layout_width="wrap_content"
        android:orientation="horizontal"
        android:layout_gravity="center"
        android:layout_height="wrap_content">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="插入"
            android:id="@+id/sql_insert"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="查询"
            android:id="@+id/sql_query"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="修改"
            android:id="@+id/sql_modify"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="删除"
            android:id="@+id/sql_delete"/>

    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="操作结果"
        android:id="@+id/sp_result"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/sp_resultshow"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="输出表的数据: "
        android:id="@+id/sp_data"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/sp_datashow"/>

</LinearLayout>

java代码实现 

package com.example.newdemo.storagefile;


import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.example.newdemo.R;
import com.example.newdemo.util.ToastManager;

public class SqliteActivity extends AppCompatActivity implements View.OnClickListener{

    private Button sql_insert;
    private Button sql_query;
    private Button sql_modify;
    private Button sql_delete;
    private EditText sql_edit;
    private EditText sql_id;
    private TextView sp_resultshow;
    private TextView sp_datashow;

    private SQLiteDatabase db;
    private MyDBopenHelper myDBopenHelper;
    private StringBuilder sb;
    private Context context;
    private int i = 1;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shared_preferences);

        context = SqliteActivity.this;
        myDBopenHelper = new MyDBopenHelper(context, "my_database.db", null, 1);
        bindView();
        queryAll();

    }

    @Override
    public void onClick(View v) {
        db = myDBopenHelper.getWritableDatabase();
        switch(v.getId()){
            // 插入数据
            case R.id.sql_insert:
                ContentValues value = new ContentValues();
                value.put("name", sql_edit.getText().toString());
                db.insert("lang", null, value);
                sp_resultshow.setText("插入成功");
                ToastManager.showMsg(context, "插入数据---");
                break;
            case R.id.sql_delete:
                // 依据id 进行删除
                db.delete("lang", "id = ?", new String[]{sql_id.getText().toString()});
                sp_resultshow.setText("删除成功");
                ToastManager.showMsg(context, "删除数据---");
                break;
            case R.id.sql_query:
                // 依据id 进行查询
                sb = new StringBuilder();
                Cursor cursor = db.query("lang", null, "id = ?",
                        new String[]{sql_id.getText().toString()}, null, null, null);
                if (cursor.moveToFirst()){
                    do{
                        int pid = cursor.getInt(cursor.getColumnIndex("id"));
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        sb.append("id " + pid + ": " + name +'\n');
                    }while (cursor.moveToNext());
                }
                cursor.close();
                sp_datashow.setText(sb.toString());
                break;
            case R.id.sql_modify:
                ContentValues contentValues = new ContentValues();
                // 将更新的数据保存
                contentValues.put("name", sql_edit.getText().toString());
                // 更新id 值
                db.update("lang", contentValues, "id = ?", new String[]{sql_id.getText().toString()});
                sp_resultshow.setText("更新成功");
                break;
        }
        queryAll();
    }

    // 查询数据库里所有的数据
    public void queryAll(){
        db = myDBopenHelper.getWritableDatabase(); // 获取数据库
        sb = new StringBuilder();

        Cursor cursor = db.query("lang", null, null, null, null, null, null);
        if (cursor.moveToFirst()){
            do {
                int pid = cursor.getInt(cursor.getColumnIndex("id"));
                String name = cursor.getString(cursor.getColumnIndex("name"));
                sb.append("id " + pid + ": " + name +'\n');
            }while (cursor.moveToNext());
        }
        cursor.close();
        sp_datashow.setText(sb.toString());
    }

    public void bindView(){
        sql_insert = findViewById(R.id.sql_insert);
        sql_query = findViewById(R.id.sql_query);
        sql_modify = findViewById(R.id.sql_modify);
        sql_delete = findViewById(R.id.sql_delete);
        sp_resultshow = findViewById(R.id.sp_resultshow);
        sp_datashow = findViewById(R.id.sp_datashow);
        sql_edit = findViewById(R.id.sql_edit);
        sql_id = findViewById(R.id.sql_id);

        sql_insert.setOnClickListener(this);
        sql_query.setOnClickListener(this);
        sql_modify.setOnClickListener(this);
        sql_delete.setOnClickListener(this);
    }
}
 

1)增加数据

insert()方法,参数一表名,参数二是在未指定添加数据的情况下给某些可为空的列自动赋值为NULL,设置为null即可,参数三是ContentValues对象。

SQLiteDatabase db = myDBopenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name","The Book Name");
values.put("author","chen");
values.put("pages",100);
values.put("price",200);
db.insert("Book",null,values);

2)删除数据

delete()方法,参数一是表名,参数二、三是去约束删除某一行或某几行的数据,不指定默认删除所有

SQLiteDatabase db = myDBopenHelper.getWritableDatabase();
db.delete("Book","pages> ?",new String[]{"100"});

或者直接使用sql语法

String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句

db.execSQL(sql);//执行删除操作

 

3)修改数据

update()方法,参数一是表名,参数二是ContentValues对象,参数三、四是去约束更新某一行或某几行的数据,不指定默认更新所有。

SQLiteDatabase db = myDBopenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("price",120);
db.update("Book",values,"name= ?",new String[]{"The Book Name"});

4)查找数据

query()方法,参数一是表名,参数二是指定查询哪几列,默认全部,参数三、四是去约束查询某一行或某几行的数据,不指定默认查询所有,参数五是用于指定需要去group by的列,参数六是对group by的数据进一步的过滤,参数七是查询结果的排序方式

SQLiteDatabase db = myDBopenHelper.getWritableDatabase();
Cursor cursor = db.query("Book",null,null,null,null,null,null);
if(cursor.moveToFirst()){
      do{
            String name = cursor.getString(cursor.getColumnIndex("name");
            String author = cursor.getString(cursor.getColumnIndex("author");
            int pages = cursor.getString(cursor.getColumnIndex("pages");
            double price = cursor.getString(cursor.getColumnIndex("price");
       }while(cursor.moveToNext());
}
cursor.close():

5)使用SQL语句操作数据库

//添加数据
db.execSQL("insert into Book(name,author,pages,price) values(?,?,?,?) "
            ,new String[]{"The Book Name","chen",100,20});
//更新数据
db.execSQL("update Book set price = ? where name = ?",new String[]
            {"10","The Book Name"});
//删除数据
db.execSQL("delete from Book where pages > ?",new String[]{"100"});
//查询数据
db.execSQL("select * from Book",null);

4.文件存储

文件存储是 Android 中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动的保存到文件当中的。它比较适合用于存储一些简单的文本数据或二进制数据。如果你想使用文件存储方式来保存一些较为复杂的文本数据,就需要定义一套自己的格式规范,方便于之后将文件重新解析出来。

1)内部存储

注意内部存储不是内存。内部存储位于系统中很特殊的一个位置,如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。

内部存储的写入步骤:

第一, 获取文件输出流对象 FileOutputStream

第二, 使用FileOutputStream类的openFileOutput(String name, int mode)方法

第三, 调用FileOutputStream对象的write()方法写入文件

第四, 调用flush()方法,因为write()方法是写入缓冲区的,调用flush()方法将缓冲中的数据写入到文件,清空缓存

第五, close()方法用于关闭FileOutputStream

 

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try{
    outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
    outputStream.write(string.getBytes());
    outputStream.close();

    } catch(Exception e) {
        e.printStackTrace();
    }

一些方法: 

  • getFileDir() 方法得到的是该目录下 files 文件夹的 File 对象
  • getChacheDir() 方法得到的是该目录下 cache 文件夹的 File 对象
  • 直接调用ContextWrapper的 openFileOutput(String name,int mode) 也会在该目录下 files 文件夹下创建相应的文件,并且是私密的。可以修改为其他应用可访问的,通过 openFileOutput 方法的 mode 参数来完成

 

2)外部存储(SD卡)

外部内存的读取步骤:

1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录

3、使用IO流操作SD卡上的文件

注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡
必须在AndroidManifest.xml上配置读写SD卡的权限

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

文件写操作函数

    private void write(String content) {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
            File file = new File(Environment.getExternalStorageDirectory()
                    .toString()
                    + File.separator
                    + DIR
                    + File.separator
                    + FILENAME); // 定义File类对象
            if (!file.getParentFile().exists()) { // 父文件夹不存在
                file.getParentFile().mkdirs(); // 创建文件夹
            }
            PrintStream out = null; // 打印流对象用于输出
            try {
                out = new PrintStream(new FileOutputStream(file, true)); // 追加文件
                out.println(content);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    out.close(); // 关闭打印流
                }
            }
        } else { // SDCard不存在,使用Toast提示用户
            Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show();
        }
    }

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值