APP登錄註冊 步驟三:客戶端

聲明:
開發平臺:AS 3.5
JDK版本:1.8
MySQL版本:5.7
JDBC驅動:mysql-connector-java-5.1.47.jar

1、項目架構:

在這裏插入圖片描述

MainSecondActivity 是 APP 入口程序;
Android 上發送 HTTP請求的方式一般有兩種:HttpURLConnection 和 HttpClient !
HttpClientActivity 以及 HttpUrlConnection 這兩個 Activity 是用來測試 Android 和 Service 的交互之GET方式,這兩個可以不寫!

Android 和服務器進行交互,必然要使用到網絡,在AndroidManifest 中添加權限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

將這三個 jar 包添加到 app/libs 下:
在這裏插入圖片描述

2、MainSecondActivity及其佈局:

public class MainSecondActivity extends AppCompatActivity {

    private Button mBtnGet,mBtnGet2;
    private Button mBtnClient;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_second);

        mBtnGet=findViewById(R.id.mBtnGet);
        mBtnGet2=findViewById(R.id.mBtnGet2);
        mBtnClient=findViewById(R.id.mBtnClient);
        OnClick onClick=new OnClick();
        mBtnGet.setOnClickListener(onClick);
        mBtnGet2.setOnClickListener(onClick);
        mBtnClient.setOnClickListener(onClick);
    }

    class OnClick implements View.OnClickListener{

        Intent intent=null;
        @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.mBtnGet:
                    intent=new Intent(MainSecondActivity.this, HttpUrlConnection.class);
                    break;
                case R.id.mBtnGet2:
                    intent=new Intent(MainSecondActivity.this, HttpClientActivity.class);
                    break;
                case R.id.mBtnClient:
                    intent=new Intent(MainSecondActivity.this, ClientActivity.class);
                    break;
            }
            startActivity(intent);
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp"
    tools:context=".second_try.MainSecondActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Android 和 Service 的交互之GET方式:"
        android:textSize="20sp"
        android:gravity="center_horizontal"/>
    <Button
        android:id="@+id/mBtnGet"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textAllCaps="false"
        android:text="HttpURLConnection 進行 HTTP 請求"/>
    <Button
        android:id="@+id/mBtnGet2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textAllCaps="false"
        android:text="HttpClient 進行 HTTP 請求"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="10dp"
        android:background="@color/colorPrimaryDark"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="10dp"/>
    <Button
        android:id="@+id/mBtnClient"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textAllCaps="false"
        android:text="客戶端"/>
</LinearLayout>

3、HttpClientActivity 及其佈局:

public class HttpClientActivity extends AppCompatActivity {
    private TextView tvContent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_http_client);
        tvContent=findViewById(R.id.tv_content2);
        requestUsingHttpClient();
    }

    // 同樣的消息機制
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                tvContent.setText(msg.obj.toString());
            }
        }
    };

    private void requestUsingHttpClient() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpClient client = new DefaultHttpClient(); // HttpClient 是一個接口,無法實例化,所以我們通常會創建一個DefaultHttpClient實例
                HttpGet get = new HttpGet("https://www.baidu.com"); // 發起GET請求就使用HttpGet,發起POST請求則使用HttpPost,這裏我們先使用HttpGet
                try {
                    HttpResponse httpResponse = client.execute(get); // 調用HttpClient對象的execute()方法
                    // 狀態碼200說明響應成功
                    if (httpResponse.getStatusLine().getStatusCode() == 200) {
                        HttpEntity entity = httpResponse.getEntity(); // 取出報文的具體內容
                        String response = EntityUtils.toString(entity, "utf-8"); // 報文編碼

                        // 發送消息
                        Message msg = new Message();
                        msg.what = 1;
                        msg.obj = response;
                        handler.sendMessage(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    tools:context=".second_try.HttpUrlConnection">

    <TextView
        android:id="@+id/tv_content2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

4、HttpUrlConnection 及其佈局:

public class HttpUrlConnection extends AppCompatActivity {

    private TextView tvContent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_http_url_connection);
        tvContent=findViewById(R.id.tv_content);
        requestUsingHttpURLConnection();
    }

    /**
     * 消息處理
     */
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 1){
                tvContent.setText(msg.obj.toString());
            }
        }
    };
    private void requestUsingHttpURLConnection() {
        // 網絡通信屬於典型的耗時操作,開啓新線程進行網絡請求
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL("https://www.baidu.com"); // 聲明一個URL,注意——如果用百度首頁實驗,請使用https
                    connection = (HttpURLConnection) url.openConnection(); // 打開該URL連接
                    connection.setRequestMethod("GET"); // 設置請求方法,“POST或GET”,我們這裏用GET,在說到POST的時候再用POST
                    connection.setConnectTimeout(8000); // 設置連接建立的超時時間
                    connection.setReadTimeout(8000); // 設置網絡報文收發超時時間
                    InputStream in = connection.getInputStream();  // 通過連接的輸入流獲取下發報文,然後就是Java的流處理
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null){
                        response.append(line);
                    }
/**
 * 因爲網絡請求是在新開的子線程中運行,不能直接拿到結果就給 TextView 賦值!
 * 可以用Android 的Handler消息機制
 */
                    Message msg = new Message();
                    msg.what = 1;
                    msg.obj = response.toString();
                    Log.e("WYJ", response.toString());
                    handler.sendMessage(msg);
//                    tvContent.setText(response.toString()); // 地雷
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    tools:context=".second_try.HttpUrlConnection">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

此時可以在模擬器運行一下,如果成功,會顯示一大堆編碼

然後進入正題:

5、連接常量類 Constant 設置:

