【安卓开发】数据存储

读书笔记系列:第一行代码 Android

6.1 持久化技术简介

三种数据持久化方式:文件存储、SharedPreference存储以及数据库存储,除此之外还可以存储在SD卡中(不安全)

6.2 文件存储

该方法不对存储的内容做格式化处理都是直接保存到文件中,所以适合存一些简单的文本数据或二进制数据,要想存复杂文本数据,就需要自己定义格式规范方便解析。

6.2.1 将数据存储到文件中

Context类中有一个openFileOutput方法,可将数据保存到指定文件中,需要两个参数,第一个是文件名(文件名不包含路径,所有都默认存在/data/data/<packagename>/files/目录下),第二个参数是文件的操作模式,MODE_PRIVATE和MODE_APPEND,一个是覆盖一个是追加。
openFileOutput()方法返回的是FileOutputStream对象,得到这个对象后就可以使用JAVA方式将数据写入到文件中了,以下是一段简单的示例:

public void save(){
        String data = "data to save";
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try{
            out = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null){
                    writer.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

一个保存下来输入值的具体案例

public class MainActivity extends AppCompatActivity {
    private EditText edit;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edit = (EditText) findViewById(R.id.edit);
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        String inputText = edit.getText().toString();
        save(inputText);
    }

    public void save(String inputText){
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try{
            out = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(inputText);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null){
                    writer.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

从文件中读取数据

Context类中还有一个OpenFileInput()方法,可以从文件中读取数据,它只接收文件名参数并返回FileInputStream对象,得到这个对象后就可以用JAVA流的方式读取出来数据了
以下是一段读文本数据的示例:

public String load(){
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try{
            in = openFileInput("data");
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            while((line = reader.readLine()) != null){
                content.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null){
                try{
                    reader.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
        return content.toString();
    }

onCreate()方法中调用 load()方法来读取文件中存储的文本内容,如果读到的内容不为null,就调用EditText的setText()方法将内容填充到EditText里,并调用setSelection()方法将输入光标移动到文本的末尾位置以便于继续输人,然后弹出一句还原成功的提示。
注意,上述代码在对字符串进行非空判断的时候使用了 Textutils.isEmpty()方法,它可以一次性进行两种空值的判断。当传入的字符串等于 null 或者等于空字符串的时候,这个方法都会返回 true,就不用再分别单独判断了。

SharedPreferences存储

该方式使用键值对存储数据,并且存的数据是整数的话读的数据也是,存的是字符串的话,读的也是字符串。

将数据存到SharedPreferences中

安卓中有三种方法获取SharedPreferences对象

  1. Context类中的getSharedPreferences方法:该方法接收两个参数(文件名、工作模式),该方法的文件都是在/data/data/<package name>/shared_prefs/目录下。第二个参数只有 MODE_PRIVATE 这一个模式可以选,默认(0),表示只有当前app才能对文件读写。
  2. Activity类中的 getPreferences() 方法:与上一个类似,但只有一个参数,因为该类会自动将当前活动类作为文件名。
  3. PreferenceManager 类中的 getDefaultSharedPreferences() 方法:这是个静态方法,接收一个Context参数,并自动使用当前应用程序的包名作为前缀来命名 SharedPreferences 文件。存储数据主要分三步:(1)调用 SharedPreferences 对象的 edit()方法,返回一个 SharedPreferences.Editor对象 (2)向其中添加数据,如布尔型则putBoolean(), 字符串则 putString(), 以此类推 (3)调用apply()方法数据提交【整个流程挺容易理解的 安全性 也类似于数据库】
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button saveData = (Button) findViewById(R.id.save_data);
        saveData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();
                editor.putString("name", "tom");
                editor.putInt("age", 28);
                editor.putBoolean("married", false);
                editor.apply();
            }
        });
    }
}

//下面是加了个按钮来触发
<Button
        android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/save_data"
                android:text="Save data"/>

保存的文件是xml格式的,可知SharedPreferences使用xml格式进行管理。

6.3.2 从SharedPreferences中读数据

直接使用getInt()等类似的get函数即可,接收一个参数,第二个参数默认值(找不到的话返回什么)。

Button restoreData = (Button) findViewById(R.id.restore_data);
        restoreData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);
                String name = pref.getString("name", "");
                int age = pref.getInt("age", 0);
                boolean married = pref.getBoolean("married", false);
                Log.d("MainActivity", "name is" + name);
            }
        });

输出结果

6.3.3 实现记住密码功能

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

        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/remember_pass"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Remember password"
            android:textSize="18sp"/>
    </LinearLayout>

checkbox是个复选框

public class MainActivity extends AppCompatActivity {
    private SharedPreferences pref;
    private SharedPreferences.Editor editor;
    private EditText accountEdit;
    private EditText passwordEdit;
    private Button login;

