Hướng dẫn lập trình mạng trong Android - Android Networking
Xem thêm các chuyên mục:

Là một website được viết trên công nghệ web Flutter vì vậy hỗ trợ rất tốt cho người học, kể cả những người học khó tính nhất.
Hiện tại website đang tiếp tục được cập nhập nội dung cho phong phú và đầy đủ hơn. Mong các bạn nghé thăm và ủng hộ website mới của chúng tôi.


Trong Android lập trình mạng bao gồm gửi yêu cầu tới máy chủ và lấy dữ liệu trả về. Về cơ bản bạn có 2 API để làm việc với mạng:
Apache HttpClient:
- Đây là một thư viện mã nguồn mở cung cấp bởi Apache.
HttpURLConnection
- Đây là một API chính thức của Android, nó bắt đầu được đưa vào từ phiên bản Android 2.3, trước đó Android sử dụng Apache HttpClient để làm việc với mạng.

Để làm việc với mạng, yêu cầu bạn cần cấp một số quyền cho ứng dụng:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
android.permission.INTERNET:
- Khai báo permission (sự cho phép) này, cho phép ứng dụng của bạn sẽ có khả năng kết nối mạng.
android.permission.ACCESS_NETWORK_STATE:
- Cho phép ứng dụng của bạn kiểm tra trạng thái kết nối mạng của điện thoại.
Đoạn code sau đây kiểm tra điện thoại của người dùng có kết nối mạng không, phương thức trả về true nếu đã có kết nối và trả về false trong trường hợp ngược lại.
private boolean checkInternetConnection() {
ConnectivityManager connManager =
(ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
if (networkInfo == null) {
Toast.makeText(this, "No default network is currently active", Toast.LENGTH_LONG).show();
return false;
}
if (!networkInfo.isConnected()) {
Toast.makeText(this, "Network is not connected", Toast.LENGTH_LONG).show();
return false;
}
if (!networkInfo.isAvailable()) {
Toast.makeText(this, "Network not available", Toast.LENGTH_LONG).show();
return false;
}
Toast.makeText(this, "Network OK", Toast.LENGTH_LONG).show();
return true;
}
Theo mặc định khi bạn làm việc với mạng (network) trong Android, bạn nên tạo ra một thread mới để gửi và nhận dữ liệu trả về. Nếu bạn làm việc trên thread chính bạn sẽ nhận được lỗi android.os.NetworkOnMainThreadException, đây là chính sách mặc định của Android. Tuy nhiên bạn có thể ghi đè chính sách này của Android để có thể làm việc với Network trên thread chính.
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);

Theo khuyến nghị bạn nên tạo một class mở rộng từ AsyncTask<Params, Progress, Result>, class này không phải là một Thread, nó mở rộng từ Object, tuy nhiên khi thực thi nhiệm vụ (Gọi phương thức AsyncTask.execute(params)), nó tạo ra một Thread mới để thực thi phương thức doInBackground(params). Sau khi thread hoàn thành phương thức onPostExecute(result) sẽ được gọi.
Bạn có thể xem minh họa dưới đây:

Trong ví dụ này, bạn download ảnh và Json từ URL và hiển thị nó lên ImageView và TextView.

Tạo project AndroidNetworkingDemo:
- File > New > New Project > Empty Activity
- Name: AndroidNetworkingDemo
- Package name: org.o7planning.androidnetworkingdemo
- Language: Java

Bạn phải cấp quyền cho ứng dụng truy cập Internet và quyền kiểm tra trạng thái của mạng.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Thêm đoạn mã vào AndroidManifest.xml:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.o7planning.androidnetworkingdemo">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Giao diện ứng dụng:

