Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ Context ใน Fragment

ภาพรวม

ตัวอย่างนี้แสดงวิธีเข้าถึง 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