记住密码实现+文件存储


记住密码实现+文件存储

(ps:其余界面参考博客之登录注册实现)

一、具体步骤

1、在login.xml中添加复选框


2、在Login.java中定义私有变量,绑定id,在onCreate中,将保存的用户名、密码设置到登陆界面的输入框中

public class Login extends AppCompatActivity 
{
   …………
    private  CheckBox cb4;//是否保存密码复选框
    
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        …………
        cb4 = (CheckBox)findViewById(R.id.check4);//绑定id

        //获取 SharedPreferences 对象
        SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
        //获取一个SharedPreferences.Editor 对象,获取编辑器
        SharedPreferences.Editor editor = sp.edit();
        //没有找到"remember_password",就返回默认值false
        boolean isRemember = sp.getBoolean("save", false);
        if (isRemember)
          {
              // 将账号和密码都设置到界面显示的用户名和密码文本框中
              String savename = sp.getString("用户名", "");//没找到就返回空
              //读取SharedPreferences中的key为"密码"对应的值,若值不存在则返回""字符串
              String savepw = sp.getString("密码", "");
              text1.setText(savename);
              text2.setText(savepw);
              cb4.setChecked(true);
          }
          ………………
     }
     ………………
}

3、在用户名和密码匹配情况下,判断是否选中复选框

//如果用户名和密码匹配成功,则Toast 显示出用户名和密码,跳转主页面
else {
    //下面两句是全局变量,只写在 if(cb4.isChecked())里则editor.clear()和editor.apply()获取不到
    //获取私有类型的 SharedPreferences 对象
    SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
    
    //获取一个SharedPreferences.Editor 对象
    /*SharedPreferences只提供获取数据的方法,不支持直接存储和修改数据,需要调用edit()方法得到 SharedPreferences.Editor()对象才可存储修改数据*/
    SharedPreferences.Editor editor = sp.edit();

       //是否选中保存密码复选框
       if(cb4.isChecked())
         {
           //判断当前是否存数据
           editor.putBoolean("save", true);
           //以键值对方式传入数据
           editor.putString("用户名",s1);//与上面的用户名对应,通过键值对传参,键名一样就可以传递
           editor.putString("密码",s2);
           //editor.commit();//editor.apply();  两句都可以,最后提交,此举可省
         }
       else
          {
           editor.clear();//没选中就在data文件夹删除所有数据信息
          }
       //先通过Editor对象删除、添加数据,最后提交
       editor.apply();//提交修改     
       …………
     }

4、完整的Login.java代码如下

package com.example.myapplication2;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.Toast;

public class Login extends AppCompatActivity {

    private Button button1,button2;
    private EditText text1,text2;
    //需要维护两个全局私有变量,用来存储用户名和密码。
    private  String login_name="yy";// 保存的用户名、或注册的新用户名
    private  String login_pss = "121";// 保存的密码、或注册的密码
    private  String s1,s2;//用户输入的用户名和密码
    private  static final  String s3="Login活动";
    private  CheckBox cb4;//是否保存密码复选框


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

        Log.w(s3,"执行onCreat()方法");

        //绑定对应的按钮
        button1 = (Button) findViewById(R.id.Button1);
        button2 = (Button) findViewById(R.id.Button2);
        text1 = (EditText) findViewById(R.id.Editext1);
        text2 = (EditText) findViewById(R.id.Editext2);
        cb4 = (CheckBox)findViewById(R.id.check4);

        //获取 SharedPreferences 对象
        SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
        //获取一个SharedPreferences.Editor 对象
        SharedPreferences.Editor editor = sp.edit();
        //没有找到"remember_password",就返回默认值false
        boolean isRemember = sp.getBoolean("save", false);
        if (isRemember)
          {
              // 将账号和密码都设置到界面显示的用户名和密码文本框中
              String savename = sp.getString("用户名", "");//没找到就返回空,用户名为键名,与后面对应
              String savepw = sp.getString("密码", "");
              text1.setText(savename);
              text2.setText(savepw);
              cb4.setChecked(true);
          }