/**
 * 使用localhost會報錯
 * 原來模擬器默認把127.0.0.1和localhost當做本身了,
 * 在模擬器上可以用10.0.2.2代替127.0.0.1和localhost;
 * 另外如果是在局域網環境(手機wifi連接電腦熱點),
 * 可以用 192.168.0.x或者192.168.1.x(根據具體配置)連接本機,這樣應該就不會報錯了
 */
public class Constant {
    //保證和服務端的訪問地址一致,同時,服務端要一直開着,即那邊要一直處於運行狀態
    public static String URL = "http://10.0.2.2:8089/Servlet/"; // IP地址、端口號要注意

    public static String URL_Register = URL + "RegisterServlet";
    public static String URL_Login = URL + "LoginServlet";
}

6、輸入字符串的判空類 StringUtil :

public class StringUtil {
    public static boolean isEmpty(String xx) {
        return xx == null || "".equals(xx);
    }
}

7、登錄註冊的 Activity 以及其佈局:

public class ClientActivity extends Activity {

    private EditText etAccount;
    private EditText etPassword;
    private TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);

        etAccount = (EditText) findViewById(R.id.et_account);
        etPassword = (EditText) findViewById(R.id.et_password);
        tvResult = (TextView) findViewById(R.id.tv_result);

        Button btnRegister = findViewById(R.id.btn_register);
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!StringUtil.isEmpty(etAccount.getText().toString())
                        && !StringUtil.isEmpty(etPassword.getText().toString())) {
                    Log.e("WYJ", "都不空");
                    register(etAccount.getText().toString(), etPassword.getText().toString());
                } else {
                    Toast.makeText(ClientActivity.this, "賬號、密碼都不能爲空!", Toast.LENGTH_SHORT).show();
                }
            }
        });

        Button btnLogin = (Button) findViewById(R.id.btn_login);
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!StringUtil.isEmpty(etAccount.getText().toString())
                        && !StringUtil.isEmpty(etPassword.getText().toString())) {
                    Log.e("WYJ", "登錄都不空");
                    login(etAccount.getText().toString(), etPassword.getText().toString());
                } else {
                    Toast.makeText(ClientActivity.this, "賬號、密碼都不能爲空!", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    private void register(String account, String password) {
        String registerUrlStr = Constant.URL_Register + "?account=" + account + "&password=" + password;
        new MyAsyncTask(tvResult).execute(registerUrlStr);
    }

    private void login(String account, String password) {
        String registerUrlStr = Constant.URL_Login + "?account=" + account + "&password=" + password;
        new MyAsyncTask(tvResult).execute(registerUrlStr);
    }

    /**
     * AsyncTask就是一個封裝過的後臺任務類,顧名思義就是異步任務,其實現原理也是基於異步消息處理機制,
     * 只是 Android給我們做了很好的封裝而已,相對於 Handler 更輕量,適用於簡單的異步處理,
     * 但是在面對多個異步任務更新同一個或同一組 UI 時的同步就比較困難
     */
    /**
     * AsyncTask類的三個泛型參數:
     * (1)Param 在執行AsyncTask是需要傳入的參數,可用於後臺任務中使用
     * (2)後臺任務執行過程中,如果需要在UI上先是當前任務進度,則使用這裏指定的泛型作爲進度單位
     * (3)任務執行完畢後,如果需要對結果進行返回,則這裏指定返回的數據類型
     */
    public static class MyAsyncTask extends AsyncTask<String, Integer, String> {

        private TextView tv; // 舉例一個UI元素,後邊會用到

        public MyAsyncTask(TextView v) {
            tv = v;
        }

        @Override
        protected void onPreExecute() {
            Log.w("WYJ", "task onPreExecute()");
        }

        /**
         * @param params 這裏的params是一個數組,即AsyncTask在激活運行是調用execute()方法傳入的參數
         */
        @Override
        protected String doInBackground(String... params) {
            Log.w("WYJ", "task doInBackground()");
            HttpURLConnection connection = null;
            StringBuilder response = new StringBuilder();
            try {
                URL url = new URL(params[0]); // 聲明一個URL,注意如果用百度首頁實驗,請使用https開頭,否則獲取不到返回報文
                connection = (HttpURLConnection) url.openConnection(); // 打開該URL連接
                connection.setRequestMethod("GET"); // 設置請求方法,“POST或GET”,我們這裏用GET,在說到POST的時候再用POST
                connection.setConnectTimeout(80000); // 設置連接建立的超時時間
                connection.setReadTimeout(80000); // 設置網絡報文收發超時時間
                InputStream in = connection.getInputStream();  // 通過連接的輸入流獲取下發報文,然後就是Java的流處理
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String line;
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return response.toString(); // 這裏返回的結果就作爲onPostExecute方法的入參
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            // 如果在doInBackground方法,那麼就會立刻執行本方法
            // 本方法在UI線程中執行,可以更新UI元素,典型的就是更新進度條進度,一般是在下載時候使用
        }

        /**
         * 運行在UI線程中,所以可以直接操作UI元素
         * @param s
         */
        @Override
        protected void onPostExecute(String s) {
            Log.w("WYJ", "task onPostExecute()");
            tv.setText(s);
        }

    }
}
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="20dp"
    tools:context=".second_try.ClientActivity">

    <EditText
        android:id="@+id/et_account"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入賬號" />

    <EditText
        android:id="@+id/et_password"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="請輸入登錄密碼"
        android:inputType="textPassword" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_register"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Register" />

        <Button
            android:id="@+id/btn_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Login" />

    </LinearLayout>

    <!-- 用來顯示報文返回結果 -->
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

8、運行測試:

在這裏插入圖片描述

至此,一個 APP服務端客戶端的登陸註冊的小 Demo 已經完畢!

學習不易~
在這裏插入圖片描述

♥ 喜 歡 請 點 贊 喲 ♥
(●ˇ∀ˇ●)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章