Android 實現(xiàn)登錄界面和功能實例

2022-05-06 09:40 更新

Android 實現(xiàn)登錄界面和功能實例

最近一個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();
        }
    }

}

其他一些布局和資源配置我就不詳細列出了,想看的可以下載 源碼

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號