            //注册监听登录按钮
        button1.setOnClickListener(new Button.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                s1 = text1.getText().toString();  //获取输入的用户名
                s2 = text2.getText().toString();  //获取输入的密码
                // 如果获取文本长度为0,创建一个信息对话框,弹出“登录信息不可为空”
                if (s1.length()==0 || s2.length()==0)
                {
                    new AlertDialog.Builder(Login.this).setTitle("登录信息不可为空")
                            .setMessage("请输入用户名或者密码")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener()
                            {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i)
                                {
                                    //finish();
                                }
                            }).show();
                    text1.setText("");//清空用户框
                    text2.setText("");//清空密码框
                    text1.requestFocus();//获取焦点,光标出现
                }

              //输入的信息与预设用户名、密码不匹配,弹出对话框提示“账号或密码错误”
               else  if (!s1.equals(login_name) || !s2.equals(login_pss))
                {
                    new AlertDialog.Builder(Login.this).setTitle("登录信息有误")
                            .setMessage("用户名或者密码错误")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener()
                            {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i)
                                {
                                    //finish();
                                }
                            }).show();
                    text1.setText("");//清空用户框
                    text2.setText("");//清空密码框
                    text1.requestFocus();//获取焦点,光标出现
                }

                //如果用户名和密码匹配成功,则Toast 显示出用户名和密码,跳转主页面
                else {
                    //下面两句是全局变量,只写在 if(cb4.isChecked())里则editor.clear()和editor.apply()获取不到
                    //获取 SharedPreferences 对象
                    SharedPreferences sp = getSharedPreferences("data",MODE_PRIVATE);
                    //获取一个SharedPreferences.Editor 对象
                    SharedPreferences.Editor editor = sp.edit();

                       //是否选中保存密码复选框
                       if(cb4.isChecked())
                       {
                           //判断当前是否存数据
                           editor.putBoolean("save", true);
                           //以键值对方式传入数据
                           editor.putString("用户名",s1);//与上面的用户名对应,通过键值对传参,键名一样就可以传递
                           editor.putString("密码",s2);
                           //editor.commit();//editor.apply();  两句都可以,最后提交,此举可省
                       }
                       else
                       {
                           editor.clear();//没选中就在data文件夹删除所有数据信息
                       }
                       editor.apply();//提交修改


                    String msg = "欢迎进入学习乐园吖 \n 您输入的用户名是:"+ login_name + "\n 密码是: "+login_pss ;
                    Toast.makeText(Login.this,msg,Toast.LENGTH_LONG).show();
                    Intent intent = new Intent(Login.this, Base.class);//创建intent对象,实现页面跳转,跳转到Base活动页面
                    startActivity(intent);//直接跳转,无信息交换
                    text1.setText("");//清空用户框
                    text2.setText("");//清空密码框
                    text1.requestFocus();//获取焦点,光标出现
                    }
            }

        });

//绑定、监听“注册”按钮
        button2.setOnClickListener(new Button.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                Intent intent = new Intent(Login.this,Register.class);
                startActivityForResult(intent,1);//携带信息跳转,请求码1,代表Register页面
            }
        });

    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        super.onActivityResult(requestCode, resultCode, data);
        //在一个活动中有可能调用 startActivityForResult()方法去启动很多不同的活动
        if (requestCode == 1)
        {
            //当Login中的Button被触发 onClick() 事件后,把Register中EditText的内容返回给Login。
//返回到Login后,执行ononActivityResult()方法,判断RequestCode和ResultCode无误后,把Login中的EditText的内容改为Register返回的结果。
            //通过这样的方式打开这两个Activity,使他们中EditText的内容同步,一个 Activity 改变了,到另一个 Activity 中也会跟着改变。
            if (resultCode == RESULT_OK)
            {
//注册成功,弹出提示框
                new AlertDialog.Builder(Login.this).setTitle("注册成功")
                        .setMessage("成功注册账号,已自动返回登录页面。")
                        .setPositiveButton("确定", new DialogInterface.OnClickListener()
                        {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i)
                            {
                                //finish();
                            }
                        }).show();
                login_name = data.getStringExtra("text1");
                login_pss = data.getStringExtra("text2");
            }

        }
    }

    @Override
    protected void onStart() 
    {
        super.onStart();
        Log.w(s3,"执行onStart()方法");
    }
}

