Android 实现登录界面和功能实例

时间:2022-04-01 14:48:18

近期一个android小程序须要登录功能,我简单实现了一下。如今记录下来也当做个笔记,同一时候也希望能够相互学习。所以,假设我的代码有问题,还各位请提出来。多谢了!

以下。就简述一下此实例的主要内容:

输入username和password 。从本地文件userinfo.json中读取users。推断此username是否在users中,假设不在则增加users,每次退出Activity都使用AES算法加密users。然后保存到userinfo.json中。username下拉菜单是由PopupWindow
+ ListView 实现。

执行效果图:

Android 实现登录界面和功能实例Android 实现登录界面和功能实例Android 实现登录界面和功能实例

基本的代码:

1、用户类User

package com.example.logindemo;

import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log; public class User {
private String mId;
private String mPwd;
private static final String masterPassword = "FORYOU"; // AES加密算法的种子
private static final String JSON_ID = "user_id";
private static final String JSON_PWD = "user_pwd";
private static final String TAG = "User"; public User(String id, String pwd) {
this.mId = id;
this.mPwd = pwd;
} public User(JSONObject json) throws Exception {
if (json.has(JSON_ID)) {
String id = json.getString(JSON_ID);
String pwd = json.getString(JSON_PWD);
// 解密后存放
mId = AESUtils.decrypt(masterPassword, id);
mPwd = AESUtils.decrypt(masterPassword, pwd);
}
} public JSONObject toJSON() throws Exception {
// 使用AES加密算法加密后保存
String id = AESUtils.encrypt(masterPassword, mId);
String pwd = AESUtils.encrypt(masterPassword, mPwd);
Log.i(TAG, "加密后:" + id + " " + pwd);
JSONObject json = new JSONObject();
try {
json.put(JSON_ID, id);
json.put(JSON_PWD, pwd);
} catch (JSONException e) {
e.printStackTrace();
}
return json;
} public String getId() {
return mId;
} public String getPwd() {
return mPwd;
}
}

2、保存和载入本地User列表

package com.example.logindemo;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONTokener; import android.content.Context;
import android.util.Log; public class Utils { private static final String FILENAME = "userinfo.json"; // 用户保存文件名称
private static final String TAG = "Utils"; /* 保存用户登录信息列表 */
public static void saveUserList(Context context, ArrayList<User> users)
throws Exception {
/* 保存 */
Log.i(TAG, "正在保存");
Writer writer = null;
OutputStream out = null;
JSONArray array = new JSONArray();
for (User user : users) {
array.put(user.toJSON());
}
try {
out = context.openFileOutput(FILENAME, Context.MODE_PRIVATE); // 覆盖
writer = new OutputStreamWriter(out);
Log.i(TAG, "json的值:" + array.toString());
writer.write(array.toString());
} finally {
if (writer != null)
writer.close();
} } /* 获取用户登录信息列表 */
public static ArrayList<User> getUserList(Context context) {
/* 载入 */
FileInputStream in = null;
ArrayList<User> users = new ArrayList<User>();
try { in = context.openFileInput(FILENAME);
BufferedReader reader = new BufferedReader(
new InputStreamReader(in));
StringBuilder jsonString = new StringBuilder();
JSONArray jsonArray = new JSONArray();
String line;
while ((line = reader.readLine()) != null) {
jsonString.append(line);
}
Log.i(TAG, jsonString.toString());
jsonArray = (JSONArray) new JSONTokener(jsonString.toString())
.nextValue(); // 把字符串转换成JSONArray对象
for (int i = 0; i < jsonArray.length(); i++) {
User user = new User(jsonArray.getJSONObject(i));
users.add(user);
} } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} return users;
}
}

3、AES加密/解密

package com.example.logindemo;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; public class AESUtils {
public static String encrypt(String seed, String cleartext)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
} public static String decrypt(String seed, String encrypted)
throws Exception {
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
} private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
sr.setSeed(seed);
kgen.init(128, sr);
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
} private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
new byte[cipher.getBlockSize()]));
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
} private static byte[] decrypt(byte[] raw, byte[] encrypted)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(
new byte[cipher.getBlockSize()]));
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
} private static String toHex(String txt) {
return toHex(txt.getBytes());
} private static String fromHex(String hex) {
return new String(toByte(hex));
} private static byte[] toByte(String hexString) {
int len = hexString.length() / 2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
16).byteValue();
return result;
} private static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2 * buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
} private final static String HEX = "0123456789ABCDEF"; private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
}
}

