Фрагмент 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 (Context).

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


Если вы используете конкретные методы Activity из переданного вами экземпляра, пытались ли вы привести контекст к вашему Activity? Помните, что активность является подклассом контекста. Может быть, кастинг будет работать.
MarkSkayff

по какой-то причине onAttach () даже не вызывается! Любые идеи? Вы пытались обновить до последней версии библиотеки поддержки.?
TareK Khoury

2
Почему API перешел на Context? Разве вам не нужно Activity, чтобы прикрепить и отобразить фрагмент в любом случае? Как еще вы будете использовать Contextпараметр?
Кенни Уорден

1
Я опубликовал сообщение об ошибке, см. Ссылку code.google.com/p/android/issues/detail?id=183358
TareK Khoury

6
Для вызова нового onAttach(Context context)вам нужно либо использовать устройство с API по крайней мере 23, либо использовать android.support.v4.app.Fragment. Смотрите здесь
Невзо

Ответы:


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

Mr.Yoann Hercouet, Можете ли вы объяснить, как это сделать выше API 23, любезно помогите мне, заранее спасибо, E / AndroidRuntime: FATAL EXCEPTION: main, java.lang.ClassCastException: com.ual.SMS_Activity@afd5683, на android. support.v4.app.FragmentManagerImpl.moveToState, atroid.support.v4.app.FragmentManagerImpl.execSingleAction. Здесь я разместил необходимые строки, которые помогут вам узнать мою ошибку.
МоханРадж С

@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), где он не вызывается, поэтому он вызывает исключения NullPointerException. Поэтому, чтобы быть в безопасности, я предлагаю также оставить устаревший метод:

// 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 четко показывает, что фрагмент был загружен, и поэтому после этого метода вызов действия get из фрагмента вернет класс 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.