java.lang.IllegalStateException: фрагмент не привязан к активности

148

Я редко получаю эту ошибку при вызове API.

java.lang.IllegalStateException: Fragment  not attached to Activity

Я попытался поместить код в isAdded()метод, чтобы проверить, добавлен ли фрагмент в настоящее время к его активности, но все же я редко получаю эту ошибку. Я не понимаю, почему я все еще получаю эту ошибку. Как я могу предотвратить это?

Это показывает ошибку на линии

cameraInfo.setId(getResources().getString(R.string.camera_id));

Ниже приведен пример вызова API, который я делаю.

SAPI.getInfo(getActivity(),
                new APIResponseListener() {
                    @Override
                    public void onResponse(Object response) {


                        cameraInfo = new SInfo();
                        if(isAdded()) {
                            cameraInfo.setId(getResources().getString(R.string.camera_id));
                            cameraInfo.setName(getResources().getString(R.string.camera_name));
                            cameraInfo.setColor(getResources().getString(R.string.camera_color));
                            cameraInfo.setEnabled(true);
                        }


                    }

                    @Override
                    public void onError(VolleyError error) {
                        mProgressDialog.setVisibility(View.GONE);
                        if (error instanceof NoConnectionError) {
                            String errormsg = getResources().getString(R.string.no_internet_error_msg);
                            Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
                        }
                    }
                });
Android-разработчик
источник
cameraInfo.setId (.. getActivity () GetResources () GetString (R.string.camera_id));
Эшвин Х

Ответы:

203

Эта ошибка происходит из-за совместного влияния двух факторов:

  • HTTP-запрос, когда завершен, вызывает либо onResponse()или onError()(которые работают в основном потоке), не зная, Activityнаходится ли все еще на переднем плане или нет. Если Activityнет (пользователь перешел в другое место),getActivity() возвращает значение NULL.
  • Залп Responseвыражается как анонимный внутренний класс, который неявно содержит сильную ссылку на внешний Activityкласс. Это приводит к классической утечке памяти.

Чтобы решить эту проблему, вы всегда должны сделать:

Activity activity = getActivity();
if(activity != null){

    // etc ...

}

а также используйте isAdded()в onError()методе также:

@Override
public void onError(VolleyError error) {

    Activity activity = getActivity(); 
    if(activity != null && isAdded())
        mProgressDialog.setVisibility(View.GONE);
        if (error instanceof NoConnectionError) {
           String errormsg = getResources().getString(R.string.no_internet_error_msg);
           Toast.makeText(activity, errormsg, Toast.LENGTH_LONG).show();
        }
    }
}
YS
источник
2
При использовании запросов Volley и AsyncTasks изнутри Activity, нет надежного способа избежать NPE. Всегда есть вероятность, что пользователь может отойти от текущего, Activityпока один из потоков что-то делает в фоновом режиме, а затем, когда поток завершает работу onPostExecute()или onResponse()вызывается, нет Activity. Все, что вы можете сделать, это проверять нулевые ссылки в различных точках вашего кода, и это не пуленепробиваемо :)
YS
2
Тест «Обезьяна андроида» (adb shell monkey) действительно хорош в устранении этой ошибки, если вы еще не учли ее в общем / общем виде.
Groovee60
5
isAdded () достаточно, окончательный публичный логический isAdded () {return mActivity! = null && mAdded; }
lannyf
2
@ruselli: проверяет addedлогический флаг и показывает, является ли текущий Activityэкземпляр текущим nullили нет.
YS
1
@gauravjain Избегайте выполнения асинхронных запросов (например, HTTP-вызовов) непосредственно из фрагментов. Сделайте это из Деятельности, и это должно быть хорошо. Кроме того, очистите ссылки Fragment от FragmentManager, это хорошая практика и лучший способ избежать утечек памяти.
YS
56

Жизненный цикл фрагмента очень сложен и полон ошибок, попробуйте добавить:

Activity activity = getActivity(); 
if (isAdded() && activity != null) {
...
}
Мирослав Михалец
источник
2
Где я должен это поставить?
Вацловас Рекашюс-младший
1
@ VaclovasRekašiusJr. Похоже, почти везде, где вы хотите получить доступ к Activity из фрагмента. Весело!
TylerJames
2
что я должен делать, если активность == ноль. чтобы сохранить в живых мое приложение @Miroslav
pavel
Посмотрите на isAdded (), вы можете обнаружить, что «активность! =
Ноль
@BertKing return mHost != null && mAdded;- это то, что внутри метода frag.isAdded (). Я думал, что mHost - это действие, если вы его отслеживаете, но кажется, что mHost находится внутри FragmentActivity. Так что, наверное, ты прав. Есть дополнения?
Джонни
14

Я нашел очень простое решение - метод isAdded (), который является одним из методов фрагмента, чтобы определить, привязан этот текущий фрагмент к его активности или нет.

мы можем использовать это как везде в классе фрагмента, как:

if(isAdded())
{

// using this method, we can do whatever we want which will prevent   **java.lang.IllegalStateException: Fragment not attached to Activity** exception.

}
Дхармеш Балдха
источник
12

