程序的终归目的还是操作数据来达到实现一些特定功能,在Android中,我们可以通过操作文件或者使用SharedPreferences还有数据库来保存一些数据。首先来看一下Android文件的读写:

假设我们现在有这么一个需求:一个Activity中有一个EditText,在每次这个程序启动的时候我们要恢复用户上一次在EditText中输入的数据。
Ok,轮到文件操作大展身手了:

新建一个Android工程:
activity_main.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

简单的布局,就不介绍了,接下来是MainActivity.java:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import android.widget.EditText;

public class MainActivity extends Activity {

    private FileOutputStream out = null;
    private BufferedWriter writer = null;
    private FileInputStream in = null;
    private BufferedReader reader = null;
    private EditText editText = null;

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

        editText = (EditText) findViewById(R.id.editText);
        String str = readText();
        editText.setText(str);
        editText.setSelection(str.length());    // 光标移至末尾继续输入
    }

    private String readText()
    {
        StringBuilder readString = new StringBuilder();
        try
        {
            String line = null;
            in = openFileInput("dataSave");
            reader = new BufferedReader(new InputStreamReader(in));
            while((line = reader.readLine()) != null)
            {
                readString.append(line);
            }
            if(reader != null)
            {
                reader.close();
            }
        }catch (IOException e)
        {
            e.printStackTrace();
        }
        String str = readString.toString();
        if(!TextUtils.isEmpty(str)) // 如果字符串不空,返回这个字符串
        {
            return str;
        }
        else 
        {
            return null;
        }
    }

    private void saveText()
    {
        String saveString = null;
        saveString = editText.getText().toString();
        try {
            out = openFileOutput("dataSave", Context.MODE_PRIVATE); 
            /*
            * 第一个参数是文件名,第二个是操作模式,目前只有两种
            * 操作模式:MODE_PRIVATE(创建的文件名已经存在时替
            * 换该文件),
            * MODE_APPEND(创建的文件名已经存在时像该文件件
            * 末尾添加数据)
            */
            writer = new BufferedWriter(new OutputStreamWriter(out));
            writer.write(saveString);
            if(writer != null)
            {
                writer.close();
            }
        } catch (IOException e){
            e.printStackTrace();
        } 
    }

    @Override 
    public void onDestroy()
    {
        super.onDestroy();
        saveText();
    }
}

在 MainActivity.java 文件中,我们定义了两个方法:saveText() 和 readText() 分别用于储存 EditText 中输入的内容和恢复 EditText 中的内容。主要是一些Java中的文件操作,如果不熟悉的话可以去网上找一些教程。在 onDestroy 方法中调用 saveText 来储存 EditText 中的数据。,在 onCreate 方法中我们进行恢复 EditText 中的数据。这里说一些 TextUtils.isEmpty(CharSequence str) 方法,一个静态方法,如果str为null或者为空字符,这个方法都会返回true。这里用来检测字符串是否为空。运行程序:

android targetSdkVersion 30永久保存文件 android文件储存_Text


刚开始什么都没有(如果你是第一次运行这个程序)

输入字符:

android targetSdkVersion 30永久保存文件 android文件储存_android数据存储_02


退出程序之后再次进入程序:

android targetSdkVersion 30永久保存文件 android文件储存_android_03


成功恢复!

前面介绍的文件操作储存数据是用文本文件或者二进制文件来储存数据的,下面介绍一个新的数据储存方式:SharedPreferences

SharedPreferences 储存的文件采用xml格式的文件来储存数据,通过“键--值“对的方式来储存,读取的时候通过“键”来读取对应的“值”。

SharedPreferences现在只有一种MODE_PRIVATE(和上面介绍的一样)操作模式。用SharedPreferences储存的文件放在 /data/data/<package name>/shared-prefs/ 目录下的,
pack name为应用程序的包名

我们有三种方式来获取SharedPreferences对象:
1、Context类的getSharedPreferences方法,此方法接收两个参数:SharedPreferences储存的文件名和操作模式。
2、Activity类中的getPreferences方法,此方法接受一个参数:操作模式(MODE_PRIVATE),储存的文件名为当前Activity对象的类名
3、PreferenceManager类中的静态方法:getDefaultSharedPreferences,此方法接收一个Context类型的参数。

