web-dev-qa-db-ja.com

Androidでスレッドまたはプロセスを一時停止/スリープさせるには?

2行のコードの間を一時停止したいのですが、少し説明しましょう。

- >ユーザーがボタン(実際にはカード)をクリックすると、このボタンの背景を変更することで表示されます。

thisbutton.setBackgroundResource(R.drawable.icon);

- > 1秒後に、背景を元に戻してボタンの前の状態に戻る必要があります。

thisbutton.setBackgroundResource(R.drawable.defaultcard);

- >この2行のコードの間のスレッドを一時停止しようとしました。

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
            }
        }  
    }

スレッドまたはプロセスを一時停止/スリープさせるにはどうすればよいですか?

271
Hubert

この問題に対する一つの解決策は Handler.postDelayed() メソッドを使うことです。いくつかのグーグル トレーニング資料 は同じ解決策を提案する。

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

しかし、 の上の解決策はメモリリークを起こすと指摘している それは暗黙のうちにその外側のクラスであるアクティビティへの参照を保持している非静的な内側および匿名クラスを使用するため。これは、アクティビティコンテキストがガベージコレクションされている場合に問題になります。

静的な内部クラスはそれらの外部クラスへの暗黙の参照を保持していないので、メモリリークを回避するより複雑な解決策はアクティビティ内の静的な内部クラスでHandlerRunnableをサブクラス化します。

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はActivityに WeakReference を使用していることに注意してください。これはUIへのアクセスを必要とする静的クラスで必要です。

435
tronman

これを試すことができますそれは short です

SystemClock.sleep(7000);

_ warning _ :UIスレッドでは絶対にしないでください。

これを使って眠りましょう。バックグラウンドスレッド.


あなたの問題に対する完全な解決策はのようになります:これは利用可能な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 Handlerを作成せずに。 Handlerによる見解を保持していないため、この解決策は@tronmanよりも優れています。また、悪いスレッドで作成されたHandlerには問題ありません。

ドキュメンテーション

パブリックスタティックボイドスリープ(長ミリ秒)

APIレベル1で追加

戻る前に、指定されたミリ秒数(uptimeMillis)待機します。 sleep(long)と同様に、 ですがInterruptedExceptionをスローしません ; interrupt()イベントは、次の割り込み可能な操作まで延期されます。 指定されたミリ秒数が経過するまで を返しません。

パラメーター

ms 戻る前にスリープ状態になるまでの時間(ミリ秒)。

Viewクラスからの 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;
}
179
Dawid Drozd

私はこれを使う:

Thread closeActivity = new Thread(new Runnable() {
  @Override
  public void run() {
    try {
      Thread.sleep(3000);
      // Do some stuff
    } catch (Exception e) {
      e.getLocalizedMessage();
    }
  }
});
24
Byt3

あなたはおそらくそのようにしたくないでしょう。ボタンをクリックしたイベントハンドラに明示的なsleep()を設定すると、実際にはUI全体が1秒間ロックされます。 1つの選択肢は、ある種のシングルショット タイマー を使うことです。 TimerTask を作成して背景色をデフォルトの色に戻し、タイマーでスケジュールします。

もう一つの可能​​性は ハンドラ を使うことです。 チュートリアル Timerを使うことからHandlerを使うことに切り替えた人についての/があります。

ちなみに、あなたはプロセスを一時停止することはできません。 Java(またはAndroid)プロセスには少なくとも1つのスレッドがあり、スリープできるのはスレッドだけです。

16

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

これは私が一日の終わりにしたことです - 今うまく働きます:

@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); 
    }
9
Hubert

ヤンコフスキー氏の答えに加えて、postDelayed()を使うこともできます。これはどのView(例えばあなたのカード)でも利用でき、Runnableと遅延期間がかかります。その遅延後にRunnableが実行されます。

8
CommonsWare

これは私の例です

Java Utilを作成する

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

        }

    }    
4
Stefano

またはあなたが使用することができます:

Android.os.SystemClock.sleep(checkEvery)

これはtry ... catchをラッピングする必要がないという利点があります。

4
aaaa

私はこれが古いスレッドであることを知っています、しかし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

これが誰かに役立つことを願っています...

0
John Byrne

Kotlinと コルーチン を使えば、簡単にできます。

GlobalScope.launch {
   delay(3000) // In ms
   //Code after sleep
}

そしてあなたがUIを更新する必要があるなら

GlobalScope.launch {
  delay(3000)
  GlobalScope.launch(Dispatchers.Main) {
    //Action on UI thread
  }
}
0
Guillaume