ความแตกต่างระหว่าง onCreateView และ onViewCreated ใน Fragment


119

อะไรคือความแตกต่างที่สำคัญระหว่างสองวิธีนี้? เมื่อฉันสร้าง TextView ฉันควรใช้อันอื่นเพื่อประสิทธิภาพหรือไม่?

แก้ไข: อะไรคือความแตกต่างจาก

onCreateView() {
  root = some view
  View v = new View(some context);
  root.add(v);
  return root;
}


onViewCreated() {
  View v = new View(some context);
  getView().add(v);
}

ฉันเพิ่มการแก้ไขเพื่ออธิบายความสับสนของฉัน ถ้าวิธีหนึ่งเกิดขึ้นทันทีทำไมถึงมีสองวิธี? การสร้างมุมมองทั้งหมดไม่สามารถทำได้ภายในวิธีการเดียวเหมือนในด้านบนหรือไม่
Smith

7
ถ้าคุณต้อง google และเดาว่าอาจมีวิธีการที่มีชื่อไม่ดี
BalázsNémeth

คำตอบ:


85

onCreateViewเราต้องเผชิญกับการเกิดปัญหาบางมุมมองในการเริ่มต้น

คุณควรจะขยายรูปแบบของคุณในonCreateViewแต่ไม่ควรเริ่มต้นมุมมองอื่น ๆ ที่ใช้ในfindViewByIdonCreateView

เนื่องจากบางครั้งมุมมองไม่ได้รับการเตรียมใช้งานอย่างถูกต้อง ดังนั้นมักจะใช้findViewByIdในonViewCreated(เมื่อมุมมองที่ถูกสร้างขึ้นอย่างเต็มที่) และยังผ่านมุมมองที่เป็นพารามิเตอร์

onViewCreated ตรวจสอบให้แน่ใจว่ามีการสร้างมุมมองอย่างสมบูรณ์

onViewCreated เอกสารประกอบของ Android

เรียกทันทีหลังจากonCreateView( android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) กลับมา แต่ก่อนที่สถานะที่บันทึกไว้จะถูกเรียกคืนในมุมมอง สิ่งนี้ทำให้คลาสย่อยมีโอกาสเริ่มต้นด้วยตนเองเมื่อพวกเขารู้ว่าลำดับชั้นมุมมองของพวกเขาถูกสร้างขึ้นอย่างสมบูรณ์ อย่างไรก็ตามลำดับชั้นมุมมองของแฟรกเมนต์ไม่ได้แนบกับพาเรนต์ ณ จุดนี้


4
ขอบคุณ ฉันยังประสบปัญหานี้และใช้ส่วนประกอบ post(... ) วิธีรอจนกว่าจะแสดง อาจจะทำให้ findViewById และการเริ่มต้นอื่น ๆ ในonViewCreated.
CoolMind

22
ข้อความนั้นยกมาจากไหน? ฉันไม่พบในเอกสารอย่างเป็นทางการ
Daniel

คุณสามารถโพสต์ข้อมูลอ้างอิงจากเว็บไซต์นักพัฒนาของคำแถลงที่ยกมานี้ได้หรือไม่?
Namrata Bagerwal

4
นี่ไม่ถูกต้องจริงๆ คุณสามารถค้นหามุมมองได้ใน onCreateView แต่หลังจากที่คุณได้ขยายแล้วเท่านั้นและจากมุมมองที่คุณได้ขยายไปแล้วเท่านั้น Fragment.findViewById () ไม่ปลอดภัย แต่ View.findViewById () จะปลอดภัยหากคุณขยายมุมมองแฟรกเมนต์แล้ว
colintheshots

46

onViewCreatedถูกเรียกทันทีหลังจากนั้นonCreateView(วิธีที่คุณเริ่มต้นและสร้างวัตถุทั้งหมดของคุณรวมทั้งของคุณTextView) ดังนั้นจึงไม่ใช่เรื่องของประสิทธิภาพ

จากไซต์นักพัฒนา:

onViewCreated (ดูมุมมอง Bundle ที่บันทึกไว้InstanceState)

เรียกทันทีหลังจาก onCreateView (LayoutInflater, ViewGroup, Bundle) กลับมา แต่ก่อนที่สถานะที่บันทึกไว้จะถูกเรียกคืนในมุมมอง สิ่งนี้ทำให้คลาสย่อยมีโอกาสเริ่มต้นด้วยตนเองเมื่อพวกเขารู้ว่าลำดับชั้นมุมมองของพวกเขาถูกสร้างขึ้นอย่างสมบูรณ์ อย่างไรก็ตามลำดับชั้นมุมมองของแฟรกเมนต์ไม่ได้แนบกับพาเรนต์ ณ จุดนี้

ที่มา: Fragment # onViewCreated


28

