Android入门05 -- 数据存储

  • Android的数据存储方式有:SharedPreferences,File,SQLite,下面来详细介绍每种数据存储的特点与使用;

SharedPreferences

  • SharedPreferences是Android平台上一个轻量级的数据存储辅助类,用来保存应用的一些常用配置,它提供了string,set,int,long,float,boolean六种数据类型,最终数据是以xml形式进行存储,在应用中通常做一些简单数据的持久化缓存
SharedPreferences的使用注意事项:
  • 不要存放大的key和value在SharedPreferences中,否则会一直存储在内存中得不到释放,内存使用过高会频发引发GC,导致界面丢帧甚至ANR;
  • 不相关的配置选项最好不要放在一起,单个文件越大读取速度则越慢;
  • 读取频繁的key和不频繁的key尽量不要放在一起(如果整个文件本身就较小则忽略,为了这点性能添加维护得不偿失);
  • 不要每次都edit,因为每次都会创建一个新的EditorImpl对象,最好是批量处理统一提交,否则edit().commit每次创建一个EditorImpl对象并且进行一次IO操作,严重影响性能;
  • commit发生在UI线程中apply发生在工作线程中,对于数据的提交最好是批量操作统一提交,虽然apply发生在工作线程(不会因为IO阻塞UI线程)但是如果添加任务较多也有可能带来其他严重后果(参照ActivityThread源码中handleStopActivity方法实现)
  • 尽量不要存放json和html,这种可以直接文件缓存;
  • SharedPreferences不能跨进程通信 Context.PROCESS
  • 最好提前初始化SharedPreferences,避免第一次创建时读取文件线程未结束而出现等待情况;
SharedPreferences的创建
  • 创建SharedPreferences有两种方式:
    • 第一种:调用Context对象的getSharedPreferences()方法;
    • 第二种:调用Activity对象的getPreferences()方法;
  • 区别在于:第一种方式获得的可以被同一应用程序下的组件共用,但是第二种方式获得的只可以在该Activity下使用
SharedPreferences的操作模式
  • MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下写入的内容会覆盖原文件的内容;
  • MODE_APPEND:检查文件是否存在,存在就往文件追加内容,否则就创建新文件;
  • MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
  • MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入;
SharedPreferences的增删改查
  • 封装成单例类SFSharedPreferences,代码实现如下:
package com.example.yyshop.general.database;

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

import static android.content.Context.MODE_PRIVATE;

public class SFSharedPreferences {

    private static volatile SFSharedPreferences mInstance;
    private SharedPreferences sharedPreferences;
    private SharedPreferences.Editor editor;

    public static synchronized SFSharedPreferences getInstance(Context context){
        if (mInstance == null) {
            synchronized (SFSharedPreferences.class) {
                if (mInstance == null) {
                    mInstance = new SFSharedPreferences(context);
                }
            }
        }
        return mInstance;
    }

    private SFSharedPreferences(Context context){
        if (sharedPreferences == null) {
            //创建SharedPreferences实例对象
            sharedPreferences = context.getSharedPreferences("config",MODE_PRIVATE);
            editor = sharedPreferences.edit();
        }
    }

    //存储数据
    public void save(String key,String data) {
        editor.putString(key,data);
        editor.commit();
    }

    //读取数据
    public String read(String key){
        String data = sharedPreferences.getString(key,"");
        return data;
    }

    //删除数据
    public void remove(String key) {
        editor.remove(key);
        editor.commit();
    }

    //清空所有数据
    public void clear() {
        editor.clear();
        editor.commit();
    }
}
  • 注意⚠️:SharedPreferences在存储,删除,清空数据时,都是通过editor对象进行操作的,且必须调用editor.commit(),进行提交操作才能生效;
  • 外界调用代码如下:
public class SFShopCarFragment extends SFBaseFragment {
    @Override
    protected void initUI() {
        Button button = find(R.id.shopcar_button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), SFShopDetailActivity.class);
                startActivity(intent);

                SFSharedPreferences.getInstance(getContext()).save("name","yanzi");
                String name = SFSharedPreferences.getInstance(getActivity()).read("name");
                Log.i("SFShopCarFragment",name);
            }
        });
    }

    @Override
    protected int getLayoutId() {
        return R.layout.fragment_shopcar;
    }
}
  • SharedPreferences存储数据的位置为:/data/data/项目包/shared_prefs/名称.xml,可通过Device File Explore进行查看,如下所示:
    image.png

SQLite数据库

  • SQLite是一款轻量型数据库,广泛使用于移动端;
  • 在Android中,系统封装了一个SQLite数据库的抽象类SQLiteOpenHelper,我们需要自定义一个子类继承自抽象类SQLiteOpenHelper,实现其相关的抽象方法,然后进行数据库的增删改查操作;
抽象类SQLiteOpenHelper的两个抽象方法
  • 第一个抽象方法是:onCreate方法,在实例化继承自SQLiteOpenHelper的子类时调用(创建数据库时),在这个方法中我们可进行数据库表的创建,此方法只会调用一次;
  • 第二个抽象方法是:onUpgrade方法,在数据库升级时使用;
  • 有关数据库的增删改查操作,见如下代码:
