เลิกใช้ Android Fragment onAttach () แล้ว


326

ฉันได้อัพเดทแอพของฉันเพื่อใช้ไลบรารี่สนับสนุนล่าสุด (เวอร์ชั่น 23.0.0) ฉันพบว่าพวกเขาเลิกใช้ฟังก์ชั่น onAttach () ของคลาส Fragment

แทน:

onAttach (Activity activity)

ตอนนี้:

onAttach (Context context)

เนื่องจากแอพของฉันใช้กิจกรรมที่ผ่านไปก่อนที่จะเลิกใช้งานโซลูชันที่เป็นไปได้ฉันคิดว่า:

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    activity = getActivity();
}

นั่นเป็นวิธีที่ถูกต้องหรือไม่

UPDATE:

หากฉันเรียกใช้อุปกรณ์ที่มี API ต่ำกว่า 23 ใหม่ onAttach () จะไม่ถูกเรียก ฉันหวังว่านี่ไม่ใช่สิ่งที่พวกเขาตั้งใจจะทำ!

อัปเดต 2:

ปัญหาได้รับการแก้ไขด้วยการอัปเดตล่าสุดของ SDK

ฉันได้ทดสอบกับอุปกรณ์ API 22 ของฉันและกำลังเรียกใช้ onAttach (บริบท)

คลิกที่นี่เพื่อติดตามรายงานข้อผิดพลาดฉันได้เปิดสองสามสัปดาห์ที่ผ่านมาและคำตอบจากพวกที่ Google


หากคุณใช้วิธีกิจกรรมเฉพาะจากอินสแตนซ์ที่ส่งผ่านของคุณคุณลองส่งบริบทไปที่กิจกรรมของคุณหรือไม่ โปรดจำไว้ว่า Activity เป็นคลาสย่อยของบริบท บางทีการคัดเลือกนักแสดงจะได้ผล
MarkSkayff

ด้วยเหตุผลบางอย่าง onAttach () ไม่ได้ถูกเรียก! ความคิดใด ๆ คุณลองอัปเดตเป็น lib การสนับสนุนล่าสุดหรือไม่
TareK Khoury

2
ทำไม API ถึงถูกย้ายไปContext? คุณไม่จำเป็นต้องActivityแนบหรือแสดงส่วนย่อยหรือไม่? คุณจะใช้Contextพารามิเตอร์เป็นอย่างไร
Kenny Worden

1
ฉันโพสต์ไว้เป็นข้อผิดพลาดโปรดดูที่ลิงค์code.google.com/p/android/issues/detail?id=183358
TareK Khoury

6
เพื่อที่onAttach(Context context)จะได้ชื่อว่าใหม่คุณต้องใช้อุปกรณ์ที่มีอย่างน้อย API 23 หรือใช้ android.support.v4.app.Fragment ดูที่นี่
nevzo

คำตอบ:


337

กิจกรรมเป็นบริบทดังนั้นหากคุณสามารถตรวจสอบบริบทเป็นกิจกรรมและใช้งานได้ถ้าจำเป็น

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}

อัปเดต:บางคนอ้างว่าไม่มีการContextแทนที่ใหม่ ฉันได้ทำการทดสอบบางอย่างแล้วและไม่สามารถหาสถานการณ์ที่นี่เป็นจริงและตามซอร์สโค้ดมันไม่ควรเป็นจริง ในทุกกรณีที่ฉันทดสอบทั้งก่อนและหลัง SDK23 ทั้งในActivityและContextรุ่นที่onAttachเรียกว่า หากคุณสามารถหาสถานการณ์ที่นี้ไม่ได้เป็นกรณีที่ผมจะแนะนำให้คุณสร้างโครงการตัวอย่างที่แสดงให้เห็นถึงปัญหาและรายงานไปยังทีมงาน Android

อัปเดต 2:ฉันใช้ชิ้นส่วนห้องสมุดสนับสนุน Android เท่านั้นเนื่องจากข้อบกพร่องได้รับการแก้ไขเร็วขึ้นที่นั่น ดูเหมือนว่าปัญหาข้างต้นที่การแทนที่ไม่ได้รับการเรียกอย่างถูกต้องจะเกิดขึ้นได้ก็ต่อเมื่อคุณใช้แฟรกเมนต์ของกรอบงาน


