暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Android中的数据存取 | 实战演练—文件存储实现自动登录

722

“快乐购商城”项目中在登录页面当用户输入用户名和密码之后,再次登录需要实现自动登录,此时可以使用文件存储的方式实现此功能。


分析

登录页面当用户第一次登录的时候需要输入用户名和密码,当用户输入正确的用户名和密码后将用户名和密码保存在本地设备上,当用户下一次登录时,自动读取保存的用户名和密码,实现自动登录,如图7-1所示。


■ 图7-1登录页面


文件存储是Android中最基本的一种数据存储方式。Android可以使用Java语言开发,Java提供了一套完整的输入/输出流操作体系,与文件相关的有FileInputStream、FileOutputStream等,通过这些类可以非常方便地访问磁盘上的文件内容。同样,Android也支持这种方式来访问手机上的文件。Android手机中的文件有两个存储位置: 内置存储空间和外部SD卡。接下来对这两种存储方式进行详细的讲解。


1

内部存储空间文件的存取

内部存储是指将数据以文件的形式存储到应用程序中。对于Android应用来说,内部存储的数据属于应用程序的私有数据,如果其他应用程序想要操作本应用程序的文件,需要设置权限。当应用卸载以后,内部存储的数据也就清空了。为了保证内存数据的安全,不让用户直接定位访问,Android中对内部存储空间中文件的读取进行了封装,用户不需要知道具体的存储路径就可以打开相应的文件输入/输出流。在Context类中提供了两个方法来打开文件I/O流。

FileInputStream openFileInput(String name): 获取应用程序中名为name的文件对应的文件输入流。

FileOutputStream openFileOutput(String name, int mode): 获取应用程序名为name的文件对应的文件输出流。

name参数表示读取或者存入指定文件的文件名,不能包含路径分隔符“\”。如果文件不存在Android会自动创建该文件。mode参数用于指定操作模式,Context类中定义了四种操作模式常量,分别如下。

(1) Context.MODE_PRIVATE: 为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下写入的内容会覆盖原文件的内容。

(2) Context.MODE_APPEND: 附加模式,会检查文件是否存在,存在就往文件后追加内容,否则创建新文件再写入内容。

(3) Context.MODE_WORLD_READABLE: 表示当前文件可以被其他应用读取。

(4) Context.MODE_WORLD_WRITEABLE: 表示当前文件可以被其他应用写入。

提示: 如果希望文件既能被其他应用读也能写,可以传入: Context.MODE_WORLD_READABLE+Contex.MODE_WORLD_WRITEABLE或者直接传入数值3,四种模式中除了Contex.MODE_ APPEND会将内容追加到文件末尾,其他模式都会覆盖掉原文件的内容。

注意: 在Android高版本中已经废弃了MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE两种模式,因为让其他应用访问具体的文件是一件很危险的事情,容易导致安全漏洞。建议采用更好的机制,例如,通过ContentProvider暴露访问接口,或者通过服务或广播。

在手机上创建文件和向文件中追加内容的步骤如下。

(1) 调用openFileOutput()方法传入文件的名称和操作的模式,该方法将会返回一个文件输出流。

(2) 调用文件输出流的write()方法,向文件中写入内容。

(3) 调用文件输出流的close()方法,关闭文件输出流。

读取手机上文件的一般步骤如下。

(1) 调用openFileInput()方法传入读取数据的文件名,该方法返回一个文件输入流对象。

(2) 调用文件输入流的read()方法读取文件的内容。

(3) 调用文件输入流的close()方法关闭文件输入流。

下面以一个简单的例子来演示文件读取的操作,界面包括一个EditText、一个TextView和两个Button控件。EditText用于获取用户的输入,TextView用于展示从文件中读取的数据。当用户单击第一个Button按钮时,将数据写入到文件中。当用户单击第二个Button按钮时,获取文件中的内容。

用于控件布局文件的核心代码如下。

程序清单7-1: chart0701\app\src\main\res\layout\activity_main.xml

1 <?xml version="1.0" encoding="utf-8"?>  
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3   xmlns:tools="http://schemas.android.com/tools"  
4      android:layout_width="match_parent"  
5      android:layout_height="match_parent"  
6      android:orientation="vertical"  
7      tools:context=".MainActivity">
  