การกำหนดมุมมองย่อยให้กับช่องต่างๆจะonViewCreatedดีกว่า เนื่องจากเฟรมเวิร์กทำการตรวจสอบค่าว่างอัตโนมัติให้คุณเพื่อให้แน่ใจว่าลำดับชั้นมุมมองของ Fragment ของคุณถูกสร้างขึ้นและขยาย (หากใช้ไฟล์เลย์เอาต์ XML) อย่างถูกต้อง

ข้อมูลโค้ดจาก: FragmentManger.java

// This calls onCreateView()
f.mView = f.performCreateView(f.getLayoutInflater(f.mSavedFragmentState), null, f.mSavedFragmentState);

// Null check avoids possible NPEs in onViewCreated
// It's also safe to call getView() during or after onViewCreated()
if (f.mView != null) {
    f.mView.setSaveFromParentEnabled(false);
    if (f.mHidden) f.mView.setVisibility(View.GONE);
    f.onViewCreated(f.mView, f.mSavedFragmentState);
}

6
นอกจากนี้ยังแยกตรรกะการเริ่มต้นออกจากมุมมองลำดับชั้นอัตราเงินเฟ้อ / ตรรกะการสร้าง
orangemako

1
สิ่งนี้น่าสนใจคุณมีแหล่งข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่แนวทางนี้ดีกว่าหรือไม่? หมายความว่าทุกเมธอด onCreateView ควรประกอบด้วย "return inflater.inflate (R.layout.layout_file, container, false) เท่านั้น" และ onviewcreated ควรมีเมธอด "findViewById" ทั้งหมดหรือไม่ สิ่งนี้ช่วยเพิ่มประสิทธิภาพอะไร จะทำให้การเปลี่ยนภาพเร็วขึ้นหรือไม่?
android_student

ในการตอบคำถามแรกของคุณonCreateViewใช้เพื่อสร้างลำดับชั้นมุมมองของแฟรกเมนต์ ซึ่งสามารถทำได้โดยใช้ XML อัตราเงินเฟ้อหรือการสร้างแบบไดนามิก (เช่นการสร้างมุมมอง Java โดยใช้โปรแกรม) ดังนั้นคุณอาจไม่โทรinflateเลย แต่คุณควรส่งคืนมุมมองพาเรนต์บางส่วนหากแฟรกเมนต์จำเป็นต้องมีองค์ประกอบ UI nullมิฉะนั้นกลับ
orangemako

ไม่มีการเพิ่มประสิทธิภาพเลย เมื่อดูที่FragmentManagerโค้ดและperformCreateViewonCreateView onViewCreated
แฟรกเมนต์

1. ลำดับชั้นของมุมมองจะแนบไปกับคอนเทนเนอร์หากมีการเพิ่มส่วนแบบไดนามิกในกิจกรรมหลัก 2. คุณสามารถดูการค้นหาได้อย่างปลอดภัยโดยไม่ต้องกังวลเกี่ยวกับ NPE 3. ฉันไม่ค่อยคุ้นเคยกับแอนิเมชั่น แต่การเปลี่ยนแฟรกเมนต์จะเริ่มขึ้นแล้ว (กล่าวคือส่งไปยังคิวข้อความเธรด UI)
orangemako

13

onCreateViewส่งคืนมุมมองที่สูงเกินจริง OnViewCreatedเรียกว่า just after onCreateViewและ get มีพารามิเตอร์มุมมองที่สูงเกินจริง ประเภทผลตอบแทนคือvoid


1
ฉันเพิ่มการแก้ไขเพื่ออธิบายความสับสนของฉัน ถ้าวิธีหนึ่งเกิดขึ้นทันทีทำไมถึงมีสองวิธี? การสร้างมุมมองทั้งหมดไม่สามารถทำได้ภายในวิธีการเดียวเช่นเดียวกับข้างต้น
Smith

3
onCreateView ควรกลับมาอย่างรวดเร็ว OnViewCreate สามารถใช้เพื่อดำเนินการเตรียมข้อมูลเบื้องต้นได้เช่น ดังที่ฉันได้กล่าวไปแล้วว่า onViewCreated มีเป็นพารามิเตอร์ View ที่คุณสูงเกินจริงภายใน onCreateView ดังนั้นคุณสามารถหลีกเลี่ยงการgetViewโทร
Blackbelt

8

onCreateView()เป็น Fragment ที่เทียบเท่าonCreate()กับสำหรับ Activities และรันระหว่างการสร้าง View
onViewCreated()ทำงานหลังจากสร้างมุมมองแล้ว

should I use one over the other for performance? NONOไม่มีหลักฐานการเพิ่มประสิทธิภาพ