5
ไม่ใช่วิธีการแก้ปัญหาอย่างแท้จริงเนื่องจาก onAttach กับบริบทไม่ได้ถูกเรียกเช่นเดียวกับ onAttach พร้อมกับกิจกรรม หากคุณมีรหัสเริ่มต้นบางส่วนใน onAttach พร้อมกับกิจกรรมเนื่องจากพารามิเตอร์การเปลี่ยนแปลงนี้จะไม่ทำงาน
บัดดี้

2
ไม่มันไม่ทำงานเหมือนกันอย่างน้อยในกรณีของฉัน ฉันไม่ได้ใช้กิจกรรมหรือบริบทใน onAttach ฉันจะเริ่มต้น ฉันได้ลองแทนที่ onAttach ด้วยกิจกรรมเป็นกิจกรรมที่มีบริบทและไม่ได้รับการเรียกในลักษณะเดียวกัน ดังนั้นพวกมันจึงไม่สามารถแลกเปลี่ยนกันได้อย่างง่ายดาย
บัดดี้

7
ปัญหาแบบเดียวกับที่บัดดี้มี ... onAttach(Context)ดูเหมือนจะไม่ถูกเรียกเช่นกัน
Stéphane

2
ฉันได้ก้าวผ่านรหัสของฉันและฉันสามารถตรวจสอบว่าเป็นไปได้ที่onAttach(context)จะไม่ถูกเรียก
Chad Bingham

2
ในกรณีของฉัน onAttach () จะไม่ถูกเรียกถ้าเรารีสตาร์ทกิจกรรมที่ระบบจะถูกล้างก่อนหน้านี้ แต่มันไม่ได้เป็นแบบนี้เสมอไป ฉันใส่การเริ่มต้นของ WeakReference ใน onAttach (บริบทบริบท), refActivity = new WeakReference <> (AppCompatActivity) บริบท และมันจะพ่น NullPointerException ใน onCreateView () เป็นครั้งคราว
Kimi Chiu

45

นี่คือการเปลี่ยนแปลงที่ยอดเยี่ยมอีกครั้งจาก Google ... การปรับเปลี่ยนที่แนะนำ: แทนที่onAttach(Activity activity)ด้วยonAttach(Context context)แอพของฉันที่ทำงานขัดข้องใน API ที่เก่ากว่าเนื่องจากonAttach(Context context)จะไม่ถูกเรียกใช้บนแฟรกเมนต์ดั้งเดิม

ฉันใช้แฟรกเมนต์ดั้งเดิม (android.app.Fragment) ดังนั้นฉันต้องทำสิ่งต่อไปนี้เพื่อให้มันทำงานได้อีกครั้งบน API ที่เก่ากว่า (<23)

นี่คือสิ่งที่ฉันทำ:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    // Code here
}

@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        // Code here
    }
}

Mr.Yoann Hercouet, คุณช่วยอธิบายได้อย่างไรว่าจะทำอย่างไรกับ API 23 ข้างต้นโปรดช่วยฉันขอบคุณล่วงหน้า E / AndroidRuntime: ข้อยกเว้นทาง FATAL: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683 ที่ android support.v4.app.FragmentManagerImpl.moveToState ที่ android.support.v4.app.FragmentManagerImpl.execSingleAction ที่นี่ฉันโพสต์บรรทัดที่จำเป็นซึ่งคุณจะรู้ข้อผิดพลาดของฉัน
MohanRaj S

@MohanRajS มันเหมือนกันกับ API 24 (อันที่ฉันใช้) ตามรหัสของคุณปัญหาของคุณดูเหมือนจะไม่ต้องทำอะไรกับสิ่งนี้
Yoann Hercouet

@YoannHercouet ขอขอบคุณสำหรับการตอบกลับของคุณให้ฉันตรวจสอบและอัปเดต
MohanRaj S

1
คุณไม่มีความสุขกับ Google เกี่ยวกับเรื่องนี้เนื่องจากปัญหาในการกำหนดเป้าหมาย API ที่เก่ากว่า ลองพิจารณาคำอวยพรที่คุณสามารถกำหนดเป้าหมายของ API ที่เก่ากว่าได้ในขณะที่ Apple นั้นจะทำให้คุณงงงวยอย่างมากและบังคับให้คุณสนับสนุนเฉพาะคนใหม่ล่าสุด
Stan

39