8 <EditText  
9          android:id="@+id/edit_content"  
10          android:layout_width="match_parent"  
11          android:layout_height="wrap_content"  
12          android:hint="请输入内容" />
  
13 <Button  
14          android:id="@+id/btn_save"  
15          android:layout_width="wrap_content"  
16          android:layout_height="wrap_content"  
17          android:text="保存到手机内部存储空间" />
  
18 <TextView  
19          android:id="@+id/tv_content"  
20          android:layout_width="match_parent"  
21          android:layout_height="wrap_content"  
22          android:lines="3"  
23          android:text="读取的内容" />
  
24 <Button  
25          android:id="@+id/btn_read"  
26          android:layout_width="wrap_content"  
27          android:layout_height="wrap_content"  
28          android:text="读取文件" />
  
29 </LinearLayout>


编写界面交互代码,在MainActivity中为按钮绑定单击事件,实现对数据的保存和读取,代码如下。

程序清单7-2: chart0701\java\com\example\administrator\chart0701\MainActivity.java

1  public class MainActivity extends AppCompatActivity {

2      private EditText editText;
3      private TextView textView;
4      private Button buttonSave;
5      private Button buttonRead;
6      private String fileName = "content.txt";
7      @Override
8      protected void onCreate(Bundle savedInstanceState) {

9          super.onCreate(savedInstanceState);
10          setContentView(R.layout.activity_main);
11          initView();
12      }
13  
14  
15      private void initView() {

16  editText = (EditText) findViewById(R.id.edit_content);
17  textView = (TextView) findViewById(R.id.tv_content);
18  buttonSave = (Button) findViewById(R.id.btn_save);
19  buttonRead = (Button) findViewById(R.id.btn_read);
20  buttonSave.setOnClickListener(new View.OnClickListener() {

21              @Override
22              public void onClick(View v) {

23                  String content = editText.getText().toString();
24                  try {

25                      FileOutputStream fos = openFileOutput(fileName, MODE_PRIVATE);
26                      fos.write(content.getBytes());
27                      fos.close();
28                  } catch (Exception e) {

29                      e.printStackTrace();
32                  }
33              }
34          });

35  
36          buttonRead.setOnClickListener(new View.OnClickListener() {

37              @Override
38              public void onClick(View v) {

39                  try {

40                      FileInputStream fis = openFileInput(fileName);
41                      byte[] bytes = new byte[fis.available()];
42                      fis.read(bytes);
43                      String content = new String(bytes);
44                      textView.setText(content);
45                      fis.close();
46                  } catch (Exception e) {

47                      e.printStackTrace();
48                  }
49              }
50          });

51      }
52  }


上述代码中,第20~34行代码为“保存到手机内部存储空间”按钮绑定单击事件,在这段代码中首先获取用户的输入,再通过openFileOutput()方法获取到文件输入/输出流对象,并传入两个参数,第一个是文件名称,第二个是操作模式,之后再调用write()方法向文件中写入内容,最后通过close()方法关闭文件。

第36~50行代码为“读取文件”按钮绑定单击事件。在上述代码中首先通过openFileInput()方法获取文件输入流对象。然后通过available()方法获取文件的长度并创建相应大小的byte数组用于存取读入的数据,再通过read()方法将文件内容读取到byte数组中,最后将读取到的内容转换成指定字符串。

当程序运行之后,首先在文本编辑框中输入”I love China”。单击“保存到手机内部存储空间”按钮。系统会首先查找手机上是否存在该文件,如果不存在就创建该文件,应用程序的数据文件默认保存在\data\data\\files目录下。其中,package name为当前应用程序的包名。

为了验证生成文件是否成功,可以通过Device File Explorer视图找到data/data/com.example.administrator.chart0701/files目录下的content.txt文件,如图7-2所示。双击Device File Explorer视图中的content.txt即可在Android Studio编辑框中查看content.txt文件中存储的数据,此时说明存储成功。


■ 图7-2文件的存储位置


之后再单击“读取文件”按钮,将content.txt文件的内容读取到应用程序中,并将数据展示在TextView控件中。

