Фрагмент Android onAttach () застарілий


326

Я оновив свою програму для використання останньої бібліотеки підтримки (версія 23.0.0), я виявив, що вони застаріли функцію onAttach () класу Fragment.

Замість:

onAttach (Activity activity)

Зараз:

onAttach (Context context)

Оскільки мій додаток використовує активність, пройдену до припинення, я думаю, що можливе рішення:

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

Це був би правильний спосіб зробити це?

ОНОВЛЕННЯ:

Якщо я запускаю пристрій з API нижче 23, новий onAttach () навіть не викликається. Я сподіваюся, що це не те, що вони мали намір робити!

ОНОВЛЕННЯ 2:

Проблема була вирішена за допомогою останніх оновлень SDK.

Я перевірив на своєму пристрої API 22, і він викликує onAttach (контекст).

Натисніть тут, щоб слідкувати за повідомленням про помилки, який я відкрив пару тижнів тому та відповіді хлопців з Google.


Якщо ви використовуєте конкретні методи діяльності від минулого екземпляра, чи спробували ви викидати контекст на активність? Запам'ятати діяльність - це підклас контексту. Можливо, кастинг спрацює.
MarkSkayff

чомусь навіть onAttach () навіть не називається! якісь ідеї? ви спробували оновити до останньої версії підтримки.?
TareK Khoury

2
Чому API перемістився Context? Вам не потрібен Activity, щоб все-таки долучити фрагмент і відобразити його? Як ще ви будете використовувати Contextпараметр?
Кенні Worden

1
Я опублікував це як помилку, дивіться посилання code.google.com/p/android/isissue/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)навіть не називаються.
Стефан

2
Я переглянув свій код і можу переконатися, що його неможливо onAttach(context)викликати.
Чад Бінгем

2
У моєму випадку, onAttach () не буде викликаний, якщо ми перезапустимо діяльність, очищену системою раніше. Але це не завжди так. Я ставлю ініціалізацію WeakReference у контексті onAttach (контекст контексту), refActivity = новий WeakReference <> ((AppCompatActivity) контексті). І він періодично кидає NullPointerException в onCreateView ().
Кімі Чіу

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
    }
}

Містер Йоанн Херкует, можете пояснити, як це зробити вище API 23, будь ласка, допоможіть мені, заздалегідь дякую, E / AndroidRuntime: FATAL EXCEPTION: 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 (той, який я використовував), згідно з вашим фрагментом коду, схоже, ваша проблема нічого з цим не має.
Йоанна Геркует

@YoannHercouet, Дякую вам за вашу відповідь, дозвольте мені перевірити та оновити.
MohanRaj S

1
Ви із цим не задоволені Google через проблеми з націленням на більш старі API. Ну, подумайте про те, що ви можете націлити на старі API, тоді як Apple, наприклад, дуже сильно покалічить вас і змусить вас підтримувати лише новітні.
Стен

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


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

    Activity activity = context instanceof Activity ? (Activity) context : 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

FraAgActivity getActivity () Повернення FragmentActivity, з яким цей фрагмент зараз асоціюється. Може повернути нуль, якщо фрагмент замість нього пов'язаний з контекстом.

Але onCreate на main_activity чітко показує, що фрагмент був завантажений, і тому після цього методу виклик отримати активність з фрагмента поверне клас main_activity.

getSupportFragmentManager (). beginTransaction () .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());}

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.