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 已经完毕!

学习不易~
在这里插入图片描述

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