该代码的显示效果如图7-3所示。


■ 图7-3使用手机存储空间读写数据


2

读取SD卡上的文件


前面学习了如何读取手机内存中的文件,内存的空间直接会影响到手机的运行速度,通常不建议将数据保存到手机内存中,特别是一些比较大的资源,如图片、音频、视频等。而是将这些数据保存在外部存储,如SD卡或者设备内嵌的存储卡中,这种存储属于永久性存储,其中比较常见的就是SD卡。

读取SD卡上的文件和读取手机上的文件类似,都是通过文件操作流的方式进行读取的,Android中没有提供单独的SD卡文件操作类,直接使用Java中的文件操作即可。因为SD卡的可移动性,可能被移除或者丢失。并且不是所有手机都有SD卡,还有可能SD卡损坏或安装不正确等。因此,在访问之前需要验证手机的SD卡的状态,Android提供了Environment类来完成这一操作,当外部设备可用并且具有读写权限时,就可以通过FileInputStream和FileOutputStream对象来读写外部设备中的文件。

SD卡中的数据涉及用户的隐私,访问时需要申请相关的权限,需要使用到运行权限,即在程序运行时时提示用户进行授权。因此,读、写SD卡上文件的主要步骤如下。

(1) 调用Environment的getExternalStorageState()方法判断手机上是否插入了SD卡,并且SD卡是否正常读写。Environment.getExternalStorageState()方法用于获取SD卡的状态,如果手机装有SD卡,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA _MOUNTED。

(2) 判断用户是否授权,如果没有授权,请求授权,如果已授权则执行下一步。

(3) 调用Environment的getExternalStorageDirectory()方法来获取外部存储器的目录,也就是SD卡的目录(如果知道SD卡目录,可以使用绝对路径表示,但不提倡,因为不同版本可能路径不同。)

(4) 使用FileInputStream、FileOutputStream等读写SD卡的文件。

提示: 为了保证应用程序的安全性,Android系统规定程序访问系统的一些关键信息时,必须申请权限,否则程序运行时会因为没有访问系统信息的权限而直接崩溃。根据程序适配的Android SDK版本的不同,申请权限分为静态申请权限和动态申请权限两种。


1

静态申请权限

静态申请权限的方式适用于Android SDK 6.0以下的版本。该方式是在清单文件(AndroidManifest.xml)的节点中声明需要申请的权限。以申请SD卡的读权限为例,代码如下。


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


2

动态申请权限

当程序适配的Android SDK版本为6.0及以上时,Android改变了权限的管理模式,权限被分为正常权限和危险权限,具体如下。

(1) 正常权限: 表示不会直接给用户隐私权带来风险的权限,如请求网络的权限。

(2) 危险权限: 表示涉及用户隐私的权限,申请了该权限的应用可能涉及用户隐私信息的数据或资源,也可能对用户存储的数据或其他应用的操作产生影响。危险权限一共有九组,分别为位置(LOCATION)、日历(CALENDAR)、照相机(CAMERA)、联系人(CONTACTS)、存储卡(STORAGE)、传感器(SENSORS)、麦克风(MICROPHONE)、电话(PHONE)和短信(SMS)的相关权限。

申请正常权限时使用静态申请权限的方式即可,但是对于一些涉及用户隐私的危险权限 需要用户的授权才可以使用,因此危险权限不仅需要在清单文件(AndroidManifest.xml)的节点中添加权限,还需要在代码中动态申请权限,以动态申请SD卡的读权限为例说明: 

ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);


requestPermissions()方法中包含3个参数,第1个参数为Context上下文,第2个参数为需要申请的权限,第3个参数为请求码。添加完动态申请权限后,运行程序,界面上会弹出是否允许中请权限的对话框,由用户进行授权,如图7-4所示。

■ 图7-4弹出对话框


当用户单击ALLOW按钮时,表示允许授权。此时程序会执行动态申请权限的回调方法onRequestPermissionsResult(),在该方法中可以获取用户授权申请权限的结果。实例代码如下。


