Androidでスレッドまたはプロセスを一時停止/スリープする方法は?


294

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

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


4
ああ、クラシックなスレッドポーズブロックを使用してください:while(true){}
KristoferA

6
@ KristoferA-Huagati.com皮肉なのか、確かにDalvik / Androidの魔法があるので、これがAndroidで受け入れられるかどうかはわかりません。明確にしていただけますか?疑問に思って申し訳ありません(!conditionCheck()) {}が、通常はお勧めできませんのでお願いします。
悲惨な変数

「しかし、これは機能しません。」「私も試しました(しかし、うまくいきません)」これは、症状を示さずに問題があると言う典型的な例です。これらの試みがどのようにして要件を満たさなかったのですか?スレッドは一時停止しませんでしたか?エラーメッセージが表示されましたか?
LarsH

回答:


454

この問題の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); 
}

ただし、上記のソリューションでは、外部クラスであるアクティビティへの参照を暗黙的に保持する非静的な内部および匿名クラスを使用するため、メモリリークが発生することを指摘する人もいます。これは、アクティビティコンテキストがガベージコレクションされている場合の問題です。

静的内部クラスはそれらの外部クラスへの暗黙的な参照を保持しないため、メモリリークを回避するより複雑なソリューションは、静的内部クラスをアクティビティ内にサブクラス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);
}

は、UIへのアクセスを必要とする静的クラスで必要なアクティビティへのWeakReferenceRunnable使用することに注意してください。


3
それは機能しますが、コード全体に遅延を導入するにはかなり不便な方法ですよね?
Ehtesh Choudhury、2012

4
「不便」とはどういう意味かわかりません。ハンドラーのpostDelayedメソッドは、一定の時間が経過した後に少しのコードを実行するようにAndroidに指示するように設計されています。
トロンマン、2012

27
2年後、このコードは私を助けました!@tronmanに感謝!! :)
Melvin Lai

2
これを別の(最終的な)変数にコピーして、ハンドラーとRunnableでfinal Button mynewbutton = mybutton;使用できますmynewbutton
Dzhuneyt 2013年

2
5年後の@MelvinLaiとこのコードは私を助けてくれました!:)
gabrieloliveira 2015年

191

短いので試してみてください

SystemClock.sleep(7000);

警告: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ハンドラを作成せずに。また、ハンドラーによるビューを保持しないため、このソリューションは@tronmanよりも優れています。また、不正なスレッドで作成されたハンドラーにも問題はありません;)

ドキュメンテーション

public static void sleep(長いミリ秒)

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

22
そして、Android UIをフリーズさせますか?これを行わないでください。
shkschneider 2013

3
Ctrl + Shift + O(Eclipse自動インポート)
Dawid Drozd '17

13
Gelldur、@ RichieHHのコメントのポイントを逃しています。あなたが投稿する3年前に受け入れられ回答と比較して、あなたが提案することはOPが彼の問題を解決するのを助けません。理由:OPで示されているコードと、受け入れられた回答に示されているコードの両方が、UIハンドラー内で実行されています。OMG of course do this in background threadそれをバックグラウンドスレッドに配置する方法を示さない限り、言うことは無関係です。その時点で、すでに受け入れられている答えよりも複雑な答えがあることに気づくでしょう。より良い解決策が3年前に受け入れられたことを私は言及しましたか?:P
ToolmakerSteve

2
...この提案が質問に対して特に目的外であるのは、OPが遅延後にUIアクションを明示的に実行することであることを言及するのを忘れていました。したがって、バックグラウンドスレッドを作成し(既に問題を解決するために必要なものよりも重い)、スリープ状態にした後、(なんらかの理由で)UIスレッドに戻る必要がある解決策があります。Handler + postRunnableこれらすべてを1つのステップで実行します。2番目のスレッドを作成するシステムオーバーヘッドなし。
ToolmakerSteve

2
@ToolmakerSteve幸せになりました:D?主な質問は次のとおりです。「Androidでスレッドまたはプロセスを一時停止/スリープする方法」だから私の答えは簡単だった:)。「スレッドのスリープ方法」をググったら、この質問が表示されます。彼/彼女はおそらく私の答えを探しています:P。しかし、私は完全な応答を追加しました;)
Dawid Drozd 2016年

28

私はこれを使います:

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

4
何をするe.getLocalizedMessage()ことになっていますか?
Philipp Reichart

シンプルで一般的で迅速な例外メッセージが必要な場合、e.getLocalizedMessage()を使用します
Byt3

1
しかし、OPがUIクリックメソッド内で問い合わせる状況では、これを行わないでください。UIはさらに更新されます。承認されたHandler/postDelayedソリューションには2つの利点があります。(1)2番目のスレッドのシステムオーバーヘッドを回避する、(1)UIスレッドで実行されるので、例外を発生させずにUIを変更できます。
ToolmakerSteve

1
質問の主な目的とは直接関係はありませんが、例外をキャッチするべきではありません。むしろ、InterruptedExceptionをキャッチします。Exceptionをキャッチすることで、問題が発生する可能性のあるすべてのものをキャッチし、そうでなければキャッチした問題を隠すことができます。
Herve Thu

16

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

別の可能性はHandlerを使用することです。タイマーの使用からハンドラーの使用に切り替えた人に関するチュートリアルがあります。

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


14

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

これは便利です。
UzaySan

9

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

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

2
postDelayedしないのはなぜですか?タイマーは必要ありません。
RichieHH 14

8

ヤンコウスキー氏の回答に加えて、も使用できますpostDelayed()。これは任意のViewカード(カードなど)で利用可能でRunnable、遅延時間がかかります。Runnableその後の遅延を実行します。


5

これは私の例です

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

        }

    }    

3
さらに別の回答は、質問が既に十分に解決されてから数年後に追加されたものであり、UI作業を実行できるという前述の要望に対応していないため、質問には関係ありません。新しいスレッドで実行しているため、ここではUI作業を実行できません。UIスレッド上ではありません。
ToolmakerSteve

1
UX側では、ユーザーにデータをロードするためのブロックダイアログを表示するのは好ましくない...
2Dee 2015年

4

または、次のように使用できます。

android.os.SystemClock.sleep(checkEvery)

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


0

Kotlinとコルーチンを使用する場合は、簡単に行うことができます

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

UIを更新する必要がある場合

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

0

私はこれが古いスレッドであることを知っていますが、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
  class MyActivity{
    private final Handler handler = new Handler();
    private Runnable yourRunnable;
    protected void onCreate(@Nullable Bundle savedInstanceState) {
       // ....
       this.yourRunnable = new Runnable() {
               @Override
               public void run() {
                   //code
               }
            };

        this.handler.postDelayed(this.yourRunnable, 2000);
       }


     @Override
  protected void onDestroy() {
      // to avoid memory leaks
      this.handler.removeCallbacks(this.yourRunnable);
      }
    }

そして、確かに、トロンマンの回答に記載されている「静的クラス」メソッドと組み合わせることができることを確認してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.