Как приостановить / спать поток или процесс в Android? - PullRequest
274 голосов
/ 05 октября 2009

Я хочу сделать паузу между двумя строками кода, позвольте мне объяснить немного:

-> пользователь нажимает кнопку (фактически карту), и я показываю ее, изменяя фон этой кнопки:

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();
}

Однако это не работает. Может быть, мне нужно приостановить процесс, а не поток?

Я тоже пробовал (но это не работает):

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's up!%n");
                timer.cancel(); //Terminate the timer thread
            }
        }  
    }

Как я могу приостановить / перевести нить или процесс?

Ответы [ 11 ]

438 голосов
/ 14 июня 2010

Одним из решений этой проблемы является использование метода 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, что необходимо в статическом классе, которому требуется доступ к пользовательскому интерфейсу.

181 голосов
/ 31 января 2013

Вы можете попробовать это, это короткий

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) перед возвратом. Аналогичен режиму сна (long), , но не создает InterruptedException ; События interrupt () откладываются до Следующая прерываемая операция. не возвращает , пока не истечет хотя бы указанное количество миллисекунд.

Параметры

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

Код для postDelayed из View class:

/**
 * <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;
}
24 голосов
/ 27 марта 2012

Я использую это:

Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});
16 голосов
/ 05 октября 2009

Вы, вероятно, не хотите делать это таким образом. Поместив явный sleep() в обработчик событий, нажимаемый кнопкой, вы фактически заблокируете весь пользовательский интерфейс на секунду. Один из вариантов - использовать какой-то один кадр Таймер . Создайте TimerTask , чтобы изменить цвет фона обратно на цвет по умолчанию, и запланируйте его на таймере.

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

Кстати, вы не можете приостановить процесс. Процесс Java (или Android) имеет как минимум 1 поток, и вы можете только спящие потоки.

12 голосов
/ 24 октября 2014

Я использую 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(); 
9 голосов
/ 17 октября 2009

Это то, что я сделал в конце дня - теперь работает нормально:

@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); 
    }
8 голосов
/ 05 октября 2009

В дополнение к ответам г-на Янковского, вы также можете использовать postDelayed(). Это доступно для любого View (например, вашей карты) и занимает Runnable и период задержки. После этой задержки выполняется Runnable.

4 голосов
/ 06 января 2018

Или вы можете использовать:

android.os.SystemClock.sleep(checkEvery)

, преимущество которого заключается в том, что не требуется упаковка try ... catch.

4 голосов
/ 25 октября 2011

Это мой пример

Создание Java Utils

    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();  

        }

    }    
0 голосов
/ 01 мая 2019

Я знаю, что это старая тема, но в документации по 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...