Android如何通過手機獲取驗證碼來完成註冊功能
註冊很多app或者網路賬戶的時候,經常需要手機獲取驗證碼,來完成註冊,那時年少,只是覺得手機獲取驗證碼這件事兒很好玩,並沒有關心太多,她是如何實現的,以及她背後的故事到底是什麼樣子的,現在小編接手的這個專案裡面,就需要通過手機號進行註冊,並且手機號傳送相應的驗證碼,來完成註冊,那麼在一些應用app裡面到底是如何實現點選按鈕獲取驗證碼,來完成註冊這整個流程的呢?今天小編就以註冊為例,和小夥伴們分享一下,如何通過手機號獲取驗證碼來完成註冊的一整套流程以及如何採用正則表示式來驗證手機號碼是否符合電信、移動、聯通的規範。
首先我們需要做的第一步就是ApiClient裡面編寫獲取驗證碼的方法,具體程式碼如下:
<span style="font-size:18px;">/** * 說明:獲取驗證碼 * 作者:丁國華 * 時間:2015-8-27 下午5:47:36 */ public static String getValidateCode(AppContext appContext, Map<String, Object> map) throws AppException { // 定義要訪問的介面和要強轉的實體 String validateUrl = _MakeURL(URLs.VALIDATE_CODE_URL, map); ValidateCode validateCode = null; try { // 獲取伺服器端Json資料 String json = http_get(appContext, validateUrl); // 解析為制定的實體物件 validateCode = (ValidateCode) JSON.parseObject(json, ValidateCode.class); } catch (Exception e) { if (e instanceof AppException) throw (AppException) e; throw AppException.network(e); } // 返回驗證碼 return validateCode.getCode(); } </span>
第二步編寫AppContent裡面的介面方法,具體程式碼如下所示:
<span style="font-size:18px;">/** * 說明:獲取伺服器驗證碼(不需要快取) * 作者:丁國華 * @date 2015-8-28 上午9:07:14 */ public String getCode(Map<String, Object> map) throws AppException { String validateCode = ""; // 如果網路可連線且解析無誤返回正確的驗證碼,否則返回空字串 if (isNetworkConnected()) { try { validateCode = ApiClient.getValidateCode(this, map); } catch (AppException e) { if (validateCode == "") { throw e; } } } return validateCode; } </span>
第三步,在StringUtils裡面編寫驗證號碼是否是手機號的正則表示式,具體程式碼如下:
<span style="font-size:18px;"> /* 說明:移動:134、135、136、137、138、139、150、151、157(TD)、158、159、187、188
* 聯通:130、131、132、152、155、156、185、186
* 電信:133、153、180、189
* 總結起來就是第一位必定為1,第二位必定為3或5或8,其他位置的可以為0-9
* 驗證號碼 手機號 固話均可
* 作者:丁國華
* 2015年9月20日 13:52:35
*/
public static boolean isPhoneNumberValid(String phoneNumber) {
boolean isValid = false;
String expression = "((^(13|15|18)[0-9]{9}$)|(^0[1,2]{1}\\d{1}-?\\d{8}$)|(^0[3-9] {1}\\d{2}-?\\d{7,8}$)|(^0[1,2]{1}\\d{1}-?\\d{8}-(\\d{1,4})$)|(^0[3-9]{1}\\d{2}-? \\d{7,8}-(\\d{1,4})$))";
CharSequence inputStr = phoneNumber;
Pattern pattern = Pattern.compile(expression);
Matcher matcher = pattern.matcher(inputStr);
if (matcher.matches() ) {
isValid = true;
}
return isValid;
}
</span>
第四步:編寫xml裡面的檔案,具體程式碼如下所示:
<span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout style="@style/top_title_style" >
<Button
android:id="@+id/register_back_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@null"
android:drawableLeft="@drawable/back"
android:paddingLeft="5dp"
android:text=" 登入"
android:textColor="#FFFFFF"
android:textSize="18sp" />
<!-- 註冊的佈局 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_marginTop="2dp"
android:layout_weight="1"
android:gravity="center"
android:paddingLeft="4dp"
android:text="註冊"
android:textColor="#FFFFFF"
android:textSize="20sp" />
<!-- 註冊的佈局 -->
<TextView
android:id="@+id/nickname_confirm"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
android:gravity="center"
android:paddingLeft="60dp"
android:paddingRight="10dp"
android:textColor="#FFFFFF"
android:textSize="20sp" />
</LinearLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="45dp"
android:minHeight="50.0dip"
android:paddingLeft="14.0dip"
android:paddingRight="12.0dip" >
<ImageView
android:layout_width="23.0dip"
android:layout_height="23.0dip"
android:layout_centerVertical="true"
android:src="@drawable/user_picture" />
<EditText
android:id="@+id/et_register_username_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:background="@null"
android:hint="使用者名稱/手機號"
android:paddingLeft="15dip"
android:paddingTop="8dp"
android:textColorHint="#BEBEBE"
android:textSize="20sp" />
</RelativeLayout>
<View style="@style/PersonalLine" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="45dp"
android:minHeight="50.0dip"
android:paddingLeft="14.0dip"
android:paddingRight="12.0dip" >
<ImageView
android:layout_width="23.0dip"
android:layout_height="23.0dip"
android:layout_centerVertical="true"
android:src="@drawable/phone_picture" />
<EditText
android:id="@+id/et_register_code_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:background="@null"
android:hint="請輸入驗證碼"
android:paddingLeft="15dip"
android:paddingTop="8dp"
android:textColorHint="#BEBEBE"
android:textSize="20sp" />
<Button
android:id="@+id/bt_getcode_id"
android:layout_width="120dp"
android:layout_height="35dp"
android:layout_marginLeft="200dp"
android:layout_marginTop="5dp"
android:background="@drawable/shape1"
android:text="獲取驗證碼"
android:textColor="#FFFFFF"
android:textSize="10sp" />
</RelativeLayout>
<View style="@style/PersonalLine" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="45dp"
android:minHeight="50.0dip"
android:paddingLeft="14.0dip"
android:paddingRight="12.0dip" >
<ImageView
android:layout_width="23.0dip"
android:layout_height="23.0dip"
android:layout_centerVertical="true"
android:src="@drawable/lock" />
<EditText
android:id="@+id/et_register_password_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:background="@null"
android:hint="請輸入新密碼"
android:paddingLeft="15dip"
android:paddingTop="8dp"
android:textColorHint="#BEBEBE"
android:textSize="20sp" />
</RelativeLayout>
<View style="@style/PersonalLine" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<!-- 小對勾的佈局 -->
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginLeft="-10dp"
android:scaleX="0.8"
android:scaleY="0.8" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="我同意"
android:textSize="18sp" />
<TextView
android:id="@+id/user_protocol"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dp"
android:gravity="center"
android:text="使用者協議及隱私條款"
android:textColor="#FE8B4A"
android:textSize="18sp" />
</LinearLayout>
<Button
android:id="@+id/bt_register_id"
android:layout_width="245dp"
android:layout_height="45dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="14dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="5dp"
android:background="@drawable/shape2"
android:gravity="center"
android:text="注 冊"
android:textColor="#FFFFFF"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="80dp"
android:paddingTop="5dp"
android:text="您也可以直接登入"
android:textColor="#BEBEBE"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:baselineAligned="false"
android:gravity="center"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
<Button
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/weixin_login" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="微信登入"
android:textColor="#BEBEBE"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
<Button
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/weibo_login" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="微博登入"
android:textColor="#BEBEBE"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical" >
<Button
android:layout_width="60dp" android:layout_height="60dp" android:background="@drawable/qq_login" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="QQ登入"
android:textColor="#BEBEBE"
android:textSize="20sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout></span>
第五步:編寫java類RegisterActivity裡面的程式碼,具體如下所示:
<span style="font-size:18px;">package com.jczb.car.ui;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.jczb.car.AppContext;
import com.jczb.car.AppException;
import com.jczb.car.R;
import com.jczb.car.common.StringUtils;
/**
* 說明:註冊功能頁面 我們實現了取消執行緒的機制,從而保證它不會洩露 onDestroy()常常被用來在Activity推出前取消執行緒
* 作者: 吳利昌
* 時間: 2015-9-3上午9:19:15
*/
public class RegisterActivity extends Activity implements OnClickListener {
// 宣告用到的頁面控制元件
private EditText etRegisterName;
private EditText etCode;
private EditText etPassword;
private Button btCode;
private Button btRegister;
private TextView tvUserProtocol;
private Button btRegisterLoginBack;
// 定義變數
private String userName;
private String passWord;
public boolean isChange = false;
private boolean tag = true;
private int i = 60;
Thread thread = null;
/**客戶端輸入的驗證碼*/
private String valicationCode;
/**伺服器端獲取的驗證碼*/
private static String serverValicationCode;
/** 註冊時所帶的引數 */
private Map<String, Object> registerParams = new HashMap<String, Object>();
/** 獲取驗證碼時所帶的引數 */
private Map<String, Object> codeParams = new HashMap<String, Object>();
/** 註冊是否成功 */
private String regisgerStatus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.register);
initView();
}
/**
* 說明:初始化頁面控制元件和事件
* 作者: 吳利昌
* 時間: 2015-9-3 上午9:23:42
*/
public void initView() {
// 初始化控制元件
etRegisterName = (EditText) findViewById(R.id.et_register_username_id);
etCode = (EditText) findViewById(R.id.et_register_code_id);
etPassword = (EditText) findViewById(R.id.et_register_password_id);
btCode = (Button) findViewById(R.id.bt_getcode_id);
btRegister = (Button) findViewById(R.id.bt_register_id);
tvUserProtocol=(TextView)findViewById(R.id.user_protocol);
btRegisterLoginBack=(Button)findViewById(R.id.register_back_login);
// 初始化監聽事件
btCode.setOnClickListener(this);
btRegister.setOnClickListener(this);
tvUserProtocol.setOnClickListener(this);
btRegisterLoginBack.setOnClickListener(this);
}
private boolean isvalidate() {
// TODO Auto-generated method stub
// 獲取控制元件輸入的值
String userName = etRegisterName.getText().toString().trim();
if (StringUtils.isEmpty(userName)) {
Toast.makeText(this, "手機號不能為空", Toast.LENGTH_SHORT).show();
return false;
}
if (!StringUtils.isPhoneNumberValid(userName)) {
Toast.makeText(this, "手機號有誤", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_getcode_id:
if(!isvalidate())
break;
btCode.setText("獲取驗證碼");
btCode.setClickable(true);
isChange = true;
changeBtnGetCode();
getValidateCode();
break;
case R.id.bt_register_id:
register();
break;
case R.id.user_protocol:
Intent intentUserProtocol = new Intent(this,UserProtocolActivity.class);
startActivity(intentUserProtocol);
break;
case R.id.register_back_login:
this.finish();
break;
default:
break;
}
}
private void changeBtnGetCode() {
thread = new Thread() {
@Override
public void run() {
if (tag) {
while (i > 0) {
i--;
if (RegisterActivity.this == null) {
break;
}
RegisterActivity.this
.runOnUiThread(new Runnable() {
@Override
public void run() {
btCode.setText("獲取驗證碼("
+ i + ")");
btCode
.setClickable(false);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
tag = false;
}
i = 60;
tag = true;
if (RegisterActivity.this != null) {
RegisterActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
btCode.setText("獲取驗證碼");
btCode.setClickable(true);
}
});
}
};
};
thread.start();
}
/**
* 說明:獲取驗證碼
*
* 作者: 吳利昌
* 時間: 2015-9-3 下午3:26:55
*/
public boolean getValidateCode() {
String name = etRegisterName.getText().toString().trim();
String code = etCode.getText().toString().trim();
if (name.equals("")) {
Toast.makeText(this, "請輸入使用者名稱或手機號!", Toast.LENGTH_SHORT).show();
return false;
}else {
userName = name;
valicationCode = code;
Thread codeThread = new Thread(codeRunnable);
codeThread.start();
}
return true;
}
/**
* 說明:註冊
*
* 作者: 吳利昌
* 時間: 2015-9-3 下午3:27:23
*/
public void register() {
// 1.首先判斷輸入的值是否有效
// 2.然後判斷輸入的驗證碼是否有效(防止沒有點選獲取驗證碼自己填的錯誤驗證碼)
// 3.最後註冊
if (isValid()) {
if (valicationCode.equals(serverValicationCode)) {
Thread thread = new Thread(sRunnable);
thread.start();
}else {
Toast.makeText(this, "輸入的驗證碼不正確!", Toast.LENGTH_SHORT).show();
}
}
}
//--------------------------------獲取驗證碼執行緒處理過程---開始-----------------------------
/**
* 自定義一個靜態的具有弱引用的Handler,解決記憶體洩漏的問題,本handler用來獲取驗證碼
*/
private static class CodeHandler extends Handler {
// 持有對本外部類的弱引用
private final WeakReference<RegisterActivity> mActivity;
public CodeHandler(RegisterActivity activity) {
mActivity = new WeakReference<RegisterActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
// 獲取上下文物件
RegisterActivity activity = mActivity.get();
if (activity != null) {
switch (msg.what) {
case 1:
serverValicationCode = (String)msg.obj;
//activity.etCode.setText(serverValicationCode);
break;
case -1:
Toast.makeText(activity, "獲取驗證碼失敗!", Toast.LENGTH_SHORT).show();
break;
case 0:
Toast.makeText(activity, "哎呀,出錯啦..", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
}
/**例項化自定義的handler*/
private final CodeHandler codeHandler = new CodeHandler(this);
private String serverCode=null;
/**定義獲取驗證碼的子執行緒*/
private Runnable codeRunnable = new Runnable() {
@Override
public void run() {
Message msg = new Message();
Map<String, Object> map = new HashMap<String, Object>();
map.put("jbPhone", userName);
// 獲取全域性物件Application
AppContext appContext = (AppContext) getApplication();
try {
// 獲取伺服器資料
serverValicationCode = appContext.getCode(map);
// 返回true則將訊息的what值為1,為false則what為-1,異常為0
if (serverValicationCode.equals("")) {
msg.what = -1;
} else {
msg.what = 1;
msg.obj = serverValicationCode;
}
} catch (AppException e) {
msg.what = 0;
e.printStackTrace();
}
codeHandler.sendMessage(msg);
}
};
//--------------------------------獲取驗證碼執行緒處理過程----完成------------------------------
//--------------------------------註冊執行緒處理過程--開始----------------------------------
/**
* 自定義一個靜態的具有弱引用的Handler,解決記憶體洩漏的問題,註冊使用
*/
private static class MyHandler extends Handler {
// 持有對本外部類的弱引用
private final WeakReference<RegisterActivity> mActivity;
public MyHandler(RegisterActivity activity) {
mActivity = new WeakReference<RegisterActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
// 獲取上下文物件
RegisterActivity activity = mActivity.get();
if (activity != null) {
switch (msg.what) {
case 1:
Toast.makeText(activity, "註冊成功!", Toast.LENGTH_SHORT).show();
activity.finish();
break;
case -1:
Toast.makeText(activity, "註冊失敗!", Toast.LENGTH_SHORT).show();
break;
case -2:
Toast.makeText(activity, "該號已經註冊!", Toast.LENGTH_SHORT).show();
break;
case 0:
Toast.makeText(activity, "哎呀,出錯啦..", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
}
/**例項化自定義的handler*/
private final MyHandler mHandler = new MyHandler(this);
/**自定義子執行緒*/
private Runnable sRunnable = new Runnable() {
@Override
public void run() {
Message msg = new Message();
// 獲取全域性物件Application
AppContext appContext = (AppContext) getApplication();
try {
// 獲取伺服器資料
regisgerStatus = appContext.register(registerParams);
// 返回true則將訊息的what值為1,為false則what為-1,異常為0
if (regisgerStatus.equals("true")) {
msg.what = 1;
msg.obj = regisgerStatus;
} else if(regisgerStatus.equals("1")){
msg.what = -2;
}else if(regisgerStatus.equals("false")){
msg.what = -1;}
} catch (AppException e) {
msg.what = 0;
e.printStackTrace();
}
mHandler.sendMessage(msg);
}
};
//--------------------------------註冊執行緒處理過程---完成-----------------------------------
/**
* 說明:註冊之前判斷資料是否為空
*
* @return
* 作者: 吳利昌
* 時間: 2015-9-3 下午3:29:04
*/
public boolean isValid() {
userName = etRegisterName.getText().toString().trim();
valicationCode = etCode.getText().toString().trim();
passWord = etPassword.getText().toString().trim();
if (userName.equals("")) {
Toast.makeText(this, "使用者名稱不能為空!", Toast.LENGTH_SHORT).show();
return false;
}
if (valicationCode.equals("")) {
Toast.makeText(this, "驗證碼不能為空!", Toast.LENGTH_SHORT).show();
return false;
}
if(!serverValicationCode.equals(valicationCode))
{
Toast.makeText(this, "驗證碼錯誤", Toast.LENGTH_SHORT).show();
return false;
}
if (passWord.equals("")) {
Toast.makeText(this, "密碼不能為空!", Toast.LENGTH_SHORT).show();
return false;
} else if (passWord.length() < 6) {
Toast.makeText(this, "密碼至少6位!", Toast.LENGTH_SHORT).show();
return false;
}
registerParams.put("username", userName);
registerParams.put("psd", passWord);
return true;
}
}
</span>
最後,我們來執行一下,看看我們的效果,由於小編的genymotion不知道為什麼不能運行了,所以委屈小夥伴們一下,看不了動態圖片了,不過並不影響,我們首先用一個號碼好註冊一下,如下圖所示:
看一下手機收到的驗證碼:
最後來看一下,我們的註冊:
小編寄語:該博文,小編主要簡單的介紹瞭如何通過手機獲取驗證碼來完成註冊的功能,以及如何利用正則表示式來驗證碼手機號碼是否符合移動、聯通、電信。還是那句話對於小編來說,既是挑戰更是機遇,因為知識都是相通的,再者來說,在小編的程式人生中,留下最珍貴的記憶,雖然以後小編不一定從事安卓這個行業,程式碼世界裡,很多種事,有的甜蜜,有的溫馨,有的婉轉成歌,有的綿延不息,在這些故事裡,我們唯一的共通之處就是,某年,某月,某個波瀾不驚的日子裡,曾經很愛很愛你!愛你--這段實習的日子裡,安卓帶給小編的種種的驚喜。