二、效果图

①未勾选保存密码(下次进入应用在用户名输入框和密码输入框没有内容,需要自己输入)

②勾选保存密码(下次进入应用在用户名输入框和密码输入框已有信息,不需要再次输入密码)

三、文件夹信息

1、打开data文件

2、data文件以xml形式存储,内容如下:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>

    kk
    
    250

四、关于文件存储的问题

1、代码:

(1)MainActivity.java

package com.example.app1savefile;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class MainActivity extends AppCompatActivity
{
    private EditText edit;
    private Button bt_save_in;
    private Button bt_read_in;
    private Button bt_save_out;
    private Button bt_read_out;
    private Button bt_clr_edit;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //绑定id
        edit = (EditText)findViewById(R.id.edit);
        bt_clr_edit = (Button)findViewById(R.id.bt_clr_edit);
        bt_save_in = (Button)findViewById(R.id.bt_save_in);
        bt_read_in =(Button)findViewById(R.id.bt_read_in);
        bt_save_out = (Button)findViewById(R.id.bt_save_out);
        bt_read_out = (Button)findViewById(R.id.bt_read_out);

        //为清除按钮添加监听器
        bt_clr_edit.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                //输入框置空
                edit.setText("");
            }
        });

        //为内部保存按钮添加监听器
        bt_save_in.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                //将输入框获得的信息转化为String类型,存入inputText变量
                String inputText = edit.getText().toString();
                //调用saveToInternalStorage()方法,参数为输入文本
                saveToInternalStorage(inputText);
                //弹出消息:内部存储成功
                Toast.makeText(MainActivity.this,"Save to internal storage succeeded",
                        Toast.LENGTH_SHORT).show();
            }
        });
        //为读取内部存储按钮添加监听器
        bt_read_in.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                //调用loadFromInternalStorage()方法
                String inputText = loadFromInternalStorage();
                /*判断字符串为空(字符串为空值,或者空字符串),当传入的字符串等于null或者等于空字符串的时候,
                这个方法就会返回 true,从而使得我们不需要先单独判断这两种空值再使用逻辑运算符连接起来了。*/
                if (!TextUtils.isEmpty(inputText))
                {
                    edit.setText(inputText);
                    edit.setSelection(inputText.length());
                    //弹出信息:从内部存储还原成功
                    Toast.makeText(MainActivity.this, "Restoring from internal storage succeeded", Toast.LENGTH_SHORT).show();
                }
            }
        });


        bt_save_out.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                String inputText = edit.getText().toString();
                saveToExternalStorage(inputText);
                Toast.makeText(MainActivity.this,"Save to external storage succeeded",
                        Toast.LENGTH_SHORT).show();
            }
        });


        bt_read_out.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                String inputText = loadFromExternalStorage();
                if (!TextUtils.isEmpty(inputText))
                {
                    edit.setText(inputText);
                    edit.setSelection(inputText.length());
                    Toast.makeText(MainActivity.this, "Restoring from external storage succeeded", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    //保存到内部存储的方法
    /*将数据写到内部存储文件中,使用Context提供的openFileOutput()方法,通过这个方法获取FileOutputStream对象,
    得到这个对象之后就可以使用 Java 流的方式将数据写入到文件中了。*/
    public void saveToInternalStorage(String inputText)
    {
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            /*设置文件创建时使用的名称为“data”,以及存储方式
            主要有两种文件的操作模式可选,MODE_PRIVATE(覆盖原文)和MODE_APPEND(追加内容)*/
            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();
            }
        }
    }
    /*从内部存储读取的方法,openFileInput() 方法只接收一个参数,即要读取的文件名,
     然后系统会自动到 /data/data/<包名>/files/ 目录下去加载这个文件,并返回一个 FileInputStream 对象。*/
    public String loadFromInternalStorage()
    {
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try {
            //设置将要打开的存储文件名称
            in = openFileInput("data");
            // FileInputStream -> InputStreamReader ->BufferedReader
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            //读取每一行数据,并追加到StringBuilder对象中,直到结束
            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();
    }

    public void saveToExternalStorage(String inputText)
    {
        /*由于外部存储方式一般存放在外部设备里,所以在使用之前要先检查外围设备是否存在。
        使用Environment.getExternalStorageState()方法来查看外部设备是否存在*/
        String environment = Environment.getExternalStorageState();
        if(Environment.MEDIA_MOUNTED.equals(environment))
        {
            //外部设备可以进行读写操作
            //保存在外部存储根目录,卸载应用时不能删除该文件
            //File sd_path = Environment.getExternalStorageDirectory();
//            Log.e("MainActivity",sd_path.toString());
//            File file = new File(sd_path,"test.txt");
            //保存在外部私有目录,卸载时会同时删除该文件
            String sd_path = this.getExternalFilesDir("").getAbsolutePath();
            Log.e("MainActivity+",sd_path);
            File file = new File(sd_path);
            if(!file.exists()){//判断文件目录是否存在
                file.mkdirs();
            }
            file = new File(sd_path,"text.txt");
           //写入数据
            try{
                // 打开文件输出流
                FileOutputStream  fos = new FileOutputStream(file);
                OutputStreamWriter osw = new OutputStreamWriter(fos);
                osw.write(inputText);
                osw.flush();
                osw.close();
                // 关闭输出流
                fos.close();
            }catch(Exception exception){
                exception.printStackTrace();
            }
        }
    }

    public String loadFromExternalStorage() {
        String content = null;
        String environment = Environment.getExternalStorageState();
        if(Environment.MEDIA_MOUNTED.equals(environment))
        {
            //使用Environment.getExternalStorageDirectory()获取外部存储的根路径。当外部设备存在时,就可以通过路径创建文件
//            File sd_path = Environment.getExternalStorageDirectory();
//            Log.e("MainActivity",sd_path.toString());
//            File file = new File(sd_path,"test.txt");
            String sd_path = this.getExternalFilesDir("").getAbsolutePath();
            File file = new File(sd_path,"text.txt");
            Log.e("MainActivity+",file.getPath());

            FileInputStream fis;
            try{//读取文件
                fis = new FileInputStream(file);
                InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
                char[] input = new char[fis.available()];
                isr.read(input);
                content = new String(input);
                isr.close();
                fis.close();
            }catch(Exception exception){
                exception.printStackTrace();
            }
        }
        return content;
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        String inputText = edit.getText().toString();
        saveToInternalStorage(inputText);
        Toast.makeText(MainActivity.this,"Save to internal storage succeeded",
                Toast.LENGTH_SHORT).show();
    }
}

