ภาพรวม
ตัวอย่างนี้แสดงวิธีเข้าถึง Context ใน Fragment อย่างถูกต้อง พร้อมแนะนำ Best Practices และการหลีกเลี่ยง Memory Leak
ขั้นตอนการสร้าง
ขั้นตอนที่ 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"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/linearlayout01"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#ccc"
android:orientation="vertical">
<fragment
android:name="com.example.myapplication.FirstFragment"
android:id="@+id/frag_1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:id="@+id/linearlayout02"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#eee"
android:orientation="vertical">
<fragment
android:name="com.example.myapplication.SecondFragment"
android:id="@+id/frag_2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
ขั้นตอนที่ 3: Activity หลัก (src/MainActivity.java)
package com.example.myapplication;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
ขั้นตอนที่ 4: Fragment แรก (src/FirstFragment.java)
package com.example.myapplication;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class FirstFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);
TextView textView = view.findViewById(R.id.text);
// วิธีที่ถูกต้อง: ใช้ requireContext() หรือ getContext()
textView.setText("Context: " + requireContext().getClass().getSimpleName());
return view;
}
}
ขั้นตอนที่ 5: Fragment ที่สอง (src/SecondFragment.java)
package com.example.myapplication;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class SecondFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
}
ขั้นตอนที่ 6: Layout Fragment (res/layout/fragment.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:textSize="30sp"
android:text="Click"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
วิธีเข้าถึง Context ใน Fragment
| เมธอด | คืนค่า | ใช้เมื่อไหร่ | ข้อควรระวัง |
|---|---|---|---|
| requireContext() | @NonNull Context | ต้องการ Context แน่นอน (API 23+) | Crash ถ้า Fragment ไม่ Attached |
| getContext() | @Nullable Context | อาจจะ null ได้ | ต้อง Null-check เสมอ |
| getActivity() | @Nullable Activity | ต้องการ Activity โดยเฉพาะ | อาจ null ได้ ต้อง Cast หากต้องการ Method เฉพาะ Activity |
| requireActivity() | @NonNull Activity | ต้องการ Activity แน่นอน (API 23+) | Crash ถ้าไม่ Attached |
| getApplicationContext() | Application Context | ต้องการ Context ที่อยู่นานกว่า Activity | ไม่เข้าถึง Theme/Resources ที่เป็น Activity-specific ได้ |
Best Practices
1. ใช้ requireContext() / requireActivity() (API 23+)
// ดี - Crash ทันทีถ้ามีปัญหา แทนที่จะ Silent Fail Context context = requireContext(); Activity activity = requireActivity();
2. หลีกเลี่ยงการเก็บ Context ไว้ใน Field
// ไม่ดี - Memory Leak
private Context savedContext;
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.savedContext = context; // Dangerous!
}
// ดี - ใช้ได้ตอนต้องการเท่านั้น
private void doSomething() {
Context context = requireContext(); // ได้ Context ปัจจุบันเสมอ
}
3. ใช้ Application Context สำหรับงานที่อยู่นาน
// สำหรับ SharedPreferences, Database, Service, BroadcastReceiver
Context appContext = requireContext().getApplicationContext();
SharedPreferences prefs = appContext.getSharedPreferences("prefs", Context.MODE_PRIVATE);
4. ใช้ View.getContext() ใน Listener/Callback
button.setOnClickListener(v -> {
Context context = v.getContext(); // Safe: View มี Context อยู่เสมอตอน Attached
Toast.makeText(context, "Clicked", Toast.LENGTH_SHORT).show();
});
Lifecycle และ Context
onAttach(Context) → Context พร้อมใช้งาน onCreate() → getContext() ใช้ได้ onCreateView() → getContext() ใช้ได้ onViewCreated() → getContext() ใช้ได้ onStart/onResume → getContext() ใช้ได้ onPause/onStop → getContext() ใช้ได้ (แต่ Activity อาจ Stopping) onDestroyView() → View ถูกทำลาย แต่ Context ยังมี onDetach() → Context = null หลังจากนี้
สรุป
- ใช้ requireContext() เป็นค่าเริ่มต้น (Null-safe, Crash-early)
- ใช้ getContext() เมื่อต้องการ Null-check เอง
- ใช้ requireActivity() เมื่อต้องการ Activity methods (startActivityForResult, getSupportFragmentManager, etc.)
- ใช้ getApplicationContext() สำหรับงาน Background/Long-lived
- อย่าเก็บ Context ไว้ใน Field เพื่อป้องกัน Memory Leak