Android:<15>数据轻量级存储之仿QQ登录界面

上一期我们讲解了如何调试和寻找bug,程序出问题了我们一定要清楚是哪一个环节,可以根据程序报错的位置,在那里打上断点,然后启动调试,查看变量值的变化情况,如果有异常的值或者变量我们就跟着它,从定义到结束都查看一下就可以找到问题了;

那么这一期我们来学习一下数据的轻量级存储,之前我们学习了使用intent和bundle来存储数据,而且他们的存储是没有本地的数据的,程序销毁之后就消失了,不利于数据长期存储,现在我们来学习一个常常用在存储登录信息的存储类,SharedPerferences,这个类是需要上下文点出来的,所以跟上下文有关联,在我们创建的时候要注意,学完了存储类之后我们就做一个QQ登录的小案例;

1、创建

看下面的代码,创建这个对象后还需要创建一个编辑对象才能实现数据的添加,跟之前我们学习的bundle一样,也是键值对的存储方式;

    public static void appendData(Context context , String username, String password){
        //1.4 新建一个数据存储对象,第一个参数是自定义的文件夹名,第二个是模式
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //创建一个文件编辑对象
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("username",username);
        editor.putString("password",password);
        //必须提交,不然不起作用
        editor.commit();
    }

注意这个是使用的sharedperences的编辑对象edit(),这种创建方法非常常见,一定要理解,然后就是放数据使用putString(),当然,不止可以放String,还有boolean、float等,最后记住commit一下; 

2、读取

读取数据同样使用这个方法来获取到文件对象,不过读取是不需要创建编辑器对象的,直接在sharedprefernces点出getString()根据我们自己定义的键值就可以拿到数据,不过注意有一个默认值,之类设置为null是为了后面的判断是否存在数据,这个方法是将数据以数组的形式返回,当然存在数据不存在的情况;

    //1.2 读取数据,因为含有多个数据,所以我们使用数组存储
    public static String[] readData(Context context){
        //1.5 同样新建一个数据存储对象,获取到我们存储的数据
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //判断是否数据为空
        String username=sp.getString("username",null);
        String password=sp.getString("password",null);
        String[] datas;
        if(username == null){
            //如果没有数据就返回null
            return null;
        }else{
            //读取数据
            datas = new String[2];
            datas[0]=username;
            datas[1]=password;
            return datas;
        }

    }

在我们的android stdio中有一个地方可以查看这个类存储的信息,会自动生成一个xml格式的文件,存放的键值对,也就是map;这个文件会存储为:data/包名/data/shres_refs路径下,在android studio右下角的文件浏览器中可以找到(注意需要启动手机才可以找到):

 

3、删除

删除同样需要创建这个对象(名字太长,懒得写,懂的都懂),毕竟是删除还是要创建一个编辑器对象,然后执行clean()或者remove(“键值”)进行删除,前者是清空;

    //1.3 删除,在我们不勾选记住密码的时候需要清除一下数据
    public void deleteData(Context context){
        //1.6 同样新建一个数据存储对象,获取到我们存储的数据
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //创建一个文件编辑对象
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
    }

小案例:

接下来就是我们的小案例部分,我们要创建两个activity,一个是登录界面,一个是登陆后的提示界面;

还要创建一个工具类,里面存放有上面介绍的三个方法:

4、创建工具类:

package com.example.qqloginactivity;

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

/*
    1.1 创建一个工具类用于简化数据的增删改查
     ,存储文件是根据上下文联系起来的,所以我们需要获取到上下文
 */
public class Utils {

    //添加,因为只有数据的操作,所以我们使用静态,将来可以直接用类名调用
    public static void appendData(Context context , String username, String password){
        //1.4 新建一个数据存储对象,第一个参数是自定义的文件夹名,第二个是模式
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //创建一个文件编辑对象
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("username",username);
        editor.putString("password",password);

        //必须提交,不然不起作用
        editor.commit();
    }
    //1.2 读取数据,因为含有多个数据,所以我们使用数组存储
    public static String[] readData(Context context){
        //1.5 同样新建一个数据存储对象,获取到我们存储的数据
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //判断是否数据为空
        String username=sp.getString("username",null);
        String password=sp.getString("password",null);
        String[] datas;
        if(username == null){
            //如果没有数据就返回null
            return null;
        }else{
            //读取数据
            datas = new String[2];
            datas[0]=username;
            datas[1]=password;
            return datas;
        }

    }
    //1.3 删除,在我们不勾选记住密码的时候需要清除一下数据
    public static void deleteData(Context context){
        //1.6 同样新建一个数据存储对象,获取到我们存储的数据
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //创建一个文件编辑对象
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.commit();
    }
}