(2)activity_main.xml

<?xml version="1.0" encoding="utf-8"?>


    

    

        

2、在内部存储私有目录和外部存储私有目录、外部根目录或外部共有目录存取文件,并测试卸载APP前后的结果

  • (1)模拟设备或真机的外部存储根目录?

    ? 雷电模拟器设备的外部存储的根目录是 storage/emulated/0

  • (2)应用管理器中对应用清除缓存是清除哪里的数据?

    ? 清除缓存是清除了APP运行过程之中临时产生的数据,比如读入程序,计算,输入输出等等,这些过程中肯 定会产生很多的数据,它们在内存中。

  • (3)应用管理器中对应用清除数据是清除了哪些地方的数据?

    ? 清理数据是清除 data/data/包名 中的cache,files,lib,databases,shared_prefs等等 以及 外部私有存储之中的storage/emulated/0/Android/data/包名 中的文件,清除的均为内外存储所有的私密文件。

  • (4)卸载应用时,创建在外部存储根目录中的文件会被自动清除吗?

    ? 卸载应用的时候,创建在外部存储根目录之下的Android/data/对应包名所在的文件夹会被自动清除,但是其他根目录之下的文件以及文件夹不会发生变化。

  • (5)卸载应用时,创建在内部存储中的文件会被自动清除吗?

    ? 卸载应用的时候,内部存储的文件会被自动清除。创建在内部存储之中的data/data/对应包名之下的所有文件都会被清除,以及data/app/包名 目录及其中的相关安装文件。

  • (6)卸载应用时,创建在外部存储私有目录的文件会被自动清除吗?

    ? 卸载应用的时候,创建在外部存储私有目录的文件也会被清除。

    3、效果图