package com.example.yyshop.general.database;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.example.yyshop.home.model.SFGoodModel;
import java.util.ArrayList;
import java.util.List;

public class SFSQLShopCarHelper extends SQLiteOpenHelper {

    //数据库版本号
    private static Integer Version = 1;

    //数据库的名称
    private static final String DATA_BASE_NAME = "shopcar.db";

    //购物车商品表
    private static final String SHOP_CAR_TABLE_NAME = "t_goods";

    //单例对象
    private static volatile SFSQLShopCarHelper mInstance;

    //在SQLiteOpenHelper的子类当中,必须有该构造函数
    private SFSQLShopCarHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        //必须通过super调用父类当中的构造函数
        super(context, name, factory, version);
    }

    private SFSQLShopCarHelper(Context context, String name, int version) {
        this(context,name,null,version);
    }

    private SFSQLShopCarHelper(Context context, String name) {
        this(context, name, Version);
    }

    private SFSQLShopCarHelper(Context context) {
        this(context,DATA_BASE_NAME);
    }

    public static synchronized SFSQLShopCarHelper getInstance(Context context) {
        if (mInstance == null) {
            synchronized (SFSharedPreferences.class) {
                if (mInstance == null) {
                    mInstance = new SFSQLShopCarHelper(context);
                }
            }
        }
        return mInstance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i("SFSQLShopCarHelper","开始创建数据库表 t_shopCar");
        createTable(db);
        Log.i("SFSQLShopCarHelper","完成创建数据库表 t_shopCar");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //数据库升级

    }

    //创建表
    private void createTable(SQLiteDatabase database){
        String create_shop_car_goods = "create table if not exists " + SHOP_CAR_TABLE_NAME +"(id integer primary key autoincrement,goodId text,goodName text,goodPic text,goodPrice text)";
        try {
            database.execSQL(create_shop_car_goods);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i("SFSQLShopCarHelper", "创表shop_car_goods -- 出现异常");
        };
    }

    //插入单条数据
    public void insert(SFGoodModel model){
        SQLiteDatabase database = getWritableDatabase();

        String goodId = model.getGoodsId();
        String goodName = model.getGoodsName();
        String goodPic = model.getComPic();
        String goodPrice = model.getPrice();

        String insert = "insert into " + SHOP_CAR_TABLE_NAME + "(goodId,goodName,goodPic,goodPrice)values" + "('"+goodId+"','"+goodName+"','"+goodPic+"','"+goodPrice+"')";
        database.execSQL(insert);
        Log.i("SFShopCarFragment",insert);
        Log.i("SFShopCarFragment","插入了1条数据");
        database.close();
    }

    //查询所有商品
    public List<SFGoodModel> select(){
        SQLiteDatabase database = getReadableDatabase();
        List<SFGoodModel> models = new ArrayList<>();

        String select = "select * from " + SHOP_CAR_TABLE_NAME;
        Cursor cursor = database.rawQuery(select,null);

        while (cursor.moveToNext()) {
            String id = cursor.getString(cursor.getColumnIndex("id"));
            String goodName = cursor.getString(cursor.getColumnIndex("goodName"));
            String goodId = cursor.getString(cursor.getColumnIndex("goodId"));
            String goodPic = cursor.getString(cursor.getColumnIndex("goodPic"));
            String goodPrice = cursor.getString(cursor.getColumnIndex("goodPrice"));

            SFGoodModel model = new SFGoodModel();
            model.setGoodsId(goodId);
            model.setGoodsName(goodName);
            model.setGoodsId(goodPic);
            model.setGoodsId(goodPrice);
            models.add(model);
            Log.i("SFShopCarFragment", id + " " + goodName + " " + goodId + " " + goodPic + " " + goodPrice);
        }
        //关闭数据库
        cursor.close();
        database.close();
        return models;
    }

    //删除指定商品
    public void delete(SFGoodModel model) {
        SQLiteDatabase database = getReadableDatabase();
        String delete = "delete from " + SHOP_CAR_TABLE_NAME + " where goodid = '"+model.getGoodsId()+"'";
        try {
            database.execSQL(delete);
            Log.i("SFSQLShopCarHelper","成功删除一条数据");
            database.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.i("SFSQLShopCarHelper", "删除指定数据 -- 出现异常");
            database.close();
        }
    }

    //删除所有商品
    public void deleteAll(){
        SQLiteDatabase database = getReadableDatabase();
        String delete = "delete from " + SHOP_CAR_TABLE_NAME;
        try {
            database.execSQL(delete);
            Log.i("SFSQLShopCarHelper","成功删除所有数据");
            database.close();
        } catch (Exception e) {
            e.printStackTrace();
            Log.i("SFSQLShopCarHelper", "删除所有数据 -- 出现异常");
            database.close();
        }
    }
}
  • 上述自定义子类SFSQLShopCarHelper继承自SQLiteOpenHelper系统抽象类;
  • 在进行数据库的增删改查时,首先是获取database,调用getReadableDatabase()或者getWritableDatabase()方法,相当于打开数据库,在执行完数据库的增删改查操作之后,调用close()方法,关闭数据库;

推荐阅读更多精彩内容