Исключение: java.lang.IllegalStateException: фрагмент

DeadlineListFragment {ad2ef970} не присоединен к Activity

Категория: Жизненный цикл

Описание : при выполнении длительной операции в фоновом потоке (например, AsyncTask) тем временем был создан новый фрагмент, который был отсоединен от действия до завершения фонового потока. Код в потоке пользовательского интерфейса (например, onPostExecute) вызывает отдельный фрагмент, вызывая такое исключение.

Исправить решение:

  1. Отмена фонового потока при приостановке или остановке фрагмента

  2. Используйте isAdded (), чтобы проверить, прикреплен ли фрагмент, а затем получить getResources () из действия.

Рахиль Али
источник
11

я могу опоздать, но могу помочь кому-то ..... Лучшее решение для этого - создать глобальный экземпляр класса приложения и вызвать его в определенном фрагменте, к которому ваша активность не привязана

как показано ниже

icon = MyApplication.getInstance().getString(R.string.weather_thunder);

Вот класс приложения

public class MyApplication extends Application {

    private static MyApplication mInstance;
    private RequestQueue mRequestQueue;

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }

    public static synchronized MyApplication getInstance() {
        return mInstance;
    }
}
Md Gouse
источник
1
Да, этот метод также широко используется.
CoolMind
1
Это не мудрый вариант. FragmentContext и ApplicationContext имеют разные стили. Контекст фрагмента может иметь темную тему, собственный стиль, локаль и т. Д., Которые будут извлекать цвет, строковые ресурсы из разных файлов. Хотя ApplicationContext может не вытянуть правильный ресурс. Если у вас нет Context, тогда вы не должны пытаться визуализировать этот ресурс.
Джемшит Искендеров
2

Эта ошибка может произойти, если вы создаете экземпляр фрагмента, который каким-либо образом не может быть создан:

Fragment myFragment = MyFragment.NewInstance();


public classs MyFragment extends Fragment {
  public void onCreate() {
   // Some error here, or anywhere inside the class is preventing it from being instantiated
  }
}

В моем случае я встречал это, когда пытался использовать:

private String loading = getString(R.string.loading);
sagits
источник
2

Использование фрагмента isAdded() Он вернет true, если фрагмент в настоящее время присоединен к Activity.

Если вы хотите проверить внутри деятельности

 Fragment fragment = new MyFragment();
   if(fragment.getActivity()!=null)
      { // your code here}
      else{
       //do something
       }

Надеюсь, это поможет кому-то

Prateek218
источник
1

Я принял следующий подход для решения этой проблемы. Создан новый класс, который действует как обертка для таких методов деятельности

public class ContextWrapper {
    public static String getString(Activity activity, int resourceId, String defaultValue) {
        if (activity != null) {
            return activity.getString(resourceId);
        } else {
            return defaultValue;
        }
    }

    //similar methods like getDrawable(), getResources() etc

}

Теперь, где бы мне ни понадобился доступ к ресурсам из фрагментов или действий, вместо прямого вызова метода, я использую этот класс. В случае, если действие contextне является, nullоно возвращает значение актива, а в случае, если оно contextявляется нулевым, оно передает значение по умолчанию (которое также указывается вызывающей функцией).

Важно! Это не решение, это эффективный способ, с помощью которого вы можете изящно справиться с таким сбоем. Вы хотели бы добавить несколько журналов в случаях, когда вы получаете экземпляр активности как нулевой, и попытайтесь исправить это, если это возможно.

Эцио
источник
0

это происходит, когда фрагмент не имеет контекста, поэтому метод getActivity () возвращает значение null. проверьте, используете ли вы контекст перед тем, как его получить , или активность больше не существует. используйте context во фрагменте. Создайте, и после ответа API обычно возникает эта проблема.

поклонник Дексиана
источник
0

Иногда это исключение вызвано ошибкой в ​​реализации библиотеки поддержки. Недавно мне пришлось понизить рейтинг с 26.1.0 до 25.4.0, чтобы избавиться от него.

Bord81
источник
Нет, не знаю, но, возможно, я должен создать его.
Bord81
0

Эта проблема возникает всякий раз, когда вы вызываете контекст, который недоступен или имеет значение null при его вызове. Это может быть ситуация, когда вы вызываете контекст основного потока операций в фоновом потоке или контекст фонового потока в основном потоке действий.

Например, я обновил свою общую строку настроек следующим образом.

editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();

И вызвал finish () сразу после него. Теперь он выполняет коммит, выполняющийся в главном потоке, и останавливает любые другие асинхронные коммиты, если поступает, пока не завершится. Таким образом, его контекст жив, пока запись не завершена. Следовательно, предыдущий контекст является живым, вызывая ошибку.

Поэтому убедитесь, что ваш код перепроверен, если есть какой-то код, имеющий эту проблему контекста.

Прашант Паливал
источник
как вам удалось решить эту проблему? Я звоню в асинхронную ветку и сейчас испытываю эту проблему.
Саймон
Просто убедитесь, что операция записи завершена, тогда только контекст уничтожается не раньше, чем завершится операция записи.
Прашант Паливал,