WedX - журнал о программировании и компьютерных науках

Как прервать поток onBackPressed без сбоя?

Я попытался переопределить onBackPressed, чтобы не только завершить текущее действие, но и прервать поток, поскольку я вызываю намерение для следующего действия внутри. Когда я нажимал назад раньше, активность всплеска заканчивалась, но поток продолжал работать и вызывал намерение для следующей активности. Теперь, когда я включил прерывание потока в BackPressed, приложение вылетает, когда я нажимаю назад. Что я делаю неправильно?

skipscreen.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            SharedPreferences savestate = getSharedPreferences("skip", MODE_PRIVATE);
            savestate.edit().putBoolean("skip", true).apply();
            skip= true;
            homeintent();
        }
    });
    Thread splashthread = new Thread() {
        @Override
        public void run() {
                try {
                    sleep(3000);
                    if (!skip) { homeintent();}
                } catch (InterruptedException Interrupt) {
                    Interrupt.printStackTrace();
                }
            }
    };
    splashthread.start();
}
private void homeintent() {
    Intent i = new Intent(splash.this, home.class);
    startActivity(i);
    finish();
}
@Override
public void onBackPressed() {
    splashthread.interrupt();
    finish();
  }
}

ОБНОВЛЕНО: (это решение сработало для меня).

skipscreen.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View view) {
            SharedPreferences savestate = getSharedPreferences("skip", MODE_PRIVATE);
            savestate.edit().putBoolean("skip", true).apply();
            skip= true;
            homeintent();
        }
    });
    Thread splashthread = new Thread() {
        @Override
        public void run() {
                try {
                    sleep(3000);
                    if (!skip) { homeintent();}
                } catch (InterruptedException Interrupt) {
                    Interrupt.printStackTrace();
                }
            }
    };
    splashthread.start();
}
private void homeintent() {
    if (!ThreadInterrupted) {
           Intent i = new Intent(splash.this, home.class);
           startActivity(i);
   }
           finish();
}
@Override
public void onBackPressed() {
        SharedPreferences savestate= getSharedPreferences("ThreadInterrupted", MODE_PRIVATE);
        savestate.edit().putBoolean("ThreadInterrupted", true).apply();
        ThreadInterrupted = true;
        homeintent();
    }
}

  • Вы пробовали простую нулевую проверку в homeintent() , то есть if(splash.this!=null) ? 29.09.2015
  • Какое исключение вы получаете? Вы можете опубликовать свою трассировку стека? 29.09.2015
  • Ссылка spashthread является локальной для onClickListener. Вам нужно назначить его глобальной ссылке и поставить проверку нулевого указателя, как сказал @Droidekas. 29.09.2015
  • Я только что заметил, но я не думаю, что ваш код скомпилируется. 29.09.2015
  • Я попробовал ваше предложение, @Droidekas, но, вероятно, я что-то упустил. Он фактически скомпилирован (обратите внимание, что я упростил имена элементов перед публикацией вопроса, чтобы другим учащимся было легче ориентироваться в коде. 29.09.2015

Ответы:


1

Чтобы дать вам краткий ответ, а также объяснить, как это сделать в будущем, взгляните на Handler и Handler.postDelayed().

 private Handler homeIntenthandler;
    @Override
    protected void onCreate(){

    //other things
        skipscreen.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                SharedPreferences savestate = getSharedPreferences("skip", MODE_PRIVATE);
                savestate.edit().putBoolean("skip", true).apply();
                skip= true;
                homeintent();
            }
        });

//initialise handler and set timer;
        homeIntenthandler= new Handler();
        homeIntenthandler.postDelayed(new Runnable() {
            @Override
            public void run() {
               homeintent();
            }
        },3000);
    }
    }
    private void homeintent() {
        Intent i = new Intent(splash.this, home.class);
        startActivity(i);
        finish();
    }
    @Override
    public void onBackPressed() {
      if(homeIntenthandler!=null)
        homeIntenthandler.removeCallbacksAndMessages(null)
        finish();
      }
    }

Handler.removeCallbacksAndMessages(null) основан на документации, предоставленной для то же самое

29.09.2015
  • Как вы думаете, лучше использовать обработчик, а не поток для экрана-заставки? Ваш код выглядит совершенно правильно. Кстати, что вы думаете об обновленном коде? Это точно? 29.09.2015
  • Обработчик предназначен для таких целей. И да, обновленный код будет работать. Но вы поддерживаете много необходимого кода, такого как общие настройки и сохраненное состояние, которого можно избежать. 29.09.2015
  • Я думаю ты прав. Позвольте мне попробовать, и я вернусь к решению вопроса. 29.09.2015

  • 2

    Когда вы вызываете метод interrupt() в своем потоке, находясь в спящем режиме, будет выброшено InterruptedException.

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

     Thread splashthread = new Thread() {
        @Override
        public void run() {
               while (shouldContinue) {
                      doSomeWork();
               }
       }
    };
    

    Затем вы можете изменить shouldContinue на false в методе onBackPressed:

    @Override
    public void onBackPressed() {
           shouldContinue = false;
           finish();
    }
    
    29.09.2015
  • Я попробовал этот способ и даже добавил дополнительную общую настройку для сохранения логического состояния, но не повезло. 29.09.2015
  • Нет необходимости использовать SharedPreferences. Можете ли вы опубликовать свою трассировку стека? 29.09.2015
  • На самом деле, я просто решил это, изменив вашу идею в некоторых вещах. Я опубликую редактирование через секунду. 29.09.2015

  • 3

    Уди я ответил на ваш вопрос. Но я рекомендую вам использовать TimerTask и Таймер вместо Thread.

    Timer timer;
    TimerTask timertask;
    timer = new Timer();
    timertask = new TimerTask() {
        @Override
        public void run() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                   homeintent();        
                }
            });
        }
    };
    timer.schedule(timertask, 3000);
    
    @Override
    public void onBackPressed() {
        if(timertask!=null){
            timertask.cancel();
        }
        if(timer!=null){
            timer.cancel();
        }
        finish();
    }
    
    29.09.2015
  • Таймер иногда не является хорошим выбором, так как Android говорит: «Если в данный момент выполняется задача, на нее это не влияет, а это означает, что если цикл продолжается, таймер не будет отменен до тех пор, пока цикл не завершит свое выполнение. Но с помощью потока и размещения логической проверки внутри цикла мы можем решить эту проблему. 29.09.2015

  • 4

    Вы можете создать изменчивую проверку boolean, чтобы остановить выполнение потока, см. следующий код:

    private volatile boolean cancelled = false;
    
    Thread splashthread = new Thread() {
        @Override
        public void run() {
                if ( cancelled ) {
                  return; // or handle this however you want
                }else{
                  // do what ever you want to do here
                }
            }
    };
    splashthread.start();
    

    И в onBackPressed сделайте что-то вроде этого:

    @Override
    public void onBackPressed() {
        cancelled = true;
        finish();
    }
    

    Рекомендуется использовать ключевое слово volatile, потому что, как правило, поток, выполняющий отмену, не обязательно будет тем же потоком, который отменяется. Пометка boolean check как volatile гарантирует, что поток, проверяющий флаг, увидит актуальное значение.

    29.09.2015
  • Я использовал изменчивое логическое значение для обновленного решения (просто не публиковал весь код). Спасибо! 29.09.2015
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

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

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]