Как приостановить/скрыть поток или процесс в Android?
Я хочу сделать паузу между двумя строками кода. Позвольте мне немного пояснить:
- > пользователь нажимает кнопку (фактически на карте), и я показываю ее, меняя фон этой кнопки:
thisbutton.setBackgroundResource(R.drawable.icon);
- > после того, как скажем 1 секунду, мне нужно вернуться к предыдущему состоянию кнопки, изменив ее фон:
thisbutton.setBackgroundResource(R.drawable.defaultcard);
- > Я попытался приостановить поток между этими двумя строками кода:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Однако это не работает. Может быть, это процесс, а не Thread, который мне нужно приостановить?
Я также пробовал (но это не работает):
new Reminder(5);
При этом:
public class Reminder {
Timer timer;
public Reminder(int seconds) {
timer = new Timer();
timer.schedule(new RemindTask(), seconds*1000);
}
class RemindTask extends TimerTask {
public void run() {
System.out.format("Time up!%n");
timer.cancel(); //Terminate the timer thread
}
}
}
Как приостановить/спящий поток или процесс?
Ответы
Ответ 1
Одним из решений этой проблемы является использование метода Handler.postDelayed(). Некоторые учебные материалы Google предлагают одно и то же решение.
@Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
}, 2000);
}
Однако некоторые из них указали, что вышеупомянутое решение вызывает утечку памяти, поскольку использует нестатический внутренний и анонимный класс, который неявно содержит ссылку на его внешний класс - активность. Это проблема, когда контекст активности - сбор мусора.
Более сложное решение, которое позволяет избежать утечки памяти подклассы Handler
и Runnable
со статическими внутренними классами внутри действия, поскольку статические внутренние классы не содержат неявной ссылки на их внешний класс:
private static class MyHandler extends Handler {}
private final MyHandler mHandler = new MyHandler();
public static class MyRunnable implements Runnable {
private final WeakReference<Activity> mActivity;
public MyRunnable(Activity activity) {
mActivity = new WeakReference<>(activity);
}
@Override
public void run() {
Activity activity = mActivity.get();
if (activity != null) {
Button btn = (Button) activity.findViewById(R.id.button);
btn.setBackgroundResource(R.drawable.defaultcard);
}
}
}
private MyRunnable mRunnable = new MyRunnable(this);
public void onClick(View view) {
my_button.setBackgroundResource(R.drawable.icon);
// Execute the Runnable in 2 seconds
mHandler.postDelayed(mRunnable, 2000);
}
Обратите внимание, что Runnable
использует WeakReference для Activity, что необходимо в статическом классе, которому необходим доступ к пользовательскому интерфейсу.
Ответ 2
Вы можете попробовать следующее: короткий
SystemClock.sleep(7000);
ПРЕДУПРЕЖДЕНИЕ. Никогда, никогда, не делайте этого в потоке пользовательского интерфейса.
Используйте это для сна, например. фоновый поток.
Полное решение для вашей проблемы будет:
Это доступный API 1
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View button) {
button.setBackgroundResource(R.drawable.avatar_dead);
final long changeTime = 1000L;
button.postDelayed(new Runnable() {
@Override
public void run() {
button.setBackgroundResource(R.drawable.avatar_small);
}
}, changeTime);
}
});
Без создания обработчика tmp. Также это решение лучше, чем @tronman, потому что мы не сохраняем представление обработчиком.
Также у нас нет проблем с Handler, созданным при плохом потоке;)
Документация
public static void sleep (long ms)
Добавлен в уровень API 1
Ожидает заданное количество миллисекунд (от uptimeMillis) перед возвратом. Аналогично sleep (long), , но не выбрасывает InterruptedException; interrupt() откладываются до тех пор, пока следующая прерывистая операция. не возвращает, пока не истечет указанное количество миллисекунд.
Параметры
ms для сна перед возвратом в миллисекундах времени безотказной работы.
Код postDelayed из класса просмотра:
/**
* <p>Causes the Runnable to be added to the message queue, to be run
* after the specified amount of time elapses.
* The runnable will be run on the user interface thread.</p>
*
* @param action The Runnable that will be executed.
* @param delayMillis The delay (in milliseconds) until the Runnable
* will be executed.
*
* @return true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the Runnable will be processed --
* if the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*
* @see #post
* @see #removeCallbacks
*/
public boolean postDelayed(Runnable action, long delayMillis) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.postDelayed(action, delayMillis);
}
// Assume that post will succeed later
ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
return true;
}
Ответ 3
Я использую это:
Thread closeActivity = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
// Do some stuff
} catch (Exception e) {
e.getLocalizedMessage();
}
}
});
Ответ 4
Вы, вероятно, не хотите так поступать. Поместив явный sleep()
в обработчик событий с нажатием кнопки, вы фактически заблокируете весь пользовательский интерфейс на секунду. Один из вариантов - использовать какой-то одноразовый Timer. Создайте TimerTask, чтобы изменить цвет фона на цвет по умолчанию и назначьте его на таймер.
Другая возможность - использовать Handler. Там учебник о том, кто переключился с использования таймера на использование обработчика.
Кстати, вы не можете приостановить процесс. Процесс Java (или Android) имеет по крайней мере 1 поток, и вы можете выполнять только потоки.
Ответ 5
Я использую CountDownTime
new CountDownTimer(5000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
// do something after 1s
}
@Override
public void onFinish() {
// do something end times 5s
}
}.start();
Ответ 6
Это то, что я сделал в конце дня, теперь прекрасно работает:
@Override
public void onClick(View v) {
my_button.setBackgroundResource(R.drawable.icon);
// SLEEP 2 SECONDS HERE ...
final Handler handler = new Handler();
Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
});
}
}, 2000);
}
Ответ 7
В дополнение к ответам г-на Янковского вы также можете использовать postDelayed()
. Это доступно для любого View
(например, вашей карты) и занимает Runnable
и период задержки. После этой задержки он выполняет Runnable
.
Ответ 8
Это мой пример
Создайте Java-утилиты
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
public class Utils {
public static void showDummyWaitingDialog(final Context context, final Intent startingIntent) {
// ...
final ProgressDialog progressDialog = ProgressDialog.show(context, "Please wait...", "Loading data ...", true);
new Thread() {
public void run() {
try{
// Do some work here
sleep(5000);
} catch (Exception e) {
}
// start next intent
new Thread() {
public void run() {
// Dismiss the Dialog
progressDialog.dismiss();
// start selected activity
if ( startingIntent != null) context.startActivity(startingIntent);
}
}.start();
}
}.start();
}
}
Ответ 9
Или вы можете использовать:
android.os.SystemClock.sleep(checkEvery)
который имеет то преимущество, что не требует обертывания try... catch
.
Ответ 10
Если вы используете Kotlin и сопрограммы, вы можете просто сделать
GlobalScope.launch {
delay(3000) // In ms
//Code after sleep
}
И если вам нужно обновить интерфейс
GlobalScope.launch {
delay(3000)
GlobalScope.launch(Dispatchers.Main) {
//Action on UI thread
}
}
Ответ 11
Я знаю, что это старая тема, но в документации по Android я нашел решение, которое мне очень помогло...
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
mTextField.setText("done!");
}
}.start();
https://developer.android.com/reference/android/os/CountDownTimer.html
Надеюсь, это поможет кому-то...