Nếu bạn quan tâm đến các bước để thiết kế giao diện ứng dụng này xin hãy xem ở phần phụ lục phía cuối bài viết.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="171dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="18dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:contentDescription="Image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_launcher_foreground" />
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="186dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="19dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView">
<Button
android:id="@+id/button_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="Download Image" />
<Button
android:id="@+id/button_json"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:text="Download JSON" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Code:
IOUtils.java
package org.o7planning.androidnetworkingdemo;
import java.io.InputStream;
import java.io.Reader;
public class IOUtils {
public static void closeQuietly(InputStream in) {
try {
in.close();
}catch (Exception e) {
}
}
public static void closeQuietly(Reader reader) {
try {
reader.close();
}catch (Exception e) {
}
}
}
DownloadJsonTask.java
package org.o7planning.androidnetworkingdemo;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
// A task with String input parameter, and returns the result as String.
public class DownloadJsonTask
// AsyncTask<Params, Progress, Result>
extends AsyncTask<String, Void, String> {
private TextView textView;
public DownloadJsonTask(TextView textView) {
this.textView= textView;
}
@Override
protected String doInBackground(String... params) {
String textUrl = params[0];
InputStream in = null;
BufferedReader br= null;
try {
URL url = new URL(textUrl);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
int resCode = httpConn.getResponseCode();
if (resCode == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
br= new BufferedReader(new InputStreamReader(in));
StringBuilder sb= new StringBuilder();
String s= null;
while((s= br.readLine())!= null) {
sb.append(s);
sb.append("\n");
}
return sb.toString();
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(br);
}
return null;
}
// When the task is completed, this method will be called
// Download complete. Lets update UI
@Override
protected void onPostExecute(String result) {
if(result != null){
this.textView.setText(result);
} else{
Log.e("MyMessage", "Failed to fetch data!");
}
}
}
DownloadImageTask.java
package org.o7planning.androidnetworkingdemo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
// A task with String input parameter, and returns the result as bitmap.
public class DownloadImageTask
// AsyncTask<Params, Progress, Result>
extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
public DownloadImageTask(ImageView imageView) {
this.imageView= imageView;
}
@Override
protected Bitmap doInBackground(String... params) {
String imageUrl = params[0];
InputStream in = null;
try {
URL url = new URL(imageUrl);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");
httpConn.connect();
int resCode = httpConn.getResponseCode();
if (resCode == HttpURLConnection.HTTP_OK) {
in = httpConn.getInputStream();
} else {
return null;
}
Bitmap bitmap = BitmapFactory.decodeStream(in);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(in);
}
return null;
}
// When the task is completed, this method will be called
// Download complete. Lets update UI
@Override
protected void onPostExecute(Bitmap result) {
if(result != null){
this.imageView.setImageBitmap(result);
} else{
Log.e("MyMessage", "Failed to fetch data!");
}
}
}
MainActivity.java
package org.o7planning.androidnetworkingdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
private TextView textView;
private Button buttonImg;
private Button buttonJson;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.imageView = (ImageView) this.findViewById(R.id.imageView);
this.textView = (TextView) this.findViewById(R.id.textView);
this.buttonImg = (Button) this.findViewById(R.id.button_img);
this.buttonJson = (Button) this.findViewById(R.id.button_json);
this.buttonImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downloadAndShowImage(v);
}
});
this.buttonJson.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
downloadAndShowJson(v);
}
});
}
private boolean checkInternetConnection() {
// Get Connectivity Manager
ConnectivityManager connManager =
(ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
// Details about the currently active default data network
NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
if (networkInfo == null) {
Toast.makeText(this, "No default network is currently active", Toast.LENGTH_LONG).show();
return false;
}
if (!networkInfo.isConnected()) {
Toast.makeText(this, "Network is not connected", Toast.LENGTH_LONG).show();
return false;
}
if (!networkInfo.isAvailable()) {
Toast.makeText(this, "Network not available", Toast.LENGTH_LONG).show();
return false;
}
Toast.makeText(this, "Network OK", Toast.LENGTH_LONG).show();
return true;
}
// When user click on the "Download Image".
public void downloadAndShowImage(View view) {
boolean networkOK = this.checkInternetConnection();
if (!networkOK) {
return;
}
String imageUrl = "https://o7planning.org/download/static/default/demo-data/logo.png";
// Create a task to download and display image.
DownloadImageTask task = new DownloadImageTask(this.imageView);
// Execute task (Pass imageUrl).
task.execute(imageUrl);
}
// When user click on the "Download Json".
public void downloadAndShowJson(View view) {
boolean networkOK = this.checkInternetConnection();
if (!networkOK) {
return;
}
String jsonUrl = "https://o7planning.org/download/static/default/demo-data/company.json";
// Create a task to download and display json content.
DownloadJsonTask task = new DownloadJsonTask(this.textView);
// Execute task (Pass jsonUrl).
task.execute(jsonUrl);
}
}
Thêm ImageView, TextView vào giao diện.


Thêm các Button vào giao diện.


Sét đặt ID, Text cho các thành phần trên giao diện.
