NetworkOnMainThreadException เกิดขึ้นเมื่อแอปพยายามทำ Network Operation (เช่น ดึงข้อมูลจากเว็บ) บน Main Thread (UI Thread) ซึ่ง Android ห้ามทำเช่นนี้ตั้งแต่ API Level 11 (Honeycomb) เป็นต้นไป เพื่อป้องกัน UI Freeze
วิธีแก้: ใช้ AsyncTask (Deprecated) หรือ Thread/Executor/RxJava/Coroutines
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
Android Studio → File → New Project
ขั้นตอนที่ 2: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="8dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/textLoad"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp"
android:textStyle="bold|italic" />
<TextView
android:id="@+id/textMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
ขั้นตอนที่ 3: MainActivity.java (ใช้ AsyncTask - แบบเก่า)
import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
public class MainActivity extends AppCompatActivity {
TextView textLoad, textMessage;
final String strMessage = "https://sites.google.com/site/androidersite/text.txt";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textLoad = findViewById(R.id.textLoad);
textMessage = findViewById(R.id.textMessage);
textLoad.setText("Loading...");
new MyTask().execute();
}
private class MyTask extends AsyncTask<Void, Void, Void> {
String result;
@Override
protected Void doInBackground(Void... voids) {
// ⚠️ Network Operation ต้องอยู่ใน doInBackground (Background Thread)
try {
URL url = new URL(strMessage);
BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
reader.close();
result = stringBuilder.toString();
} catch (IOException e) {
e.printStackTrace();
result = "Error: " + e.getMessage();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
// ✅ อัปเดต UI ได้ที่นี่ (Main Thread)
textMessage.setText(result);
textLoad.setText("Finished");
super.onPostExecute(aVoid);
}
}
}
ขั้นตอนที่ 4: AndroidManifest.xml (ต้องมี Internet Permission)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<uses-permission android:name="android.permission.INTERNET" />
<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>
⚠️ AsyncTask ถูก Deprecated แล้ว (API 30+) - ใช้วิธีใหม่แทน
ทางเลือกที่ 1: Kotlin Coroutines (แนะนำ)
// build.gradle
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
// ใน Activity
lifecycleScope.launch(Dispatchers.IO) {
try {
val url = URL("https://example.com/data.txt")
val result = url.readText()
withContext(Dispatchers.Main) {
textMessage.text = result
textLoad.text = "Finished"
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
textMessage.text = "Error: ${e.message}"
}
}
}
ทางเลือกที่ 2: Java Thread + Handler
new Thread(() -> {
try {
URL url = new URL(strMessage);
BufferedReader reader = new BufferedReader(
new InputStreamReader(url.openStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
String result = sb.toString();
// กลับมาที่ Main Thread
runOnUiThread(() -> {
textMessage.setText(result);
textLoad.setText("Finished");
});
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(() -> textMessage.setText("Error: " + e.getMessage()));
}
}).start();
ทางเลือกที่ 3: OkHttp (Library ยอดนิยม)
// build.gradle
implementation "com.squareup.okhttp3:okhttp:4.11.0"
// ใช้งาน
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://example.com/data.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
runOnUiThread(() -> textMessage.setText("Error: " + e.getMessage()));
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String result = response.body().string();
runOnUiThread(() -> {
textMessage.setText(result);
textLoad.setText("Finished");
});
}
});
สรุป
- ❌ ห้ามทำ Network บน Main Thread
- ✅ ใช้ Background Thread (Coroutine, Thread, RxJava, WorkManager)
- ✅ อัปเดต UI ต้องกลับมาที่ Main Thread (
runOnUiThread,withContext(Dispatchers.Main),onPostExecute) - ✅ อย่าลืม Permission
android.permission.INTERNET
การทดสอบ
รันแอป → จะแสดง "Loading..." → หลังโหลดเสร็จจะแสดงข้อความจาก URL และ "Finished"