หากคุณใช้ชิ้นส่วนของเฟรมเวิร์กและเวอร์ชั่น SDK ของอุปกรณ์ต่ำกว่า 23 OnAttach(Context context)จะไม่มีการเรียกใช้

ฉันใช้แฟรกเมนต์สนับสนุนแทนดังนั้นการคัดค้านจะได้รับการแก้ไขและonAttach(Context context)ได้รับการเรียกเสมอ


11

ในปัจจุบันจากonAttachรหัสส่วนมันไม่ชัดเจนว่าContextเป็นกิจกรรมปัจจุบัน: รหัสที่มา

public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

หากคุณจะดูที่getActivityคุณจะเห็นสายเดียวกัน

/**
 * Return the Activity this fragment is currently associated with.
 */
final public Activity getActivity() {
    return mHost == null ? null : mHost.getActivity();
}

ดังนั้นหากคุณต้องการให้แน่ใจว่าคุณได้รับกิจกรรมแล้วใช้ getActivity()(ในonAttachในของคุณFragment) แต่ไม่ลืมที่จะตรวจสอบnullเพราะถ้าmHostเป็นnullกิจกรรมของคุณจะnull



5

แม้ว่าดูเหมือนว่าในกรณีส่วนใหญ่ก็เพียงพอที่จะมีonAttach(Context)แต่ก็มีโทรศัพท์บางรุ่น (เช่น: Xiaomi Redme Note 2) ซึ่งไม่ได้ถูกเรียกดังนั้นจึงทำให้ NullPointerExceptions ดังนั้นในด้านความปลอดภัยฉันแนะนำให้ออกจากวิธีการคัดค้านเช่นกัน:

// onAttach(Activity) is necessary in some Xiaomi phones
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    _onAttach(activity);
}

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    _onAttach(context);
}

private void _onAttach(Context context) {
    // do your real stuff here
}

3

ดาวน์โหลดไลบรารีการสนับสนุนใหม่ล่าสุดพร้อมผู้จัดการ sdk และรวมถึง

compile 'com.android.support:appcompat-v7:23.1.1'

ใน gradle.app และตั้งค่าเวอร์ชั่นคอมไพล์เป็น api 23


1

คำตอบด้านล่างเกี่ยวข้องกับคำเตือนการคัดค้านที่เกิดขึ้นในบทช่วยสอนการแยกส่วนในเว็บไซต์นักพัฒนา Android และอาจไม่เกี่ยวข้องกับโพสต์ด้านบน

ฉันใช้รหัสนี้ในบทเรียนการสอนและใช้งานได้

public void onAttach(Context context){
    super.onAttach(context);

    Activity activity = getActivity();

ฉันกังวลว่ากิจกรรมอาจเป็นโมฆะตามที่ระบุในเอกสาร

getActivity

FragmentActivity getActivity () กลับ FragmentActivity ส่วนนี้เกี่ยวข้องกับ อาจส่งคืนค่าว่างถ้าแฟรกเมนต์เชื่อมโยงกับบริบทแทน

แต่ onCreate บน main_activity แสดงให้เห็นอย่างชัดเจนว่ามีการโหลดชิ้นส่วนและหลังจากวิธีนี้การเรียกรับกิจกรรมจากส่วนจะกลับชั้น main_activity

getSupportFragmentManager (). startTransaction () .add (R.id.fragment_container, firstFragment) .commit ();

ฉันหวังว่าฉันถูกต้องกับสิ่งนี้ ฉันเป็นมือใหม่อย่างแน่นอน


1

android.support.v4.app.Fragmentคุณอาจจะใช้ สำหรับวิธีนี้แทนที่จะonAttachใช้เมธอดเพียงใช้วิธีgetActivity()รับFragmentActivityแฟรกเมนต์ที่เชื่อมโยงด้วย มิฉะนั้นคุณสามารถใช้onAttach(Context context)วิธีการ


0

สิ่งนี้ใช้ได้สำหรับฉันเมื่อฉันมีส่วนติดต่อผู้ใช้ที่กำหนด 'TopSectionListener' ซึ่งเป็นผู้ดำเนินกิจกรรมวัตถุ:

  //This method gets called whenever we attach fragment to the activity
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    Activity a=getActivity();
    try {
        if(context instanceof Activity)
           this.activitycommander=(TopSectionListener)a;
    }catch (ClassCastException e){
        throw new ClassCastException(a.toString());}

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