จริงๆแล้วมีonCreate()วิธีใน Fragments ด้วย แต่ก็ไม่ค่อยได้ใช้ (ฉันไม่เคยใช้มันและไม่พบวิธีการใช้ที่ดีสำหรับมัน)

ฉันมักจะใช้onCreateView()ใน Fragments แทนonCreate()ไฟล์.
และฉันมีความสุขกับสิ่งนั้น


2
@npace ทำไม? ผมยังคิดว่าเป็นเทียบเท่าของกิจกรรมonCreateView onCreate
CoolMind

2
@CoolMind อืม nPace ไม่ได้ผิดทั้งหมดเนื่องจากมีonCreate()วิธีการใน Framents เช่นกัน แต่มันไม่เคยใช้ (หรืออย่างน้อยฉันก็ไม่เคยใช้มัน) ฉันมักจะใช้onCreateView()ใน Fragments แทน
Phantômaxx

1
@ โรตวังเห็นด้วย! บางบทช่วยสอนใช้ onCreate เพื่อใส่ setHasOptionsMenu (true) แต่ฉันคิดว่ามันน่าจะทำได้ดีกว่าใน onCreateView หรือ onViewCreated
CoolMind

1
@CoolMind ฉันเห็นด้วยอย่างยิ่ง บางทีฉันอาจใช้คำผิดในคำตอบของฉัน
Phantômaxx

1
@ โรตวังคุณพูดถูก เมื่อฉันใช้ชิ้นส่วนเป็นครั้งแรกฉันก็ไม่รู้ว่าทำไมถึงไม่ใช้ onCreate
CoolMind

4

เอกสารในFragment.onCreateView()ตอนนี้กล่าวว่า:

ขอแนะนำให้ขยายเลย์เอาต์ในวิธีนี้เท่านั้นและย้ายตรรกะที่ทำงานบน View ที่ส่งคืนไปยัง onViewCreated (View, Bundle)

ไม่จำเป็นต้องให้เราเข้าใจว่าทำไม เราแค่ต้องทำตามที่เอกสารบอก แต่ก็น่าสนใจที่จะรู้ว่าทำไมจึงมีคำแนะนำนี้ การเดาที่ดีที่สุดของฉันคือการแยกความกังวลแต่ IMHO สิ่งนี้ทำให้ซับซ้อนกว่าที่ควรจะเป็นเล็กน้อย


หากเหตุผลคือการแยกความกังวลเหตุใดกิจกรรมจึงขยายเลย์เอาต์setContentView()ในonCreate()?
Minh Nghĩa

@ MinhNghĩaจุดดี. คำตอบสำหรับคำถามนั้นอาจเป็นได้ว่าได้รับการออกแบบโดยโปรแกรมเมอร์คนอื่นที่คิดต่างกัน (มีการเปิดตัวชิ้นส่วนหลายปีหลังจากที่เรามี Android เป็นครั้งแรก) แต่ใครจะรู้
Peppe LG

2

เหตุผลหลักที่ฉันจะใช้onViewCreatedคือเนื่องจากมันแยกตรรกะการเริ่มต้นใด ๆ ออกจากตรรกะการขยายตัว / การสร้างลำดับชั้นของมุมมองซึ่งควรอยู่ในonViewCreate. ลักษณะการทำงานอื่น ๆ ทั้งหมดมีลักษณะเหมือนกัน


2

ฉันคิดว่าความแตกต่างหลักระหว่างสิ่งเหล่านี้คือเมื่อคุณใช้ kotlin.in onCreateView ()ทุกครั้งที่คุณต้องการเข้าถึงเพื่อดูในไฟล์ xml ของคุณคุณควรใช้findViewByIdแต่ในonViewCreatedคุณสามารถเข้าถึงมุมมองของคุณได้เพียงแค่เรียกรหัสของมัน .


นี่มันเรื่องจริงเหรอ? ฉันได้รับค่าว่างสำหรับมุมมองถ้าฉันใช้ id ในโค้ดไม่ทางใดก็ทางหนึ่ง ฉันจำเป็นต้องใช้ findViewById เสมอ
Jim Leask

1
ไม่มันไม่ใช่ .. oncreate view ทำให้มุมมองเป็นอินสแตนซ์ onviewcreated ถูกเรียกหลังจาก oncreateview และก่อนที่สถานะที่บันทึกไว้จะถูกเรียกคืน ... มันเป็นปัญหาเรื่องเวลาในวงจรชีวิตของส่วนย่อยมากกว่า
me_

1

onCreateView ใช้ในแฟรกเมนต์เพื่อสร้างเลย์เอาต์และขยายมุมมอง onViewCreated ใช้เพื่ออ้างอิงมุมมองที่สร้างขึ้นโดยวิธีการด้านบน สุดท้ายนี้เป็นแนวทางปฏิบัติที่ดีในการกำหนดการฟังการกระทำใน onActivityCreated

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.