1|0界面布局
布局其实很简单,用相对布局累起来就可以了,然后注册和记住密码这两个控件放在一个水平线性布局里
界面底部还设置了一个QQ一键登录的入口,可以直接用。
控件的ID命名有点乱
注意一下我在styles中把所有框颜色改成了白色(为了更好适配黑色背景),你也可以选择不改
2|0逻辑实现
2|1数据存储:
因为map正好key与value一一对应(即name与password一一对应),所以选择使用map来进行账号的保存。
而本地的存储是用的SharedPreference来实现的,但是由于SharedPreference无法直接对map进行存储,所以需要单独写一个方法来实现。
密码是用Base64做了一次转码操作,增强了一丢丢的安全性。
2|2主代码:
由于有一个保存密码功能,所以需要单独再使用SharedPreference来存储记住密码的账号啥的。同样也是使用Base64进行转码操作。
import android.content.Intent; import android.content.SharedPreferences; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Base64; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.bumptech.glide.Glide; import com.paul.notebook.Tools.Base64Activity; import com.paul.notebook.dataBase.userData; /** * 作者:created by 巴塞罗那的余晖 on 2019/3/10 18:35 * 邮箱:zhubaoluo@outlook.com * 不会写BUG的程序猿不是好程序猿,嘤嘤嘤 */ public class LoginActivity extends AppCompatActivity { //声明变量 private Boolean login_state=false; private TextView mregister; private ImageView mimageView; private ImageButton mimageButton; private EditText muesername, mpassword; private Button mconfirm; private userData data; private CheckBox checkBox; private String LOCAL_USER_NAME="paul"; private String portraitURL = "https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2281052020,3958255485&fm=27&gp=0.jpg"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); //找布局控件对应ID mimageView = findViewById(R.id.iv_1); mimageButton = findViewById(R.id.im_qq); muesername = findViewById(R.id.et_username); mpassword = findViewById(R.id.et_password); mconfirm = findViewById(R.id.btn_confirm); mregister = findViewById(R.id.btn_register); checkBox=findViewById(R.id.cb_rm); data=new userData(LoginActivity.this); //Glide.with(LoginActivity.this).load(portraitURL).into(mimageView); initLogin(); mregister.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { { if(data.getRegister(muesername.getText().toString(),mpassword.getText().toString())) { Toast.makeText(LoginActivity.this,"注册成功!",Toast.LENGTH_SHORT).show(); } else { Toast.makeText(LoginActivity.this,"注册失败!用户名重复或者为空!",Toast.LENGTH_SHORT).show(); } } } }); mconfirm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(data.verifyPassword(muesername.getText().toString(),mpassword.getText().toString())) { Intent intent=new Intent(LoginActivity.this, Base64Activity.class); saveLogin(login_state); startActivity(intent); //Toast.makeText(LoginActivity.this,muesername.getText().toString()+"欢迎您!",Toast.LENGTH_SHORT).show(); } else { Toast.makeText(LoginActivity.this,"登陆失败!请检查用户是否存在或者密码错误!",Toast.LENGTH_SHORT).show(); } } }); checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { login_state=isChecked; } }); } private void saveLogin(boolean flag) { SharedPreferences sharedPreferences = LoginActivity.this.getSharedPreferences("ACCOUNT_REMEMBER", MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); String secreat_name = muesername.getText().toString(); String secreat_password=mpassword.getText().toString(); if(sharedPreferences.getBoolean("flag",false)) { return; //验证通过,不需要再次保存了 } if(flag) { secreat_password=Base64.encodeToString(secreat_password.getBytes(),Base64.NO_WRAP); editor.putString("name",secreat_name); editor.putString("password", secreat_password); editor.putBoolean("flag", flag); editor.commit(); } else{ editor.clear(); editor.putString("name",secreat_name); editor.putBoolean("flag",false); editor.commit(); } } private void cleanState() { SharedPreferences sharedPreferences = LoginActivity.this.getSharedPreferences("ACCOUNT_REMEMBER", MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.clear(); editor.commit(); } private void initLogin() { SharedPreferences sharedPreferences=LoginActivity.this.getSharedPreferences("ACCOUNT_REMEMBER", MODE_PRIVATE); if(sharedPreferences.getBoolean("flag",false)){ String decode_password=sharedPreferences.getString("password",""); decode_password= new String(Base64.decode(decode_password.getBytes(),Base64.NO_WRAP)); muesername.setText(sharedPreferences.getString("name","")); mpassword.setText(decode_password); checkBox.setChecked(true); } else { muesername.setText(sharedPreferences.getString("name","")); checkBox.setChecked(false); } } }
2|3Base64测试
当时考虑到安全性问题所以就写了这个来测试Base64的加密解密,但是加密后无法通过解密获得原文,超级烦!!!
下面列出两个我遇到的(应该大部分就是这两个)问题。
1.字符串转换问题
当Base64解密的时候返回的是一个byte[],肯定需要转成字符串,所以我就直接使用了toString方法,结果发现转换出来的是@开头的一堆乱码。
在网上查阅资料后发现转换String有两种方法,一种是直接toString,还有一种是new String
toString()与new String ()用法区别 str.toString是调用了b这个object对象的类的toString方法。一般是返回这么一个String:[class name]@[hashCode]。 new String(str)是根据parameter是一个字节数组,使用java虚拟机默认的编码格式,将这个字节数组decode为对应的字符。若虚拟机默认的编码格式是ISO-8859-1,按照ascii编码表即可得到字节对应的字符。 什么时候用什么方法呢? new String()一般使用字符转码的时候,byte[]数组的时候 toString()将对象打印的时候使用 --------------------- 作者:火星码农 来源:CSDN 原文:https://blog.csdn.net/u014622411/article/details/45147363 版权声明:本文为博主原创文章,转载请附上博文链接!
2.编码方式选择问题
在网上看到的Base64基本使用方法都是直接传Base64.DEFAULT,使用默认编码方式来进行编码。看似没有问题,但是!!!如果字符串过长,比如80位,那么在转码的过程中会自动添加换行符,如果是和别的模块进行对接就会出现错误···
所以我们一般就强制设置成忽略所有换行符就OK了
具体五种参数的含义:
3.使用方法
3|0最终效果图(仅供参考,还是很丑的···)
背景、头像和QQ一键登录图片自己去到网上找一下就可以了,注意一下大小什么的,虽然用了fit_center属性。
__EOF__
本文链接:https://www.cnblogs.com/robotpaul/p/10541585.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
发表评论 取消回复