public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
      @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1) {
            for (int i = 0; i < permissions.length; i++) {
                if (permissions[i].equals
("android.permission.READ_EXTERNAL_STORAGE")
                     && grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "授权成功", Toast.LENGTH_SHORT).show();
               } else  {
                    Toast.makeText(this, "拒绝授权", Toast.LENGTH_SHORT).show();
                }
            }
        }
}


在上述代码中,onRequstPermissionsResult()方法中包含3个参数:requestCode、permissions、grantResults,分别表示请求码、请求的权限和用户授予权限的结果。当用户授予SD卡读权限时,对应该权限的grantResults数组中的值为PackageManager.PERMISSION_GRANTED。

仍然以上一小节的程序为例,展示把数据写入到SD卡,对于布局页面保持一致,在此就不再列出。
读写SD卡上的数据的第一步,必须在清单文件(AndroidManifest.xml)的节点中声明需要申请的读写SD卡的权限,如下。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />


在MainActivity代码页面中首先要判断是否存在SD卡,如果存在SD卡判断是否有相关的授权,如果没有授权请求授权,授权成功之后利用IO输入/输出流对文件进行读写操作。关键代码如下。

程序清单7-3: char0702\app\src\main\java\com\example\administrator\

1  public class MainActivity extends AppCompatActivity {

2      private EditText editText;
3      private TextView textView;
4      private Button buttonSave;
5      private Button buttonRead;
6      private String fileName = "sdtext.txt";
7      @Override
8      protected void onCreate(Bundle savedInstanceState) {

9          super.onCreate(savedInstanceState);
10          setContentView(R.layout.activity_main);
11          initView();
12      }
13  
14  
15  
16      private void initView() {

17          editText = (EditText) findViewById(R.id.edit_content);
18          textView = (TextView) findViewById(R.id.tv_content);
19          buttonSave = (Button) findViewById(R.id.btn_save);
20          buttonRead = (Button) findViewById(R.id.btn_read);
21          buttonSave.setOnClickListener(new View.OnClickListener() {

22              @Override
23              public void onClick(View v) {

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

25  if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission
26                    .WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

27  ActivityCompat.requestPermissions(MainActivity.this, new
28  String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2);
29                     } else {

30                      writeToSD();
31                      }
32                  }
33              }
34          });

35          buttonRead.setOnClickListener(new View.OnClickListener() {

36              @Override
37              public void onClick(View v) {

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

39  if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission
40                              .READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

41                          ActivityCompat.requestPermissions(MainActivity.this, new

42  String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
43                      } else {

44                          readFromSD();
45                      }
46                  }
47              }
48          });

49      }
50      @Override
51      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,

52                @NonNull int[] grantResults)
 
{

53                 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
54          if (requestCode == 1) {

55             for (int i = 0; i < permissions.length; i++) {

56  if(permissions[i].equals("android.permission.READ_EXTERNAL_STORAGE")
57                          && grantResults[i] == PackageManager.PERMISSION_GRANTED) {

58                      readFromSD();
59                  } else {

60                      Toast.makeText(this, "拒绝授权", Toast.LENGTH_SHORT).show();
61                  }
62              }
63          }
64          if (requestCode == 2) {

65             for (int i = 0; i < permissions.length; i++) {

66  if(permissions[i].equals("android.permission.WRITE_EXTERNAL_STORAGE")
67                          && grantResults[i] == PackageManager.PERMISSION_GRANTED) {

68                      writeToSD();
69                  } else {

70                      Toast.makeText(this, "拒绝授权", Toast.LENGTH_SHORT).show();
71                  }
72              }
73          }
74      }
75      private void readFromSD() {

76          File SDPath = Environment.getExternalStorageDirectory();
77          File file = new File(SDPath, fileName);
78          try {

79              FileInputStream fis = new FileInputStream(file);
80              BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
81              String content = reader.readLine();
82              textView.setText(content);
83              fis.close();
84          } catch (Exception e) {

85              e.printStackTrace();
86          }
87      }
88      private void writeToSD() {

89          String content = editText.getText().toString();
90          File SDPath = Environment.getExternalStorageDirectory();
91          try {

92            File file = new File(SDPath, fileName);
93            FileOutputStream fos = new FileOutputStream(file);
94              fos.write(content.getBytes());
95              fos.close();
96          } catch (Exception e) {

97              e.printStackTrace();
98          }
99      }
100  }


