ภาพรวม
ตัวอย่างนี้แสดงวิธีใช้ findViewById ใน Fragment อย่างถูกต้อง โดยสำคัญคือต้องเรียกผ่าน View ที่ inflate ไม่ใช่ผ่าน Activity
ขั้นตอนการสร้าง
ขั้นตอนที่ 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) {
// 1. Inflate Layout → ได้ root View
View rootView = inflater.inflate(R.layout.fragment, container, false);
// 2. ใช้ rootView.findViewById() ไม่ใช่ getActivity().findViewById()
TextView textView = rootView.findViewById(R.id.text);
textView.setText("First Fragment - Click Me");
// 3. Set Listener
textView.setOnClickListener(v -> {
// ทำงานเมื่อคลิก
});
return rootView;
}
}
ขั้นตอนที่ 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) {
// Inflate และ return ทันที (ไม่ต้อง findViewById ถ้าไม่ได้ใช้)
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>
หลักการสำคัญ: findViewById ใน Fragment
✅ ถูกต้อง
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment, container, false);
TextView tv = view.findViewById(R.id.text); // ใช้ View ที่ inflate
return view;
}
❌ ผิด - ใช้ Activity.findViewById()
// ไม่ดี - หา View ใน Activity Layout ไม่เจอ (Fragment มี Layout แยก) TextView tv = getActivity().findViewById(R.id.text); // Null หรือเจอ View ผิด
❌ ผิด - ใช้ findViewById() โดยตรง (ใน Fragment)
// Fragment ไม่มี findViewById() method (แค่ Activity และ View มี) TextView tv = findViewById(R.id.text); // Compile Error
ViewBinding (แนะนำสำหรับโปรเจกต์ใหม่)
// build.gradle (app)
android {
buildFeatures {
viewBinding true
}
}
// Fragment
private FragmentBinding binding;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
binding = FragmentBinding.inflate(inflater, container, false);
binding.textView.setText("Hello ViewBinding");
return binding.getRoot();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null; // ป้องกัน Memory Leak
}
DataBinding (ทางเลือกอื่น)
// build.gradle
buildFeatures {
dataBinding true
}
// Layout (layout/fragment.xml)
<layout>
<data>
<variable name="viewModel" type="com.example.MyViewModel"/>
</data>
<LinearLayout ...>
<TextView android:text="@{viewModel.title}" />
</LinearLayout>
</layout>
// Fragment
FragmentBinding binding = DataBindingUtil.inflate(inflater, R.layout.fragment, container, false);
binding.setViewModel(viewModel);
binding.setLifecycleOwner(this);
return binding.getRoot();
Lifecycle และ View Access
| Lifecycle Method | View Available | findViewById |
|---|---|---|
| onAttach() | ไม่ | ไม่ได้ |
| onCreate() | ไม่ | ไม่ได้ |
| onCreateView() | ✅ เริ่มมี | ✅ ผ่าน inflated View |
| onViewCreated() | ✅ | ✅ แนะนำทำที่นี่ |
| onStart/onResume | ✅ | ✅ |
| onPause/onStop | ✅ | ✅ |
| onDestroyView() | ❌ ถูกทำลาย | ❌ ห้ามใช้ |
| onDetach() | ไม่ | ไม่ได้ |
Best Practices
- ใช้ ViewBinding แทน findViewById (Type-safe, Null-safe, Fast)
- ทำการ findView/Setup UI ใน onViewCreated() ไม่ใช่ onCreateView()
- ตั้งค่า binding = null ใน onDestroyView()
- ไม่ใช้ getActivity().findViewById() ใน Fragment
- ใช้ requireView() (API 23+) ใน onViewCreated/onStart/onResume