欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android如何通过手机获取验证码来完成注册功能

程序员文章站 2023-11-28 22:00:22
注册很多app或者网络账户的时候,经常需要手机获取验证码,来完成注册,那时年少,只是觉得手机获取验证码这件事儿很好玩,并没有关心太多,她是如何实现的,以及她背后的故事到底是...

注册很多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不知道为什么不能运行了,所以委屈小伙伴们一下,看不了动态图片了,不过并不影响,我们首先用一个号码好注册一下,如下图所示:

Android如何通过手机获取验证码来完成注册功能

        看一下手机收到的验证码:   

Android如何通过手机获取验证码来完成注册功能

        最后来看一下,我们的注册:       

  Android如何通过手机获取验证码来完成注册功能

小编寄语:该博文,小编主要简单的介绍了如何通过手机获取验证码来完成注册的功能,以及如何利用正则表达式来验证码手机号码是否符合移动、联通、电信。还是那句话对于小编来说,既是挑战更是机遇,因为知识都是相通的,再者来说,在小编的程序人生中,留下最珍贵的记忆,虽然以后小编不一定从事安卓这个行业,代码世界里,很多种事,有的甜蜜,有的温馨,有的婉转成歌,有的绵延不息,在这些故事里,我们唯一的共通之处就是,某年,某月,某个波澜不惊的日子里,曾经很爱很爱你!爱你--这段实习的日子里,安卓带给小编的种种的惊喜。