    private CheckBox rememberPass;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        pref = PreferenceManager.getDefaultSharedPreferences(this);
        accountEdit = (EditText) findViewById(R.id.account);
        passwordEdit = (EditText) findViewById(R.id.password);
        rememberPass = (CheckBox) findViewById(R.id.remember_pass);
        login = (Button) findViewById(R.id.login);
        
        boolean isRemember = pref.getBoolean("remember_password", false);
        if(isRemember){
            // 将账号和密码都设置到文本框中
            String account = pref.getString("account", "");
            String password = pref.getString("password", "");
            accountEdit.setText(account);
            passwordEdit.setText(password);
            rememberPass.setChecked(true);
        }
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String account = accountEdit.getText().toString();
                String password = passwordEdit.getText().toString();
                //如果账号密码对就登录成功
                if(account.equals("admin") && password.equals("13123")){
                    editor = pref.edit();
                    if(rememberPass.isChecked()){ //检查复选框是否被选中
                        editor.putBoolean("remember_password", true);
                        editor.putString("account", account);
                        editor.putString("password", password);
                    }else{
                        editor.clear();
                    }
                    editor.apply();
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();;
                }else{
                    Toast.makeText(LoginActivity.this, "feifamima", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

6.4 SQLite数据库存储

6.4.1 创建数据库

安卓提供了抽象类 SQLiteOpenHelper 管理数据库,要使用它就需要自己创建类继承它。其中有两个抽象函数 onCreate() 和 onUpgrade() ,我们要重写这两个方法。
除此之外,getReadableDatabase() 和 getWritableDatabase(),都可以创建或打开一个现有数据库,并返回一个可对数据库读写的对象,不同的是,数据库不可写入时,getReadableDatabase() 方法将以只读方式打开,而另一个则抛出异常。
SQLiteOpenHelper 类的构造函数有两个,其中一个接收4个参数(常用),Context、数据库名、第三个参数允许在查询时返回我们自定义的Cursor,一般传入null。最后一个是版本号。数据库文件会存放在 /data/data/<package name>/database/ 目录下,此时,重写的 onCreate 方法也会得到执行,所以通常在其中加创建表的逻辑。

public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table Book ("
            + "id integer primary key autoincrement, "
            + "author text,"
            + "price real,"
            + "pages integer,"
            + "name text)";

    private Context mContext;

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

    @Override
    public void onCreate(SQLiteDatabase db){
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext, "create success", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){

    }
}

建一个类,之后再main中测试

public class MainActivity extends AppCompatActivity {

    private MyDatabaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dbHelper.getWritableDatabase();
            }
        });
    }
}

数据库

6.4.2 升级数据库

上面代码中可以看到 MyDatabaseHelper 中还有个空方法 onUpgrade() 这个函数用于对数据库升级。
如果我们再在onCreate函数中添加一个数据库执行语句,这条语句将不会执行,我们之前说到过只在数据库创建时才会执行其中代码,那么要想实现新建表、修改表等操作,该怎么办呢?
我们可以在 SQLiteOpenHelper 的第四个参数中输入一个比1大的值,就可以让它执行 onUpgrade() 函数了。

dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 1);

修改 onUpgrade() 函数如下:

@Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }

其中先删除了表,又创建了表。

6.4.3 添加数据

SQLiteDatabase 中提供了 insert() 函数可以插入数据,它接收3个参数,第一个是表名,第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL,一般用不到,直接传null。第三个是一个 ContentValues 对象,提供了一系列 put() 方法重载,用于向 ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。

Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 开始组装第一条数据
                values.put("name", "The dasdad");
                values.put("author", "dasdad");
                values.put("pages", 3213);
                values.put("price", 3213);
                db.insert("Book", null, values); // 插入第一条数据
                values.clear();
                // 组装第二条数据
                values.put("name", "dasdad");
                // 等等等
                db.insert("Book", null, values); // 插入第二条数据
            }
        });

6.4.4 更新数据

updata() 方法 和 insert() 方法类似,接收4个参数,第一个参数是表名,第二个是 ContentValues 对象(组装更新数据),第三、四个参数用于约束更新某一行或者某几行的数据,不指定的话就是更新所有行。

Button updateData = (Button) findViewById(R.id.Update_data);
        updateData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", 10.99);
                db.update("Book", values, "name = ?", new String[]{"the da Vinci code"})
            }
        });

这里第三个参数对应的是SQL中的where语句,表示更新所有name等于?的行,?使一个占位符,可以通过第四个参数的字符串为第三个参数的每个占位符指定相应的内容,则上述代码含义是更新“the da Vinci code”价格为10.99.

6.4.5 删除数据

delete() 三个参数:表名,第二三个参数用于约束删除某一行或某几行数据,不指定则删除所有行。

db.delete("Book", "pages > ?", new String[]{"500"});

6.4.6 查询数据

query()需要七个参数(不全要)
参数列表

Button queryData = (Button) findViewById(R.id.query_data);
        queryData.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 查询表中的所有数据
                Cursor cursor = db.query("Book", null, null, null, null, null, null);
                if(cursor.moveToFirst()){
                    do {
                        // 遍历Cursor对象,取出数据并打印
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int page = cursor.getInt(cursor.getColumnIndex("pages"));
                    }while(cursor.moveToNext());
                }
                cursor.close();
            }
        });

