Использование RunOnUIThread вызывает исключение нулевого указателя после переключения на другой фрагмент

public class ViewPagerTask extends TimerTask {
    @Override
    public void run() {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (viewPager.getCurrentItem() == 0){
                    viewPager.setCurrentItem(1);
                } else if (viewPager.getCurrentItem() == 1){
                    viewPager.setCurrentItem(2);
                } else  viewPager.setCurrentItem(0);
            }
        });
    }
}

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

ошибка

E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: com.example.android.indianmetro, PID: 5150
java.lang.NullPointerException: Attempt to invoke virtual method 'void 
android.support.v4.app.FragmentActivity.runOnUiThread(java.lang.Runnable)' 
on a null object reference
    at com.example.android.indianmetro.HomeFragment$ViewPagerTask.run(HomeFragment.java:258)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
E/AbstractTracker: Can't create handler inside thread that has not called 
Looper.prepare()

3 ответа

Решение

Первое, вы должны понимать о потоках в Android. В Android у нас есть поток под названием MainUIThread. Я не уверен, что это основной поток или нет. Тем не менее, он имеет экземпляр Looper учебный класс.

Ваш исходный фрагмент по умолчанию работает на MainUIThread. Когда вы создаете подкласс TimerTask, вы создаете новый Runnable для запуска вашего источника в другом потоке, верно?

Ваше сообщение об ошибке java.lang.NullPointerException означает, что возвращаемое значение getActivity() метод null, Хорошее место для начала - JavaDocs. У них есть это покрыто:

Брошенный, когда приложение пытается использовать нуль в случае, когда объект требуется. Они включают:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Принимая длину нуля, как если бы это был массив.
  • Доступ или изменение пустых слотов, как если бы это был массив.
  • Бросить ноль, как если бы это было значение Throwable.

Приложения должны генерировать экземпляры этого класса, чтобы указать на другое незаконное использование нулевого объекта.

Решение для вас:

  1. Позвольте проверить и убедитесь, что вы не заканчиваете деятельность. (Другой случай, когда вы отсоединяете этот фрагмент под названием Activity. Поскольку вы используете ViewPager, я полагаю, что вы проводите два раза влево или вправо. По умолчанию он автоматически отсоединяет ваш фрагмент.) Попробуйте отказаться от него.
  2. Если вам нужно закончить свою активность, которая содержит ваш фрагмент или отсоединить ваш фрагмент. Простой способ проверяется нулевым перед вызовом runOnUiThread() метод.

    public class ViewPagerTask extends TimerTask {
        @Override
        public void run() {
            Activity activity = getActivity();
            if (activity != null) {
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (viewPager.getCurrentItem() == 0) {
                            viewPager.setCurrentItem(1);
                        } else if (viewPager.getCurrentItem() == 1) {
                            viewPager.setCurrentItem(2);
                        } else {
                            viewPager.setCurrentItem(0);
                        }
                    }
                });
            }
        }
    }
    

Ваш TimerTask срабатывает после удаления фрагмента. В таком случае, getActivity() вернет ноль и, следовательно, исключение.

Я могу предложить два варианта:

  1. назначить вывод getActivity() для локальной переменной, когда TimeTask уволен, проверьте и используйте, если не ноль.
  2. отменить свой TimerTask в onDetach(). Это рекомендуемый подход.
      public class The_slide_timer extends TimerTask {
        @Override
        public void run() {
            Activity activity = getActivity();

            if (activity != null) {
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if (page.getCurrentItem() < listItems.size() - 1) {
                            page.setCurrentItem(page.getCurrentItem() + 1);
                        } else
                            page.setCurrentItem(0);
                    }
                });

            }
        }
    }

просто проверяю, является ли активность нулевой или нет, просто решаю проблемы.

Другие вопросы по тегам