Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách sử dụng findViewById trong Fragment Android

Giới thiệu

Trong Fragment, findViewById() phải được gọi trên View root của Fragment (trong onCreateView hoặc onViewCreated), không phải trên Activity.

Các bước đúng

1. Inflate layout trong onCreateView

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate layout fragment
    View rootView = inflater.inflate(R.layout.fragment_layout, container, false);

    // Tìm view TRÊN rootView
    TextView textView = rootView.findViewById(R.id.myTextView);
    Button button = rootView.findViewById(R.id.myButton);

    // Thiết lập listener, dữ liệu...
    button.setOnClickListener(v -> textView.setText("Clicked!"));

    return rootView; // Trả về root view
}

2. Hoặc dùng onViewCreated (khuyên dùng)

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    // view ở đây là rootView đã inflate
    TextView tv = view.findViewById(R.id.myTextView);
    // ...
}

3. View Binding (Hiện đại, an toàn, khuyên dùng)

// build.gradle (app)
android {
    buildFeatures {
        viewBinding true
    }
}

// Fragment
private FragmentLayoutBinding binding;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    binding = FragmentLayoutBinding.inflate(inflater, container, false);
    return binding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    binding.myTextView.setText("Hello ViewBinding!");
    binding.myButton.setOnClickListener(v -> { ... });
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    binding = null; // QUAN TRỌNG: Giải phóng binding tránh leak
}

Sai lầm thường gặp

SaiĐúng
findViewById(R.id.x) trong onCreate()Dùng trong onCreateView/onViewCreated trên rootView
getActivity().findViewById(R.id.x)Chỉ dùng nếu view nằm trong Activity layout
Không check nullDùng ViewBinding hoặc check null
Giữ reference View sau onDestroyViewSet null trong onDestroyView

Ví dụ hoàn chỉnh (2 Fragment trong Activity)

Layout Activity (res/layout/activity_main.xml)

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:name="com.example.myapplication.FirstFragment"
        android:id="@+id/fragment_first"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <fragment
        android:name="com.example.myapplication.SecondFragment"
        android:id="@+id/fragment_second"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

FirstFragment.java

package com.example.myapplication;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class FirstFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_simple, container, false);
        TextView tv = root.findViewById(R.id.tvContent);
        tv.setText("Fragment 1 - findViewById trên rootView");
        return root;
    }
}

SecondFragment.java

package com.example.myapplication;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class SecondFragment extends Fragment {

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_simple, container, false);
        TextView tv = root.findViewById(R.id.tvContent);
        tv.setText("Fragment 2 - findViewById trên rootView");
        return root;
    }
}

Fragment Layout (res/layout/fragment_simple.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:padding="16dp" />

</LinearLayout>

MainActivity.java

package com.example.myapplication;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

public class MainActivity extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Chạy ứng dụng

Nhấn Run. Activity hiển thị 2 Fragment, mỗi Fragment tự tìm view trong layout của mình và set text.

Cách sử dụng findViewById trong Fragment Android

Tóm tắt quy tắc vàng

  1. Luôn inflate layout với container, false.
  2. Gọi rootView.findViewById(), không phải findViewById() hay getActivity().findViewById().
  3. Dùng View Binding cho type-safe, null-safe, performance tốt hơn.
  4. Dọn dẹp binding trong onDestroyView().