注意,清除数据一样是需要提交事务的,不然会清除失败 

5、布局登录界面:

当然,按你们的喜好就行,我这里提供一个参考:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LoginActivity">
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@mipmap/tou4"
        android:scaleType="fitXY"
        android:layout_marginTop="100dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:id="@+id/img_tou"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="用户名:"
        android:textSize="30sp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/img_tou"
        android:id="@+id/tv_username"/>
    <EditText
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_marginRight="20dp"
        app:layout_constraintTop_toBottomOf="@id/img_tou"
        app:layout_constraintLeft_toRightOf="@id/tv_username"
        app:layout_constraintRight_toRightOf="parent"
        android:id="@+id/ed_username"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="密码:"
        android:textSize="30sp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/ed_username"
        android:id="@+id/tv_pwd"/>
    <EditText
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_marginRight="20dp"
         android:inputType="textPassword"
        app:layout_constraintTop_toBottomOf="@id/ed_username"
        app:layout_constraintLeft_toRightOf="@id/tv_pwd"
        app:layout_constraintRight_toRightOf="parent"
        android:id="@+id/ed_pwd"/>
    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="记住密码"
        android:textSize="20sp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/ed_pwd"
        android:id="@+id/check_pwd"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录"
        android:textSize="30sp"
        android:layout_marginTop="30dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/check_pwd"
        android:id="@+id/btn_login"/>



</androidx.constraintlayout.widget.ConstraintLayout>

 6、提示布局界面:

毕竟只是提示一下,所以就一个登录成功

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="登录成功"
        android:textSize="50sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

7、登录界面的逻辑处理代码:

 首先我们理一下思路,变量什么的、组件什么的先初始化好,然后添加一个按钮监听、先读取一下文件,如果有数据的话显示到编辑框中;在监听方法里面判断是否勾选记住密码,如果勾选了,我们执行插入数据函数,如果没有就执行删除函数;

package com.example.qqloginactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

