• 一口气看完口袋微博源码(二)之用户登录


    这一篇讲用户登录,步入正题,用户登录首先要写好安卓的界面部分,既然是登录,无外乎用户名,密码,是否记住,然后就是登录按钮,ok直接上代码:

    Xml代码  
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout  
    3.     xmlns:android="http://schemas.android.com/apk/res/android"  
    4.     android:orientation="vertical"  
    5.     android:gravity="center_horizontal"  
    6.     android:background="@drawable/back"  
    7.     android:layout_width="fill_parent"  
    8.     android:layout_height="fill_parent"  
    9.     >                           <!-- 声明垂直分布的线性布局 -->  
    10.     <LinearLayout  
    11.        android:orientation="horizontal"  
    12.        android:layout_gravity="center_horizontal"  
    13.        android:paddingTop="25px"  
    14.        android:layout_width="wrap_content"  
    15.        android:layout_height="wrap_content"  
    16.        >  
    17.        <TextView  
    18.            android:text="@string/tvUid"  
    19.            android:layout_width="100px"  
    20.            style="@style/text"  
    21.            android:layout_height="wrap_content"  
    22.            android:layout_gravity="center_vertical"  
    23.            />  
    24.        <EditText  
    25.            android:id="@+id/etUid"  
    26.            android:singleLine="true"  
    27.            android:layout_width="150px"  
    28.            android:layout_height="wrap_content"  
    29.            />  
    30.        </LinearLayout>  
    31.     <LinearLayout  
    32.        android:orientation="horizontal"  
    33.        android:layout_gravity="center_horizontal"  
    34.        android:layout_width="wrap_content"  
    35.        android:layout_height="wrap_content"  
    36.        >  
    37.        <TextView  
    38.            android:text="@string/tvPwd"  
    39.            android:layout_width="100px"  
    40.            style="@style/text"  
    41.            android:layout_height="wrap_content"  
    42.            android:layout_gravity="center_vertical"  
    43.            />  
    44.        <EditText  
    45.            android:id="@+id/etPwd"  
    46.            android:singleLine="true"  
    47.            android:password="true"  
    48.            android:layout_width="150px"  
    49.            android:layout_height="wrap_content"  
    50.            />  
    51.        </LinearLayout>  
    52.     <LinearLayout  
    53.        android:orientation="horizontal"  
    54.        android:gravity="center_horizontal"  
    55.        android:layout_width="wrap_content"  
    56.        android:layout_height="wrap_content"  
    57.        >                            
    58.        <CheckBox  
    59.            android:id="@+id/cbRemember"  
    60.            android:text="@string/cbRemember"  
    61.            android:layout_gravity="center_horizontal"  
    62.            android:checked="false"  
    63.            android:textColor="@color/character"  
    64.            android:layout_width="wrap_content"  
    65.            android:layout_height="wrap_content"  
    66.            />  
    67.    
    68.        <ImageButton  
    69.            android:id="@+id/ibExit"  
    70.            android:layout_width="60px"  
    71.            android:layout_height="60px"  
    72.            android:src="@drawable/exit" />  
    73.    
    74.        </LinearLayout>  
    75.     <LinearLayout  
    76.        android:orientation="horizontal"  
    77.        android:layout_gravity="center_horizontal"  
    78.        android:layout_width="wrap_content"  
    79.        android:layout_height="wrap_content"  
    80.        >                                         <!-- 声明于显示按钮的线性布局 -->  
    81.        <Button  
    82.            android:id="@+id/btnLogin"  
    83.            style="@style/button"  
    84.            android:layout_width="120px"  
    85.            android:layout_height="wrap_content"  
    86.            android:text="@string/btnLogin"  
    87.            />  
    88.        <Button  
    89.            android:id="@+id/btnReg"  
    90.            style="@style/button"  
    91.            android:layout_width="120px"  
    92.            android:layout_height="wrap_content"  
    93.            android:text="@string/btnReg"  
    94.            />  
    95.        </LinearLayout>  
    96. </LinearLayout>  

    接下来就是写对应布局的activity了,这里就只着重讲登录的实现流程了,因为相信大家对获取文本框数据和checkBox配合sharedPreference很了解了就不再赘述,当点击登录按钮的时候进入登录,登录的客户端的流程和前面讲的注册的流程是一样的,客户端把登录数据装到字符串里面,数据格式为请求头+用户名+”|”+密码,这个|是分割线。然后通过上文降到的MyConnection获取到与服务器的socket连接,然后通过这个连接的数据输出流向服务器发送数据,然后通过服务端返回的数据判断是否登录成功:

    Java代码  
    1. //方法:连接服务器进行登录  
    2.     public void login(){  
    3.     new Thread(){  
    4.         public void run(){  
    5.             Looper.prepare();  
    6.               try{  
    7.                   if(mc == null){  
    8.                      mc = new MyConnector(SERVER_ADDRESS, SERVER_PORT);  
    9.                   }  
    10.                   EditText etUid = (EditText)findViewById(R.id.etUid); //获得帐号EditText  
    11.                   EditText etPwd = (EditText)findViewById(R.id.etPwd); //获得密码EditText  
    12.                   String uid = etUid.getEditableText().toString().trim(); //获得输入的帐号  
    13.                   String pwd = etPwd.getEditableText().toString().trim(); //获得输入的密码  
    14.                   if(uid.equals("") || pwd.equals("")){     //判断输入是否为空  
    15.                      Toast.makeText(LoginActivity.this, "请输入帐号或密码!", Toast.LENGTH_SHORT).show();//输出提示消息  
    16.                      return;  
    17.                   }  
    18.                   String msg = "<#LOGIN#>"+uid+"|"+pwd;                //组织要返回的字符串  
    19.                   mc.dout.writeUTF(msg);                                  //发出消息  
    20.                   String receivedMsg = mc.din.readUTF();    //读取服务器发来的消息  
    21.                   pd.dismiss();  
    22.                   if(receivedMsg.startsWith("<#LOGIN_SUCCESS#>")){ //收到的消息为登录成功消息  
    23.                      receivedMsg = receivedMsg.substring(17);  
    24.                      String [] sa = receivedMsg.split("\|");  
    25.                      CheckBox cb = (CheckBox)findViewById(R.id.cbRemember);      //获得CheckBox对象  
    26.                      if(cb.isChecked()){  
    27.                          rememberMe(uid,pwd);  
    28.                      }  
    29.                      //转到功能面板  
    30.                      Intent intent = new Intent(LoginActivity.this,FunctionTabActivity.class);  
    31.                      intent.putExtra("uno", sa[0]);  
    32.                      startActivity(intent);                    //启动功能Activity  
    33.                      finish();  
    34.                   }  
    35.                   else if(msg.startsWith("<#LOGIN_FAIL#>")){                  //收到的消息为登录失败  
    36.                      Toast.makeText(LoginActivity.this, msg.substring(14), Toast.LENGTH_LONG).show();  
    37.                      Looper.loop();  
    38.                      Looper.myLooper().quit();  
    39.                   }  
    40.               }catch(Exception e){  
    41.                   e.printStackTrace();  
    42.               }  
    43.         }  
    44.     }.start();  
    45. }  
    46.    

    接下来我们转到服务端,看服务端执行情况,当服务器收到客户端<#LOGIN#>的请求头后,通过解析客户端发来的数据拿到用户名和密码,然后调用DBUtil.checkLogin()方法,校验用户,并返回校验结果,校验结果是ArrayList<String>的形式,其实很好理解,因为用户信息包括用户名,id,email,state等信息,我们来看看这个过程是怎么处理的:

    Java代码  
    1. //方法:检查用户名和密码是否正确  
    2.     public static ArrayList<String> checkLogin(String u_no,String u_pwd){  
    3.        ArrayList<String> result = new ArrayList<String>();  
    4.        Connection con = null;      //声明获取数据库连接  
    5.        PreparedStatement ps = null;                  //声明Statement对象  
    6.        ResultSet rs = null;               //声明ResultSet对象  
    7.        try{  
    8.            con = getConnection();      //获取数据库连接  
    9.            if(con == null){         //判断数据库连接对象是否  
    10.               result.add(CONNECTION_OUT);     //  
    11.               return result;  
    12.            }  
    13.            ps = con.prepareStatement("select u_no,u_name,u_email,u_state,h_id from user where u_no=? and u_pwd=?");  
    14.            ps.setString(1, u_no);             //设置预编译语句的参数  
    15.            ps.setString(2, u_pwd);            //设置预编译语句的参数  
    16.            rs = ps.executeQuery();  
    17.            if(rs.next()){              //判断结果集是否为空  
    18.               for(int i=1;i<=5;i++){  
    19.                   result.add(rs.getString(i));    //将结果集中数据存放到ArrayList中  
    20.               }  
    21.            }  
    22.            else{                    //如果数据库查无此人  
    23.               result.add(LOGIN_FAIL);  //返回登录出错信息  
    24.            }  
    25.        }catch(Exception e){  
    26.            e.printStackTrace();  
    27.        }  
    28.        finally{  
    29.            try{  
    30.               if(rs != null){  
    31.                   rs.close();  
    32.                   rs = null;  
    33.               }  
    34.            }catch(Exception e){  
    35.               e.printStackTrace();  
    36.            }  
    37.            try{  
    38.               if(ps != null){  
    39.                   ps.close();  
    40.                   ps = null;  
    41.               }  
    42.            }catch(Exception e){  
    43.               e.printStackTrace();  
    44.            }  
    45.            try{  
    46.               if(con != null){  
    47.                   con.close();  
    48.                   con = null;  
    49.               }  
    50.            }catch(Exception e){  
    51.               e.printStackTrace();  
    52.            }  
    53.        }  
    54.        return result;  
    55.     }  

    哦,原来是查询数据库,然后把数据装在一个list集合返回去,然后serverAgent把这些用户数据封装成一条格式化后的字符串,然后写给客户端:

    Java代码  
    1. if(msg.startsWith("<#LOGIN#>")){              //消息为登录  
    2.                   String content = msg.substring(9);        //获得消息内容  
    3.                   String [] sa = content.split("\|");  
    4.                   ArrayList<String> result = DBUtil.checkLogin(sa[0], sa[1]);  
    5.                   if(result.size()>1){        //登录成功  
    6.                      StringBuilder sb = new StringBuilder();  
    7.                      sb.append("<#LOGIN_SUCCESS#>");  
    8.                      for(String s:result){  
    9.                          sb.append(s);  
    10.                          sb.append("|");  
    11.                      }  
    12.                      String loginInfo = sb.substring(0,sb.length()-1);  
    13.                      dout.writeUTF(loginInfo);          //返回用户的基本信息         
    14.                   }  

    数据发给客户端了,所以我们又转回到客户端,看看客户端是怎么处理这些数据的。

    客户端判断服务端发过来的数据的消息头是不是<#LOGIN_SUCCESS#>,是的话获取后的数据然后跳转到FunctionTabActivity.java,同时用intent把这些数据带过去。如果消息头是<#LOGIN_FAIL#>则给用户一个友好提示,在处理失败消息的时候我们发现用到了一个不太熟悉的东西Looper:

    Java代码  
    1. Looper.loop();  
    2. Looper.myLooper().quit();  

    那这个Looper是个啥玩意呢,现在来科普一下:

    1. Looper类用来为一个线程开启一个消息循环。 
        默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。) 
        Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。 

    2. 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。 
        默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。 
    mainHandler = new Handler() 等价于new Handler(Looper.myLooper()). 
    Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。 

    3. 在非主线程中直接new Handler() 会报如下的错误: 
    AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception 
    AndroidRuntime( 6173): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 
    原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。 

    4. Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。 

        注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。 

    5. 基于以上知识,可实现主线程给子线程(非主线程)发送消息。

    到现在,用户登录一个模块我们已经学习完了,需要详细请看代码。

  • 相关阅读:
    Linux下面编译安装ffmpeg
    Fidder简单使用方法(HTTPS抓取和url替换)
    关于一下个阶段的计划
    JAVA的随机的字符串的封装(基本上够用了)
    Shell Script中的间接变量引用
    进程概念
    int main(int argc, char *argv[])的解读
    存储数组数据到SharedPreferences
    C语言中的基本声明
    C中关于指针数组的用法
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/4171801.html
Copyright © 2020-2023  润新知