声明:
开发平台: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 已经完毕!
学习不易~
♥ 喜 欢 请 点 赞 哟 ♥ |
(●ˇ∀ˇ●) |