在上述代码中第21~34行代码为“保存到SD卡”注册单击事件,在单击事件中首先判断SD卡是否可用,如果可用检查是否动态授权,如果没有授权第27~28行申请授权。如果已经动态授权,第30行代码直接写入到SD卡的文件中。

第35~49行代码为“读取SD卡文件”注册单击事件,同样地,首先判断SD卡是否可用,如果可用检查是否动态授权,如果没有授权第41~42行申请授权。如果已经动态授权,第44行代码直接写入到SD卡的文件中。

第51~74行代码,在用户手动选择是否授权之后执行回调函数,在回调函数中判断用户是否授权,如果授权则执行相应的方法执行读写文件的操作。如果没有授权则提示用户“拒绝授权”。

第75~99行代码封装读取SD卡文件和写入到SD卡文件的方法,在方法中利用Java中的输入/输出流实现对文件的读取和存储。

先在文本输入框中输入“I love Android”,单击“保存到SD卡”按钮将数据保存在SD卡中。为了验证生成文件是否成功,可以通过Device File Explorer视图找到storage\\emulated\\0\\目录下sdtext.txt文件,如图7-5所示。双击Device File Explorer视图中的sdtext.txt即可在Android Studio编辑框中查看sdtext.txt文件中存储的数据,此时说明存储成功。


■ 图7-5文件存储的位置


之后再单击“读取SD卡文件”按钮,将sdtext.txt文件的内容读取到应用程序中,并将数据展示在TextView控件中。

代码的运行效果如图7-6所示。


■ 图7-6使用SD卡读写文件


3

实战演练——文件存储实现自动登录


通过对文件存储的学习,实现登录页面用户名和密码的自动保存。布局页面的代码如下。

程序清单7-4: chart0703\app\src\main\res\layout\activity_main.xml

1  <?xml version="1.0" encoding="utf-8"?> 
2  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3      xmlns:tools="http://schemas.android.com/tools"  
4      android:layout_width="match_parent"  
5      android:layout_height="match_parent"  
6      android:orientation="vertical"  
7      tools:context=".MainActivity">
8      <ImageView
9          android:id="@+id/iv_head"  
10          android:layout_width="70dp"  
11          android:layout_height="70dp"  
12          android:layout_gravity="center_horizontal"  
13          android:layout_marginTop="70dp"  
14          android:background="@drawable/defaultuser_icon" />
15     
16          android:id="@+id/et_user_name"  
17          android:layout_width="fill_parent"  
18          android:layout_height="40dp"  
19          android:layout_gravity="center_horizontal"  
20          android:layout_marginLeft="35dp"  
21          android:layout_marginRight="35dp"  
22          android:layout_marginTop="35dp"  
23          android:background="@drawable/textview_borders"  
24          android:drawableLeft="@drawable/user_name_icon"  
25          android:drawablePadding="10dp"  
26          android:gravity="center_vertical"  
27          android:hint="请输入用户名"  
28          android:paddingLeft="8dp"  
29          android:singleLine="true"  
30          android:textColor="#000000"  
31          android:textColorHint="#a3a3a3"  
32          android:textSize="14sp" />
33      <EditText
34          android:id="@+id/et_psw"  
35          android:layout_width="fill_parent"  
36          android:layout_height="40dp"  
37          android:layout_gravity="center_horizontal"  
38          android:layout_marginLeft="35dp"  
39          android:layout_marginRight="35dp"  
40          android:background="@drawable/textview_borders"  
41          android:layout_marginTop="5dp"  
42          android:drawableLeft="@drawable/psw_icon"  
43          android:drawablePadding="10dp"  
44          android:hint="请输入密码"  
45          android:inputType="textPassword"  
46          android:paddingLeft="8dp"  
47          android:singleLine="true"  
48          android:textColor="#000000"  
49          android:textColorHint="#a3a3a3"  
50          android:textSize="14sp" />
51      <Button
52          android:id="@+id/btn_login"  
53          android:layout_width="fill_parent"  
54          android:layout_height="40dp"  
55          android:layout_gravity="center_horizontal"  
56          android:layout_marginLeft="35dp"  
57          android:layout_marginRight="35dp"  
58          android:layout_marginTop="15dp"  
59          android:background="@color/colorPrimary"  
60          android:text="登 录"  
61          android:textColor="@android:color/white"  
62          android:textSize="18sp" />
63      <LinearLayout
64          android:layout_width="fill_parent"  
65          android:layout_height="fill_parent"  
66          android:layout_marginLeft="35dp"  
67          android:layout_marginRight="35dp"  
68          android:layout_marginTop="8dp"  
69          android:gravity="center_horizontal"  
70          android:orientation="horizontal">
71          <TextView
72              android:id="@+id/tv_register"  
73              android:layout_width="0dp"  
74              android:layout_height="wrap_content"  
75              android:layout_weight="1"  
76              android:gravity="center_horizontal"  
77              android:padding="8dp"  
78              android:text="立即注册"  
79              android:textColor="@color/colorPrimary"  
80              android:textSize="14sp" />
81          <TextView
82              android:id="@+id/tv_find_psw"  
83              android:layout_width="0dp"  
84              android:layout_height="wrap_content"  
85              android:layout_weight="1"  
86              android:gravity="center_horizontal"  
87              android:padding="8dp"  
88              android:text="找回密码?"  
89              android:textColor="@color/colorPrimary"  
90              android:textSize="14sp" />
91      </LinearLayout>
92  </LinearLayout>


