Mengapa saya ingin menghindari konstruktor non-default dalam fragmen?

173

Saya membuat aplikasi dengan Fragmentsdan di salah satunya, saya membuat konstruktor non-default dan mendapat peringatan ini:

Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead

Dapatkah seseorang memberi tahu saya mengapa ini bukan ide yang baik?

Bisakah Anda menyarankan bagaimana saya akan mencapai ini:

public static class MenuFragment extends ListFragment {
    public ListView listView1;
    Categories category;

    //this is my "non-default" constructor
    public MenuFragment(Categories category){
        this.category = category;
    }....

Tanpa menggunakan konstruktor non-standar?

BlackHatSamurai
sumber
3
Tidak, itu tidak membantu. Mereka tidak menjawab pertanyaan saya. Tapi terima kasih tidak ada yang kurang :)
BlackHatSamurai
31
@ BlaineOmega Sebenarnya yang ini khususnya: stackoverflow.com/a/11602478/321697 pasti menjawab pertanyaan Anda. Pada perubahan orientasi atau peristiwa lain yang menyebabkan Fragment dibuat ulang, Android menggunakan konstruktor default serta Bundle yang disahkan sebagai argumen. Jika Anda menggunakan konstruktor khusus, maka segera setelah fragmen dibuat kembali karena salah satu peristiwa ini, apa pun yang Anda lakukan di konstruktor kustom hilang.
Kevin Coppock
1
Terima kasih, tapi itu menjawab mengapa, tapi bukan caranya.
BlackHatSamurai
Itu tercakup oleh tautan pertama dan kedua di komentar asli saya.
CommonsWare

Jawaban:

110

Buat objek bundel dan masukkan data Anda (dalam contoh ini Categoryobjek Anda ). Hati-hati, Anda tidak bisa melewatkan objek ini langsung ke bundel, kecuali serializable. Saya pikir lebih baik untuk membangun objek Anda dalam fragmen, dan hanya memasukkan id atau sesuatu yang lain ke dalam bundel. Ini adalah kode untuk membuat dan melampirkan bundel:

Bundle args = new Bundle();
args.putLong("key", value);
yourFragment.setArguments(args);

Setelah itu, di data akses fragmen Anda:

Type value = getArguments().getType("key");

Itu saja.

nistv4n
sumber
3
bagaimana cara melewatkan objek? Saya ingin meneruskan Objek Konteks atau objek lainnya.
Adil Malik
12
Bundel dapat membawa objek Java serial dan juga Parcelableobjek. Juga, Anda tidak harus lulus Context, karena informasi yang dapat diakses melalui fragmen getActivity()metode .
krakatoa
Dalam fragmen di mana melakukan ini Type value = getArguments().getType("key");?
Muhammad Babar
4
@Muhammad Babar: Jika saya jadi Anda, saya akan menambahkannya ke newInstance()metode. Sebagai contoh: public static FragmentName newInstance(your variables){}. Seperti yang direkomendasikan oleh dokumentasi Android, jangan buat konstruktor dengan parameter, karena yang default (tanpa parameter) akan dipanggil secara otomatis setelah restart fragmen Anda.
nistv4n
@MuhammadBabar onCreateView tidak masalah
chanjianyi
272

Sepertinya tidak ada jawaban yang benar-benar menjawab "mengapa menggunakan bundel untuk melewatkan parameter daripada konstruktor non default"

Alasan mengapa Anda harus melewati parameter melalui bundel adalah karena ketika sistem mengembalikan fragment(misalnya pada perubahan konfigurasi), itu akan secara otomatis mengembalikan Anda bundle.

Panggilan balik suka onCreateatau onCreateViewharus membaca parameter dari bundle- dengan cara ini Anda dijamin untuk mengembalikan keadaan yang fragmentbenar ke keadaan yang sama dengan fragmentyang diinisialisasi dengan (perhatikan kondisi ini dapat berbeda dari onSaveInstanceState bundleyang diteruskan ke onCreate/onCreateView)

Rekomendasi menggunakan newInstance()metode statis hanyalah rekomendasi. Anda dapat menggunakan konstruktor non default tetapi pastikan Anda mengisi parameter inisialisasi di bagian bundledalam tubuh konstruktor itu. Dan baca parameter-parameter tersebut di dalam onCreate()atau onCreateView()metode.

salati numan
sumber
2
Diterangkan dengan baik. Terima kasih. Jika saya yang mengajukan pertanyaan, saya akan beri tanda centang
Karue Benson Karue
5
Anda tidak lagi dapat menggunakan konstruktor non-default (untuk alasan apa pun) .... itu memberikan kesalahan kompiler (dulu peringatan).
MPavlak
51

Anda Fragmentseharusnya tidak memiliki konstruktor karena bagaimana FragmentManagerinstantiasinya. Anda harus memiliki newInstance()metode statis yang didefinisikan dengan parameter yang Anda butuhkan, lalu bundel dan setel sebagai argumen fragmen, yang nantinya dapat Anda akses dengan Bundleparameter.

Sebagai contoh:

public static MyFragment newInstance(int title, String message) {
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle(2);
    bundle.putInt(EXTRA_TITLE, title);
    bundle.putString(EXTRA_MESSAGE, message);
    fragment.setArguments(bundle);
    return fragment ;
}

Dan baca argumen ini di onCreate:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...
}

Dengan cara ini, jika dilepaskan dan dilampirkan kembali, keadaan objek dapat disimpan melalui argumen, sangat mirip bundlesdengan Intents.

Asaf Pinhassi
sumber
9

Jika Anda menggunakan parameter untuk beberapa kelas. coba ini

SomeClass mSomeInstance;
public static final MyFragment newInstance(SomeClass someInstance){
    MyFragment f = new MyFragment();
    f.mSomeInstance = someInstance;
    return f;
}
김동기
sumber
5
Ini sebenarnya saran yang buruk. Setelah Fragmen akan dibuat ulang oleh FragmentManager, Anda akan kehilangan mSomeInstance.
Yaroslav Mytkalyk
Setuju, SomeClass harus parcelable dan disimpan dalam bundel menggunakan setArguments ()
Jake_
1

Saya pikir, tidak ada perbedaan antara konstruktor statis dan dua konstruktor (kosong dan parametrik yang menyimpan argumen ke dalam bundel argumen Fragmen), kemungkinan besar, aturan praktis ini dibuat untuk mengurangi kemungkinan lupa untuk mengimplementasikan konstruktor no-arg di Jawa , yang tidak secara implisit dihasilkan saat kelebihan hadir.

Dalam proyek saya, saya menggunakan Kotlin, dan mengimplementasikan fragmen dengan konstruktor no-arg primer dan konstruktor sekunder untuk argumen yang hanya menyimpannya ke dalam bundel dan menetapkannya sebagai argumen Fragmen, semuanya berfungsi dengan baik.

Pavlus
sumber
0

Jika fragmen menggunakan konstruktor non-default setelah konfigurasi mengubah fragmen akan kehilangan semua data.

Akop Vardanian
sumber