得到了SharedPreferences对象之后我们就可以利用它进行数据的储存了:
(1) 调用Sharedpreferences 对象的 edit() 方法获取一个SharedPreferences.Editor 对象
(2) 使用SharedPreferences.Editor 对象的特性方法储存数据(putString()...)
(3) 调用SharedPreferences.Editor 对象的apply() 方法提交数据,完成储存。

下面通过一个简单的实例来介绍SharedPreferences:模拟账号登录过程中的记住密码问题:
新建一个Android工程:
activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TableRow 
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#00FFFF"
            android:text="用户名"/>
        <EditText 
            android:id="@+id/userNameEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="输入用户名"/>
    </TableRow>
    <TableRow 
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#FF00FF"
            android:text="  密码  "/>
        <EditText 
            android:id="@+id/passwordEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:password="true"
            android:layout_weight="1"
            android:hint="输入密码"/>
    </TableRow>
    <CheckBox 
        android:id="@+id/savePasswordsCheckBox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="记住密码"
        android:checked="false" />
    <TableRow 
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
        <Button 
            android:id="@+id/registerButton"
            android:layout_weight="1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="注册"
            android:background="#FFAAFF"/>
        <Button 
            android:id="@+id/loginButton"
            android:layout_weight="1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#AADDFF"
            android:text="登录"/>
    </TableRow>

</TableLayout>

布局文件采用TableLayout布局方式,TableLayout很适合设计账号登录界面,主要的布局逻辑并不难,一行账号输入,一行密码输入,一行单选框,用于判断是否记住密码,还有一行就是登录和注册按钮。
MainActivity.java:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;

public class MainActivity extends Activity {

    private Button button = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login_activity);

        loadUserInfo();
        button = (Button) findViewById(R.id.loginButton);
        button.setOnClickListener(listener);

    }

    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch(v.getId())
            {
            case R.id.loginButton:
                login();
                break;
            }
        }
    };

    @SuppressLint("NewApi")
    private void login() // 单击登录按钮事件
    {
        CheckBox checkBox = (CheckBox) findViewById(R.id.savePasswordsCheckBox);

        SharedPreferences.Editor editor = getSharedPreferences("userInfo", Context.MODE_PRIVATE).edit();// 获取 Sharedpreferences.Editor 对象
        editor.putString("userName", ((EditText) findViewById(R.id.userNameEditText)).getText().toString());
        if(checkBox.isChecked()) 
        {
            editor.putString("passwords", ((EditText) findViewById(R.id.passwordEditText)).getText().toString()); // 如果选中记住密码单选框就储存密码
        }
        editor.apply(); // 上传数据
        Toast.makeText(this, "单击登录按钮", Toast.LENGTH_SHORT).show();
    }

    private void loadUserInfo()
    {
        SharedPreferences preferences = getSharedPreferences("userInfo", Context.MODE_PRIVATE);
        String userName = preferences.getString("userName", ""); // 第一个参数是“键”,第二个参数是如果数据不存在默认的返回数据
        String passwords = preferences.getString("passwords", "");
        ((EditText) findViewById(R.id.userNameEditText)).setText(userName);
        ((EditText) findViewById(R.id.passwordEditText)).setText(passwords);
        if(!TextUtils.isEmpty(passwords))
        {
            ((CheckBox) findViewById(R.id.savePasswordsCheckBox)).setChecked(true); // 更新单选框的状态
        }
    }
}

主要的思想还是通过两个自定义方法实现:login() 方法用于单击“登录”按钮时对用户名和密码等信息的储存,loadUserInfo() 方法用于恢复用户名和密码等操作。Ok,忙了这么久,让我们来试试:

android targetSdkVersion 30永久保存文件 android文件储存_android_04


如果你是第一次运行程序,那么你的界面应该是这样的。输入账户和密码,单击记住密码:

android targetSdkVersion 30永久保存文件 android文件储存_数据_05


点击登录按钮。然后完全退出程序,再次启动程序:

android targetSdkVersion 30永久保存文件 android文件储存_android数据存储_06

Yes,成功记住了密码,我们可以在模拟器的文件管理中找到我们刚刚储存的文件

android targetSdkVersion 30永久保存文件 android文件储存_Text_07


也可以将其导出到电脑中查看

android targetSdkVersion 30永久保存文件 android文件储存_android数据存储_08


当然,这里的代码还有很多不足之处,比如没有实现用户名和密码检测,没有对空的用户名和密码进行处理,有兴趣的小伙伴们可以自己实现。

如果博客中有什么不正确的地方,还请多多指点。

谢谢观看。。。