新建工具类实现对用户名和密码的保存,类名为saveFile,在该类中实现对用户名和密码的保存。

程序清单7-5: char0703\app\src\main\java\com\example\administrator\chart0703\saveFile.java

1  public class saveFile {

2  public static boolean saveInfoToFile(Context context, String userName, String userPwd) {

3          FileOutputStream fos = null;
4          try {

5             fos = context.openFileOutput("user.txt", Context.MODE_PRIVATE);
6  fos.write((userName + "&" + userPwd).getBytes());
7              fos.close();
8              return true;
9          } catch (Exception e) {

10              e.printStackTrace();
11              return false;
12          }
13      }
14  public static Map<String, String> getInfoFromFile(Context context){

15          FileInputStream fis = null;
16          try {

17              fis = context.openFileInput("user.txt");
18  byte[] bytes = new byte[fis.available()];
19              fis.read(bytes);
20              String content = new String(bytes);
21  String[] splitStr = content.split("&");
22  HashMap<String, String> userMap = new HashMap<>();
23              userMap.put("userName", splitStr[0]);
24              userMap.put("userPwd", splitStr[1]);
25              fis.close();
26              return userMap;
27          } catch (Exception e) {

28              e.printStackTrace();
29              return null;
32          }
33      }
34  }


在上述代码中,第2~13行代码创建一个saveInfoToFile()方法,用于将用户名和密码保存在user.txt文件中,第5行通过调用openFileOutput()方法获取fos对象,之后通过该对象的write()方法将用户名和密码以字节的形式写入到user.txt文件中。

第14~33行代码创建一个getInfoFromFile()方法用于读取保存在user.txt文件中的用户名和密码。第17行代码通过调用openFileInput()方法获取fis对象,之后通过该对象的read()方法将user.txt文件中的内容读取到字节数组中。在将字节数组转换成字符串并对字符串进行分隔,最终获取到用户名和密码。

逻辑代码页面MainActivity中的代码如下。

程序清单7-6: chart0703\app\src\main\java\com\example\administrator\

