聲明:
開發平臺: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 已經完畢!
學習不易~
♥ 喜 歡 請 點 贊 喲 ♥ |
(●ˇ∀ˇ●) |