Android 實現登入介面和功能例項
阿新 • • 發佈:2019-01-03
最近一個android小程式需要登入功能,我簡單實現了一下。現在記錄下來也當做個筆記,同時也希望可以相互學習。所以,如果我的程式碼有問題,還各位請提出來。多謝了!
下面,就簡述一下此例項的主要內容:
輸入使用者名稱和密碼 ,從本地檔案userinfo.json中讀取users。判斷此使用者名稱是否在users中,如果不在則加入users,每次退出Activity都使用AES演算法加密users,然後儲存到userinfo.json中。使用者名稱下拉選單是由PopupWindow + ListView 實現。
執行效果圖:
主要的程式碼:
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; // 登入密碼編輯框
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的監聽器
private PopupWindow mPop; // 下拉彈出窗
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
setListener();
mLoginLinearLayout.startAnimation(mTranslate); // Y軸水平移動
/* 獲取已經儲存好的使用者密碼 */
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沒有登入到web伺服器,所以效果可能看不出.可以結合情況使用
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();// 關閉對話方塊
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();
}
}
}
其他一些佈局和資源配置我就不詳細列出了,想看的可以下載 原始碼