6.5 使用 LitePal 操作数据库

在app/build.gradle中的denpendencies中添加内容

implementation 'org.litepal.guolindev:core:3.2.3'

报错解决地址
然后在,app/src/main 目录下创建assets目录,在它下面再创建 litepal.xml 文件,在文件中加入

<?xml version="1.0" encoding="utf-8" ?>
<litepal>
    <dbname value="BookStore"></dbname>
    <version value="1"></version>
    <list>
        
    </list>
</litepal>

数据库名和数据库版本,list中是指定的映射模型。最后还需配置下litepal,修改AndroidManifest文件:

 <application
<!--        添加的内容-->
        android:name="org.litepal.LitePalApplication" 
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.LitePalTest"
        tools:targetApi="31">

6.5.3 创建和升级数据库

LitePal 采用的是对象关系映射(ORM)模式(将面向对象的语言和面向关系的数据库间建立映射关系)
首先创建一个Book类

public class Book {
    private int id;
    private String author;
    private double price;
    
    public int getId(){
        return id;
    }
    
    public void setId(int id){
        this.id = id;
    }
    
    public String getAuthor(){
        return author;
    }
    
    public void setAuthor(String author){
        this.author = author;
    }
}

Book类其实就是数据库中的Book表,其中的每个字段就代表每一个列。接下来修改litepal.xml中代码:

<list>
        <mapping class="com.example.litepaltest.Book"/>
    </list>

现在只要任意执行一次数据库操作,数据库就会被创建

Button createDatabas = (Button) findViewById(R.id.create_database);
        createDatabas.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Connector.getDatabase();
            }
        });

Connector.getDatabase()方法就是一次简单的数据库操作。
如果我们想更新数据库,那么直接修改Book类中的代码,添加相应字段, 并将版本号加一即可。
添加数据
更新数据得话直接在原对象基础上set就行。
更新数据

Book book = new Book();
        book.setId(12);
        book.setAuthor("dsad");
        book.updateAll("name = ? and author = ?", "The Lost Symbol", "Dan bda");

还可以这样更新
要想将数据更改为默认值可以使用 setToDefault() 方法,ru:

// 将所有书的页数都变为0
		Book book = new Book();
        book.setToDefault("pages");
        book.updateAll();

删除数据

DataSupport.deleteAll(Book.class, "price < ?", "15");

查询语句

list<Book> books = DataSupport.findAll(Book.class);

除此之外,还有很多的api

安全视角下的数据存储

安全相关的
2
3

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
对于安卓开发中的数据存储与访问,我们可以使用SharedPreferences或SQLite数据库来实现幸运抽奖器的中奖结果记录。以下是一个简单的示例代码(仅供参考): 1. MainActivity.java ```java public class MainActivity extends AppCompatActivity { // 定义抽奖按钮 Button btnDraw; // 定义显示中奖结果的文本框 TextView tvResult; // 定义SharedPreferences对象 SharedPreferences sp; // 定义中奖结果的键值 String key = "result"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定控件 btnDraw = findViewById(R.id.btn_draw); tvResult = findViewById(R.id.tv_result); // 获取SharedPreferences对象 sp = getSharedPreferences("lottery", MODE_PRIVATE); // 设置抽奖按钮的点击事件 btnDraw.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 调用抽奖方法 String result = draw(); // 显示中奖结果 tvResult.setText(result); // 将中奖结果保存到SharedPreferences中 saveResult(result); } }); // 从SharedPreferences中获取上一次的中奖结果并显示 String lastResult = sp.getString(key, ""); if (!lastResult.isEmpty()) { tvResult.setText(lastResult); } } // 抽奖方法 private String draw() { // 定义奖品数组 String[] prizes = {"一等奖", "二等奖", "三等奖", "谢谢参与"}; // 生成随机数,模拟抽奖过程 int index = (int) (Math.random() * prizes.length); // 返回中奖结果 return prizes[index]; } // 将中奖结果保存到SharedPreferences中 private void saveResult(String result) { SharedPreferences.Editor editor = sp.edit(); editor.putString(key, result); editor.apply(); } } ``` 2. activity_main.xml ```xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/btn_draw" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="抽奖" android:layout_centerHorizontal="true" android:layout_marginTop="50dp"/> <TextView android:id="@+id/tv_result" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="抽奖结果" android:textSize="20sp" android:layout_below="@id/btn_draw" android:layout_centerHorizontal="true" android:layout_marginTop="50dp"/> </RelativeLayout> ``` 这个示例程序使用了SharedPreferences来保存中奖结果,并在每次抽奖后将中奖结果保存到SharedPreferences中。同时,程序在启动时会从SharedPreferences中获取上一次的中奖结果并显示。如果你需要更复杂的数据存储和访问功能,可以考虑使用SQLite数据库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Godams

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值