//实现监听接口
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {

    //2.1 创建好变量
    EditText ed_username,ed_pwd;
    Button btn_login;
    CheckBox check_pwd;
    //创建好用户名和密码
    String username,password;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        initParams();
        //2.4 当程序启动时,如果数据存在,我们就显示到编辑框上
        String[] datas = Utils.readData(this);
        if(datas != null){
            ed_username.setText(datas[0]);
            ed_pwd.setText(datas[1]);
        }
    }
    //2.2 初始化各个变量,包括添加监听器
    private void initParams(){
        ed_username = findViewById(R.id.ed_username);
        ed_pwd = findViewById(R.id.ed_pwd);
        btn_login = findViewById(R.id.btn_login);
        check_pwd = findViewById(R.id.check_pwd);
        btn_login.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch(view.getId()){
            case R.id.btn_login:
                //2.5 注意,我们需要设置一个正确的密码,在让用户登录
                //获取到用户填写的数据
                username = ed_username.getText().toString();
                password = ed_pwd.getText().toString();
                if(password.equals("123456")){
                    //2.3 监听到用户按下按钮之后,我们判断是否勾选了复选框
                    if(check_pwd.isChecked()){
                        //如果勾选了,那么存储数据
                        Utils.appendData(this,username,password);
                    }else{
                        //否则,删除数据
                        Utils.deleteData(this);
                    }
                    //最后,打开我们的登录界面
                    Intent intent = new Intent(this,MainActivity.class);
                    startActivity(intent);
                }else{
                    Toast.makeText(this, "密码错误", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
}

而我们的登录提示页面是不需要写的;这里要注意我是实现的监听接口要给按钮写监听函数;

 

8、拓展:

当我们写好登录和数据存储之后,可以拓展一下,我们设计一个记住密码之后自动跳转的功能,也就是自动登录;

大家想一想,我这里提供一个参考,我们先要在布局文件里再添加一个复选框,表示我们要自动登录,于是复选框变成了两个:

<CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="记住密码"
        android:textSize="20sp"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="20dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/ed_pwd"
        app:layout_constraintRight_toLeftOf="@id/check_login"
        android:id="@+id/check_pwd"/>
    <CheckBox
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="自动登录"
        android:textSize="20sp"
        android:layout_marginTop="30dp"
        android:layout_marginRight="20dp"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/ed_pwd"
        app:layout_constraintLeft_toRightOf="@id/check_pwd"
        android:id="@+id/check_login"/>

其实别看是一个拓展,可是别想当然我加一个Boolean就可以,大错特错!

我们可是重启项目,无法保存你的Boolean,有人就说我们存到文件里,对,但是存一个Boolean还要定另一个变量来存储,麻烦,我给大家一个建议,就直接存字符串,“true”和“false”然后使用字符串判断就可以: 

我定义一个变量flag,存字符串true和false还更简单,因为我们后面读取数据的时候就可以:

   //1.2 读取数据,因为含有多个数据,所以我们使用数组存储
    public static String[] readData(Context context){
        //1.5 同样新建一个数据存储对象,获取到我们存储的数据
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //判断是否数据为空
        String username=sp.getString("username",null);
        String password=sp.getString("password",null);
        String flag = sp.getString("flag",null);
        String[] datas;
        if(username == null){
            //如果没有数据就返回null
            return null;
        }else{
            //读取数据
            datas = new String[3];
            datas[0]=username;
            datas[1]=password;
            datas[2]=flag;
            return datas;
        }

    }

但是,我们添加了之后又怎么判断用户勾选了自动登录呢?如果用户没有勾选我们又怎么处理呢?

别慌,我这里专门准备了一个更改数据的方法,同样放在utils类里面:

    //1.4 更新自动登录
    public static void updateLogin(Context context,String flag){
        //1.6 同样新建一个数据存储对象,获取到我们存储的数据
        SharedPreferences sp = context.getSharedPreferences("data",Context.MODE_PRIVATE);
        //创建一个文件编辑对象
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(flag);
        editor.putString("flag",flag);
        editor.commit();
    }

 我们传入flag不就可以了,在判断到用户没有勾选的时候我修改一下flag的值就完美解决了;

那么我们的逻辑就变了,首先,我们登陆的时候先判断data文件是否存在,如果存在判断一下是否是自动登录,如果是那么自动登录一下;然后,当我们点击按钮的时候,判断密码是否正确,如果正确判断时候勾选了记住密码,如果勾选了,那么将数据存进去,注意我们有三个数据和,我们还没有判断是否勾选自动登录,于是我们存默认值flag为false,然后再判断是否勾选,然后将我们的flag的值更改,最后调用更行数值的函数就可以解决了,这里最怕一些老六会尝试各种办法让我的程序出bug,所以就严谨一点,于是代码变成了:

package com.example.qqloginactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

//实现监听接口
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {

    //2.1 创建好变量
    EditText ed_username,ed_pwd;
    Button btn_login;
    CheckBox check_pwd,check_login;
    //创建好用户名和密码,外加一个判断是否自动登录
    String username,password,flag;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        initParams();
        //2.4 当程序启动时,如果数据存在,我们就显示到编辑框上
        String[] datas = Utils.readData(this);
        if(datas != null){
            ed_username.setText(datas[0]);
            ed_pwd.setText(datas[1]);
            //如果数据存在,自动跳转
            if(datas[2].equals("true")){
                check_login.setChecked(true);
                jump();
            }

        }else{
            //如果数据不存在,不跳转且将自动登录变为false
            check_login.setChecked(false);
        }
    }
    //2.2 初始化各个变量,包括添加监听器
    private void initParams(){
        ed_username = findViewById(R.id.ed_username);
        ed_pwd = findViewById(R.id.ed_pwd);
        btn_login = findViewById(R.id.btn_login);
        check_pwd = findViewById(R.id.check_pwd);
        check_login = findViewById(R.id.check_login);
        btn_login.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch(view.getId()){
            case R.id.btn_login:
                //2.5 注意,我们需要设置一个正确的密码,在让用户登录
                //获取到用户填写的数据
                username = ed_username.getText().toString();
                password = ed_pwd.getText().toString();
                if(password.equals("123456")){
                    //2.3 监听到用户按下按钮之后,我们判断是否勾选了复选框
                    if(check_pwd.isChecked()){
                        //如果勾选了,那么存储数据
                        Utils.appendData(this,username,password,flag);
                        if(check_login.isChecked()){
                            flag = "true";
                        }else{
                            flag = "false";
                        }
                        Utils.updateLogin(this,flag);
                    }else{
                        //否则,删除数据
                        Utils.deleteData(this);
                    }
                    jump();
                }else{
                    Toast.makeText(this, "密码错误", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
    //2.6 封装跳转方法
    private void jump(){
        //最后,打开我们的登录界面
        Intent intent = new Intent(this,MainActivity.class);
        startActivity(intent);
    }
}

最后完美运行:

好了,那么这一期就到这,学会了就快去试试吧。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

编程学渣ズ

谢谢老板

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

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

打赏作者

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

抵扣说明:

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

余额充值