4、LoginActivity.java

package com.example.logindemo;

import java.util.ArrayList;

import android.app.Activity;
import android.app.Dialog;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.PopupWindow.OnDismissListener;
import android.widget.TextView;
import android.widget.Toast; public class LoginActivity extends Activity implements OnClickListener,
OnItemClickListener, OnDismissListener {
protected static final String TAG = "LoginActivity";
private LinearLayout mLoginLinearLayout; // 登录内容的容器
private LinearLayout mUserIdLinearLayout; // 将下拉弹出窗体在此容器下方显示
private Animation mTranslate; // 位移动画
private Dialog mLoginingDlg; // 显示正在登录的Dialog
private EditText mIdEditText; // 登录ID编辑框
private EditText mPwdEditText; // 登录password编辑框
private ImageView mMoreUser; // 下拉图标
private Button mLoginButton; // 登录button
private ImageView mLoginMoreUserView; // 弹出下拉弹出窗的button
private String mIdString;
private String mPwdString;
private ArrayList<User> mUsers; // 用户列表
private ListView mUserIdListView; // 下拉弹出窗显示的ListView对象
private MyAapter mAdapter; // ListView的监听器
private PopupWindow mPop; // 下拉弹出窗 @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
setListener();
mLoginLinearLayout.startAnimation(mTranslate); // Y轴水平移动 /* 获取已经保存好的用户password */
mUsers = Utils.getUserList(LoginActivity.this); if (mUsers.size() > 0) {
/* 将列表中的第一个user显示在编辑框 */
mIdEditText.setText(mUsers.get(0).getId());
mPwdEditText.setText(mUsers.get(0).getPwd());
} LinearLayout parent = (LinearLayout) getLayoutInflater().inflate(
R.layout.userifo_listview, null);
mUserIdListView = (ListView) parent.findViewById(android.R.id.list);
parent.removeView(mUserIdListView); // 必须脱离父子关系,不然会报错
mUserIdListView.setOnItemClickListener(this); // 设置点击事
mAdapter = new MyAapter(mUsers);
mUserIdListView.setAdapter(mAdapter); } /* ListView的适配器 */
class MyAapter extends ArrayAdapter<User> { public MyAapter(ArrayList<User> users) {
super(LoginActivity.this, 0, users);
} public View getView(final int position, View convertView,
ViewGroup parent) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(
R.layout.listview_item, null);
} TextView userIdText = (TextView) convertView
.findViewById(R.id.listview_userid);
userIdText.setText(getItem(position).getId()); ImageView deleteUser = (ImageView) convertView
.findViewById(R.id.login_delete_user);
deleteUser.setOnClickListener(new OnClickListener() {
// 点击删除deleteUser时,在mUsers中删除选中的元素
@Override
public void onClick(View v) { if (getItem(position).getId().equals(mIdString)) {
// 假设要删除的用户Id和Id编辑框当前值相等,则清空
mIdString = "";
mPwdString = "";
mIdEditText.setText(mIdString);
mPwdEditText.setText(mPwdString);
}
mUsers.remove(getItem(position));
mAdapter.notifyDataSetChanged(); // 更新ListView
}
});
return convertView;
} } private void setListener() {
mIdEditText.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s, int start, int before,
int count) {
mIdString = s.toString();
} public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
} public void afterTextChanged(Editable s) {
}
});
mPwdEditText.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s, int start, int before,
int count) {
mPwdString = s.toString();
} public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
} public void afterTextChanged(Editable s) {
}
});
mLoginButton.setOnClickListener(this);
mLoginMoreUserView.setOnClickListener(this);
} private void initView() {
mIdEditText = (EditText) findViewById(R.id.login_edtId);
mPwdEditText = (EditText) findViewById(R.id.login_edtPwd);
mMoreUser = (ImageView) findViewById(R.id.login_more_user);
mLoginButton = (Button) findViewById(R.id.login_btnLogin);
mLoginMoreUserView = (ImageView) findViewById(R.id.login_more_user);
mLoginLinearLayout = (LinearLayout) findViewById(R.id.login_linearLayout);
mUserIdLinearLayout = (LinearLayout) findViewById(R.id.userId_LinearLayout);
mTranslate = AnimationUtils.loadAnimation(this, R.anim.my_translate); // 初始化动画对象
initLoginingDlg();
} public void initPop() {
int width = mUserIdLinearLayout.getWidth() - 4;
int height = LayoutParams.WRAP_CONTENT;
mPop = new PopupWindow(mUserIdListView, width, height, true);
mPop.setOnDismissListener(this);// 设置弹出窗体消失时监听器 // 注意要加这句代码,点击弹出窗体其他区域才会让窗体消失
mPop.setBackgroundDrawable(new ColorDrawable(0xffffffff)); } /* 初始化正在登录对话框 */
private void initLoginingDlg() { mLoginingDlg = new Dialog(this, R.style.loginingDlg);
mLoginingDlg.setContentView(R.layout.logining_dlg); Window window = mLoginingDlg.getWindow();
WindowManager.LayoutParams params = window.getAttributes();
// 获取和mLoginingDlg关联的当前窗体的属性,从而设置它在屏幕中显示的位置 // 获取屏幕的高宽
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int cxScreen = dm.widthPixels;
int cyScreen = dm.heightPixels; int height = (int) getResources().getDimension(
R.dimen.loginingdlg_height);// 高42dp
int lrMargin = (int) getResources().getDimension(
R.dimen.loginingdlg_lr_margin); // 左右边沿10dp
int topMargin = (int) getResources().getDimension(
R.dimen.loginingdlg_top_margin); // 上沿20dp params.y = (-(cyScreen - height) / 2) + topMargin; // -199
/* 对话框默认位置在屏幕中心,所以x,y表示此控件到"屏幕中心"的偏移量 */ params.width = cxScreen;
params.height = height;
// width,height表示mLoginingDlg的实际大小 mLoginingDlg.setCanceledOnTouchOutside(true); // 设置点击Dialog外部随意区域关闭Dialog
} /* 显示正在登录对话框 */
private void showLoginingDlg() {
if (mLoginingDlg != null)
mLoginingDlg.show();
} /* 关闭正在登录对话框 */
private void closeLoginingDlg() {
if (mLoginingDlg != null && mLoginingDlg.isShowing())
mLoginingDlg.dismiss();
} @Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.login_btnLogin:
// 启动登录
showLoginingDlg(); // 显示"正在登录"对话框,由于此Demo没有登录到webserver,所以效果可能看不出.能够结合情况使用
Log.i(TAG, mIdString + " " + mPwdString);
if (mIdString == null || mIdString.equals("")) { // 账号为空时
Toast.makeText(LoginActivity.this, "请输入账号", Toast.LENGTH_SHORT)
.show();
} else if (mPwdString == null || mPwdString.equals("")) {// password为空时
Toast.makeText(LoginActivity.this, "请输入password", Toast.LENGTH_SHORT)
.show();
} else {// 账号和password都不为空时
boolean mIsSave = true;
try {
Log.i(TAG, "保存用户列表");
for (User user : mUsers) { // 推断本地文档是否有此ID用户
if (user.getId().equals(mIdString)) {
mIsSave = false;
break;
}
}
if (mIsSave) { // 将新用户增加users
User user = new User(mIdString, mPwdString);
mUsers.add(user);
} } catch (Exception e) {
e.printStackTrace();
}
closeLoginingDlg();// 关闭对话框
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
finish();
}
break;
case R.id.login_more_user: // 当点击下拉栏
if (mPop == null) {
initPop();
}
if (!mPop.isShowing() && mUsers.size() > 0) {
// Log.i(TAG, "切换为角向上图标");
mMoreUser.setImageResource(R.drawable.login_more_down); // 切换图标
mPop.showAsDropDown(mUserIdLinearLayout, 2, 1); // 显示弹出窗体
}
break;
default:
break;
} } @Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
mIdEditText.setText(mUsers.get(position).getId());
mPwdEditText.setText(mUsers.get(position).getPwd());
mPop.dismiss();
} /* PopupWindow对象dismiss时的事件 */
@Override
public void onDismiss() {
// Log.i(TAG, "切换为角向下图标");
mMoreUser.setImageResource(R.drawable.login_more_up);
} /* 退出此Activity时保存users */
@Override
public void onPause() {
super.onPause();
try {
Utils.saveUserList(LoginActivity.this, mUsers);
} catch (Exception e) {
e.printStackTrace();
}
} }

其它一些布局和资源配置我就不具体列出了,想看的能够下载    源代码