Android DialogFragment и не удается запустить activity ComponentInfo после уничтожения / восстановления приложения

#java #android #android-dialogfragment #android-inflate

#java #Android #android-dialogfragment #android-раздуть

Вопрос:

У меня приложение работает нормально до одного очень специфического сценария.

  1. Я открываю диалоговое окно.
  2. Я завершаю работу приложения (используя SystemTuner)
  3. Я восстанавливаю приложение после того, как оно было убито.

Тогда мое приложение не запускается, и следующие сообщения находятся в LogCat.

     07-05 20:45:36.469: W/ResourceType(4866): No package identifier when getting value for resource number 0x00000000
07-05 20:45:36.469: W/dalvikvm(4866): threadid=1: thread exiting with uncaught exception (group=0x40a7b390)
07-05 20:45:36.469: E/AndroidRuntime(4866): FATAL EXCEPTION: main
07-05 20:45:36.469: E/AndroidRuntime(4866): java.lang.RuntimeException: Unable to start activity ComponentInfo{petersoft.petermemoflashcards/petermemo.android.gui.activities.MainActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x0
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1964)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1989)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.access$600(ActivityThread.java:126)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1155)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.os.Looper.loop(Looper.java:137)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.main(ActivityThread.java:4482)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at java.lang.reflect.Method.invokeNative(Native Method)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at java.lang.reflect.Method.invoke(Method.java:511)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at dalvik.system.NativeStart.main(Native Method)
07-05 20:45:36.469: E/AndroidRuntime(4866): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x0
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.content.res.Resources.getValue(Resources.java:1041)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.content.res.Resources.loadXmlResourceParser(Resources.java:2191)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.content.res.Resources.getLayout(Resources.java:880)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.view.LayoutInflater.inflate(LayoutInflater.java:394)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at petermemo.android.gui.dialogs.PMDialogFragment.onCreateView(PMDialogFragment.java:51)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at petermemo.android.gui.dialogs.DialogCardStats.onCreateView(DialogCardStats.java:61)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1877)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:552)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1133)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.Activity.performStart(Activity.java:4475)
07-05 20:45:36.469: E/AndroidRuntime(4866):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1937)
07-05 20:45:36.469: E/AndroidRuntime(4866):     ... 11 more
  

Существует часть кода диалога:

 public abstract class PMDialogFragment extends DialogFragment {

    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);

        setRetainInstance(true);  
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(layoutId, container);

        return view;
    }

@Override
    public void onDestroyView() {
        if (getDialog() != null amp;amp; getRetainInstance())
            getDialog().setDismissMessage(null);
        super.onDestroyView();
    }

}
  

Следующая строка вызывает исключение:

 View view = inflater.inflate(layoutId, container);
  

Пожалуйста, также обратите внимание, что, как я уже сказал, если приложение не уничтожено, оно работает полностью нормально. Даже если оно скрыто и восстановлено, проблем нет.

Я не имею ни малейшего представления, в чем причина проблем… Пожалуйста, помогите. 🙂

Добавлено позже:

Мне интересно, возможно, это может быть связано с тем фактом, что layoutId равен нулю. Я не вставлял ранее весь код, но класс PMDialogFragment используется дочерним классом следующим образом:

 public class DialogCardStats extends PMDialogFragment {

public static DialogCardStats newInstance (Fragment fragment, String fragmentTag, InterfaceCallback.Callback callback, Bundle bundle) {
        FragmentManager fm = fragment.getFragmentManager();
        DialogCardStats dialogCardStats = new DialogCardStats();
        dialogCardStats.setArguments(bundle);
        dialogCardStats.layoutId = R.layout.dialog_card_stats;
        dialogCardStats.registerCallbackListener(callback);
        dialogCardStats.show(fm, fragmentTag); 
        return dialogCardStats;
    }
  

Когда мой диалог отображается с использованием n, ewInstance значит layoutId , что он установлен правильно. Однако, когда оно автоматически восстанавливается Android, layoutId равно нулю. Как я должен сохранить важные поля класса?

Комментарии:

1. Почему вы «убиваете» свое приложение?

2. Чтобы проверить, что произойдет, когда Android его уничтожит. Будет ли оно затем восстановлено должным образом? И то, что я наблюдаю, нет.

3. Android не «убивает» приложения — он отключает их чисто. Я не знаю, что такое SystemTuner, но если это убийца задач, то это, вероятно, ваша проблема.

4. Я только что расширил описание проблемы. У меня сложилось впечатление, что это связано с неправильным сохранением состояния диалога.

Ответ №1:

Когда система повторно создает activity с фрагментами, которые были уничтожены, фрагменты, которые присутствовали на момент уничтожения, автоматически создаются и повторно добавляются в диспетчер фрагментов activity. Однако создание экземпляра в этом случае происходит посредством отражения, то есть автоматического вызова конструктора без аргументов ваших классов фрагментов. Следовательно, это повторное создание экземпляра не проходит через ваш newInstance статический метод.

Ошибка в этом случае — та, которую я лично совершил в старом проекте, поэтому я могу посочувствовать — заключается в том, что вы сохраняете значения путем прямого присвоения переменным экземпляра, например

 dialogCardStats.layoutId = R.layout.dialog_card_stats;
  

вместо использования пакета аргументов. Смотрите, пакет аргументов автоматически сохраняется и восстанавливается для вас, в то время как эти переменные экземпляра никогда не восстанавливаются после уничтожения активности / фрагмента и повторного создания.

Правильный способ сделать это — использовать пакет аргументов, например

 bundle.putInt(ARG_LAYOUT_ID, R.layout.dialog_card_stats);
  

где ARG_LAYOUT_ID — частная статическая конечная переменная (т. Е. константа) в DialogCardStats классе, затем снова использовать константу в onCreateView для извлечения идентификатора ресурса, например

 int layoutId = getArguments().getInt(ARG_LAYOUT_ID);
View view = inflater.inflate(layoutId, container);
  

и все должно работать нормально.

Комментарии:

1. Да, точно. Кажется, это решает проблему. Удивительно, но я использую решение, о котором вы пишете в других диалогах, но в этом случае я этого не сделал….. Спасибо за помощь.