1  public class MainActivity extends AppCompatActivity {

2      private TextView tvRegister;
3      private TextView tvFindPwd;
4      private EditText editName;
5      private EditText editPwd;
6      private Button btnLogin;
7      private String userName;
8      private String psw;
9      @Override  
10      protected void onCreate(Bundle savedInstanceState) {

11          super.onCreate(savedInstanceState);
12          setContentView(R.layout.activity_main);
13          initView();
14          initListener();
15          Map<String, String> uerInfo = saveFile.getInfoFromFile(this);
16          if (uerInfo != null) {

17              editName.setText(uerInfo.get("userName"));
18              editPwd.setText(uerInfo.get("userPwd"));
19          }
20      }
21      private void initView() {

22          tvRegister = (TextView) findViewById(R.id.tv_register);
23          editName = (EditText) findViewById(R.id.et_user_name);
24          editPwd = (EditText) findViewById(R.id.et_psw);
25          tvRegister = (TextView) findViewById(R.id.tv_register);
26          tvFindPwd = (TextView) findViewById(R.id.tv_find_psw);
27          btnLogin = (Button) findViewById(R.id.btn_login);
28      }
29    
30    
31    
32      private void initListener() {

33          btnLogin.setOnClickListener(new View.OnClickListener() {

34              @Override  
35              public void onClick(View v) {

36         userName = editName.getText().toString().trim();
37                        psw = editPwd.getText().toString();
38                  if (userName.isEmpty() || psw.isEmpty()) {

39                      Toast.makeText(MainActivity.this, "用户名或密码不能为空",
Toast.LENGTH_SHORT).show();

40                      return;
41                  } else {

42                      Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
43                      boolean isSave = saveFile.saveInfoToFile(MainActivity.this, userName, psw);
44                      if (isSave) {

45                         Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
46                      }
47                  }
48              }
49          });

50      }
51  }


在上述代码中,第15~19行首先通过工具类saveFile中的getInfoFromFile()方法获取保存在文件中的用户名和密码,如果之前保存了用户名和密码,则将读取的用户名和密码展示在登录框和密码框中。

第33~49行代码为“登录”按钮注册单击事件,在单击事件内部,首先获取用户输入的用户名和密码,如果获取的用户名或者密码为空,则提示用户“用户名或密码不能为空”,否则调用saveFile类中的saveInfoToFile()方法将用户名和密码保存在本地文件中,并提示用户“登录成功”和“保存成功”。

运行以上程序,在用户名和密码框中分别输入“123”,单击“登录”按钮,弹出“登录成功”和“保存成功”表示用户名和密码已经保存在本地文件中,也可以通过Device File Explorer浏览设备文件,从该应用程序目录中查找该文件。运行结果如图7-7所示。


■ 图7-7登录成功并保存登录信息


当关闭程序再次打开程序之后,界面上会自动加载出用户名和密码,如图7-8所示。


■ 图7-8再次登录自动加载登录信息


实例讲解

Android零基础入门到实战

精彩回顾

鸿蒙开发入门

开发第一个鸿蒙应用+页面跳转



下期预告

Android中的数据存取

2. SharedPreferences保存用户名和密码
3. 实战演练——订单处理




4

参考书籍


《Android零基础入门到实战(App项目开发·鸿蒙开发入门·微课视频版)》

ISBN:9787302600671

作者:赵圣鲁、胡颖辉、余燕萍、汪宗伟、吴微微

定价:59.8元

扫码微店优惠购书


内容简介

本书围绕Android初学者从零基础到实战达人的过程进行设计,采用项目教学法,以作者开发的“欢乐购商城”App为例,以一个完整的项目开发为主线,将项目开发分解为9个教学模块,分别为App应用体验、Android基础界面控件、Android高级界面控件、列表控件、页面跳转与切换、Android中的数据存取、Android客户端与服务器端交互、综合项目“欢乐购商城”实现等。读者在学习基础知识过程中将熟悉App综合项目开发流程,逐步培养独立开发综合项目的能力,并最终实现综合项目。同时本书引入鸿蒙开发入门知识,供有兴趣的读者参考学习。本书可作为应用型本科计算机专业、软件专业、高职软件技术专业及相关专业的教材,也可作为Android和鸿蒙开发爱好者以及初、中级Android应用开发人员的参考工具书。


编辑推荐

为了方便读者学习,本书配套了微课教学视频、源码、课件、试题、课程大纲等教学资源。所有配套资源均可在清华大学出版社官方网站下载。其中安卓项目案例源码,基于Java JDK1.8+Android Studio Arctic Fox+Android SDK 11.0+gradle:7.0.0-beta04开发;鸿蒙项目案例源码,基于Open JDK1.8+DevEco Studio 2.1 release+sdk(api version 5)+gradle6.3开发。


扫码京东优惠购书


5

精彩推荐


文章转载自清华计算机学堂,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论