最近一個android小程序需要登錄功能,我簡單實現(xiàn)了一下?,F(xiàn)在記錄下來也當做個筆記,同時也希望可以相互學習。所以,如果我的代碼有問題,還各位請?zhí)岢鰜?。多謝了!
下面,就簡述一下此實例的主要內(nèi)容:
輸入用戶名和密碼 ,從本地文件userinfo.json中讀取users。判斷此用戶名是否在users中,如果不在則加入users,每次退出Activity都使用AES算法加密users,然后保存到userinfo.json中。用戶名下拉菜單是由PopupWindow + ListView 實現(xiàn)。
運行效果圖:
主要的代碼:
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(); // 把字符串轉(zhuǎn)換成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; // 登錄內(nèi)容的容器
private LinearLayout mUserIdLinearLayout; // 將下拉彈出窗口在此容器下方顯示
private Animation mTranslate; // 位移動畫
private Dialog mLoginingDlg; // 顯示正在登錄的Dialog
private EditText mIdEditText; // 登錄ID編輯框
private EditText mPwdEditText; // 登錄密碼編輯框
private ImageView mMoreUser; // 下拉圖標
private Button mLoginButton; // 登錄按鈕
private ImageView mLoginMoreUserView; // 彈出下拉彈出窗的按鈕
private String mIdString;
private String mPwdString;
private ArrayList<User> mUsers; // 用戶列表
private ListView mUserIdListView; // 下拉彈出窗顯示的ListView對象
private MyAapter mAdapter; // ListView的監(jiān)聽器
private PopupWindow mPop; // 下拉彈出窗
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
setListener();
mLoginLinearLayout.startAnimation(mTranslate); // Y軸水平移動
/* 獲取已經(jīng)保存好的用戶密碼 */
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); // 必須脫離父子關(guān)系,不然會報錯
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);// 設置彈出窗口消失時監(jiān)聽器
// 注意要加這句代碼,點擊彈出窗口其它區(qū)域才會讓窗口消失
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關(guān)聯(lián)的當前窗口的屬性,從而設置它在屏幕中顯示的位置
// 獲取屏幕的高寬
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外部任意區(qū)域關(guān)閉Dialog
}
/* 顯示正在登錄對話框 */
private void showLoginingDlg() {
if (mLoginingDlg != null)
mLoginingDlg.show();
}
/* 關(guān)閉正在登錄對話框 */
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沒有登錄到web服務器,所以效果可能看不出.可以結(jié)合情況使用
Log.i(TAG, mIdString + " " + mPwdString);
if (mIdString == null || mIdString.equals("")) { // 賬號為空時
Toast.makeText(LoginActivity.this, "請輸入賬號", Toast.LENGTH_SHORT)
.show();
} else if (mPwdString == null || mPwdString.equals("")) {// 密碼為空時
Toast.makeText(LoginActivity.this, "請輸入密碼", Toast.LENGTH_SHORT)
.show();
} else {// 賬號和密碼都不為空時
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();// 關(guān)閉對話框
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();
}
}
}
其他一些布局和資源配置我就不詳細列出了,想看的可以下載 源碼
更多建議: