Androidで遅延後にメソッドを呼び出す方法


770

指定した遅延後に次のメソッドを呼び出すことができるようにしたいと思います。目的cでは、次のようなものがありました。

[self performSelector:@selector(DoSomething) withObject:nil afterDelay:5];

AndroidのJavaでこのメソッドに相当するものはありますか?たとえば、5秒後にメソッドを呼び出せるようにする必要があります。

public void DoSomething()
{
     //do something here
}

回答:


1859

コトリン

Handler().postDelayed({
  //Do something after 100ms
}, 100)


ジャワ

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);



109
このソリューションは、UIスレッドでのみ役立ちます。それ以外の場合、通常のスレッドでは、私が思う最高のバージョンではないルーパーを実装する必要があります
olivier_sdg

2
@olivier_sdgなぜルーパーを実装する必要があるのですか?
djechlin 2013年

37
@djechlinハンドラーは常にルーパーにリンクする必要があります。ルーパーは、実際に投稿したRunnableを処理します。UIスレッドにはすでにルーパーが付属しているため、UIスレッドで新しいHandler()を作成し、それに直接Runnableをpost()できます。これらのRunnableは、UIスレッドで実行されます。Runnablesを別のスレッドで実行するには、新しいスレッドを作成し、次にLooper.prepare()、新しいHandler()、次にLooper.loop()を作成する必要があります。この新しいハンドラーにポストされたRunnableは、この新しいスレッドで実行されます。これをすべて行わないと、post()は例外をスローします。
Dororo

12
場合は、あなたは、あなたもすることができますする必要があり、キャンセルのRunnableを呼び出すことにより、メッセージキューに残っている限り、実行をremoveCallbacks(Runnable r)Handler
デニス

9
べきimport android.os.handler
カカ

322

私の場合、他の答えはどれも使用できませんでした。代わりにネイティブJavaタイマーを使用しました。

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // this code will be executed after 2 seconds       
    }
}, 2000);

43
ハンドラーがUIスレッドで実行されていない場合、ルーパーの問題がないため、これはハンドラーを使用するものよりも優れています。
Ben H

32
Androidドキュメントによると、タイマーが不要になったときにそれをキャンセルするために、タイマーへの参照を保持する必要があります。明示的にキャンセルされないタイマーは、無期限にリソースを保持する可能性があります。」
Pooksの

14
注意!これはUIスレッドでは実行されません。これをuiスレッドで実行すると致命的なエラーが発生しました:android.view.ViewRootImpl $ CalledFromWrongThreadException:ビュー階層を作成した元のスレッドのみがそのビューにアクセスできます。
vovahost 2015年

13
@vovahostこれは、タイマーブロック内のUIコンポーネントを更新しているためです
Tim

10
java.util.Timer(およびTimerTask)はJDK 9で非推奨になることに注意してください。TimerTaskは、あまり良くないタスクの新しいスレッドを作成します。
Varvara Kalinina 2017年

183

注:この回答は、質問でAndroidがコンテキストとして指定されていない場合に出されました。Android UIスレッドに固有の回答については、こちらをご覧ください。


Mac OS APIは現在のスレッドを継続させ、タスクを非同期で実行するようにスケジュールしているようです。Javaでは、同等の機能がjava.util.concurrentパッケージによって提供されます。Androidがどのような制限を課すかわかりません。

private static final ScheduledExecutorService worker = 
  Executors.newSingleThreadScheduledExecutor();

void someMethod() {
  
  Runnable task = new Runnable() {
    public void run() {
      /* Do something… */
    }
  };
  worker.schedule(task, 5, TimeUnit.SECONDS);
  
}

3
これでRunnableが呼び出されることはありません
Supuhstar

14
補足:これにより、後でタスクをキャンセルすることもできます。これは、状況によっては役立つ場合があります。ScheduledFuture<?>返されたへの参照を格納し、worker.schedule()そのcancel(boolean)メソッドを呼び出すだけです。
デニス

この答えは時代遅れだと思います。.scheduleはRunnableのメソッドではなくなったようです...?:/
beetree

5
@beetreeそれはのメソッドScheduledExecutorServiceです。
エリクソン2015年

3
これは、UIスレッドオブジェクトが関係する場合は機能しません。runOnUIThread(new runnable(){run()....});を呼び出す必要があります。または、run(){}内からハンドラーオブジェクトを使用してランナブルを投稿します
Jayant Arora

107

5秒後にUIスレッドで何かを実行する場合:

new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something here
    }
}, 5000);

8
確認してください。これは、looper.prepareの呼び出しを防ぎ、すべてをUIスレッドに配置するための最良のソリューションです。
Tobliug、2015年

このおかげで、ルーパーの問題で私を助けました:)
Tia

1
メインルーパーでハンドラーを作成する場合は注意が必要です。このスレッドでは、長時間のタスクを実行しないでください
Shayan_Aryan

40

UIThread内でハンドラーを使用できます。

runOnUiThread(new Runnable() {

    @Override
    public void run() {
         final Handler handler = new Handler();
         handler.postDelayed(new Runnable() {
           @Override
           public void run() {
               //add your code here
           }
         }, 1000);

    }
});

36

すばらしい回答をありがとう、私は自分のニーズに最適なソリューションを見つけました。

Handler myHandler = new DoSomething();
Message m = new Message();
m.obj = c;//passing a parameter here
myHandler.sendMessageDelayed(m, 1000);

class DoSomething extends Handler {
    @Override
    public void handleMessage(Message msg) {
      MyObject o = (MyObject) msg.obj;
      //do something here
    }
}

このアプローチを使用してアイテムのクリック時にタッチフィードバックを取得しても問題ありません。view.setColor(some_color)で、x秒後にハンドラーでこの色を削除します...?
eRaisedToX 2017年

25

KotlinJava多くの方法

1.使用 Handler

Handler().postDelayed({
    TODO("Do something")
    }, 2000)

2. TimerTaskの使用

Timer().schedule(object : TimerTask() {
    override fun run() {
        TODO("Do something")
    }
}, 2000)

またはもっと短い

Timer().schedule(timerTask {
    TODO("Do something")
}, 2000)

または最短になります

Timer().schedule(2000) {
    TODO("Do something")
}

3.使用 Executors

Executors.newSingleThreadScheduledExecutor().schedule({
    TODO("Do something")
}, 2, TimeUnit.SECONDS)

Javaで

1.使用 Handler

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something
    }
}, 2000);

2.使用 Timer

new Timer().schedule(new TimerTask() {          
    @Override
    public void run() {
        // Do something
    }
}, 2000);

3.使用 ScheduledExecutorService

private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();

Runnable runnable = new Runnable() {
  public void run() {
      // Do something
  }
  };
worker.schedule(runnable, 2, TimeUnit.SECONDS);

1
@JanRabeご提案ありがとうございます。私はそれをappriciateします。しかし質問ですHow to call a method after a delay in Android。それで私はそれについて考えました。ポイントへ。それ以外の場合、Javaリークは、開発者が個別に理解する大きなトピックです。
ケムラジ

20

このデモをご覧ください:

import java.util.Timer;
import java.util.TimerTask;

class Test {
     public static void main( String [] args ) {
          int delay = 5000;// in ms 

          Timer timer = new Timer();

          timer.schedule( new TimerTask(){
             public void run() { 
                 System.out.println("Wait, what..:");
              }
           }, delay);

           System.out.println("Would it run?");
     }
}

20

ハンドラーを使用する必要があるが、別のスレッドを使用runonuithreadしている場合は、を使用してUIスレッドでハンドラーを実行できます。これにより、呼び出しを要求してスローされた例外からあなたを救いますLooper.Prepare()

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //Do something after 1 second
            }
        }, 1000);
    }
});

かなり乱雑に見えますが、これはその方法の1つです。


4
これは機能します。編集する最小6文字の愚かなSOルールのため、投稿を編集できませんが、「(新しいハンドラ)」の後に「()」がありません。「新しいハンドラ()」でなければなりません
Jonathan Muller

2
すべてをUIスレッドに配置する代わりに、次のことができます。new Handler(Looper.getMainLooper())
Tobliug

17

私はView.postDelayed()メソッド、以下の簡単なコードを使用することを好みます:

mView.postDelayed(new Runnable() {
    @Override
    public void run() {
        // Do something after 1000 ms
    }
}, 1000);

1
ビューハンドラーでスケジュールされるため、UI要素自体をフリーズしませんか?
JacksOnF1re 2015年

1
いいえ、掲載タスクは、1秒間に実行されますが、この第二のUIスレッドの間に、他の有用な作業します
demaksee

14

これが私の最短の解決策です:

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Do something after 100ms
    }
}, 100);

10
final Handler handler = new Handler(); 
Timer t = new Timer(); 
t.schedule(new TimerTask() { 
    public void run() { 
        handler.post(new Runnable() { 
            public void run() { 
                //DO SOME ACTIONS HERE , THIS ACTIONS WILL WILL EXECUTE AFTER 5 SECONDS...
            }
        }); 
    } 
}, 5000); 

10

あなたが使用している場合はAndroidのメーカー3.0をして上に、あなたは、ラムダ式を使用することができます。このメソッドcallMyMethod()は2秒後に呼び出されます。

new Handler().postDelayed(() -> callMyMethod(), 2000);

遅延したランナブルをキャンセルする必要がある場合は、これを使用してください:

Handler handler = new Handler();
handler.postDelayed(() -> callMyMethod(), 2000);

// When you need to cancel all your posted runnables just use:
handler.removeCallbacksAndMessages(null);

どうすればキャンセルできますか?
ダミアフエンテス2017

ここで、標準Javaであるラムダ式を完全に無視しながら、Kotlinに移行する人の数に驚いています。
TomDK、

6

Timerをお勧めします。これにより、非常に特定の間隔で呼び出されるメソッドをスケジュールできます。これはUIをブロックせず、メソッドの実行中もアプリの応答を維持します。

もう1つのオプションは、wait();です。メソッド、これは、指定された時間の間、現在のスレッドをブロックします。これにより、UIスレッドでこれを行うと、UIが応答を停止します。


2
Thread.sleep()はObject.wait()よりも優れています。待機は、通知されることを期待していて、いくつかのアクティビティーについて同期していることを意味します。スリープは、特定の時間だけ何もしないことを希望することを示します。後でアクションを非同期的に実行したい場合は、タイマーを使用します。
Tim Bender、

1
それは本当です。それが私が別のオプションとしてそれをリストした理由です;-)
Nate

6

シンプルなラインHandle Post遅延の場合、次のように実行できます。

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        // Do someting
    }
}, 3000);

これが役に立てば幸い


5

これを最も簡単なソリューションに使用できます。

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //Write your code here
    }
}, 5000); //Timer is in ms here.

そうでなければ、以下は別のクリーンで便利な解決策になります:

new Handler().postDelayed(() -> 
{/*Do something here*/}, 
5000); //time in ms


5

この猫の皮をむく方法はたくさんあるので、ここで考慮すべきことがいくつかあります。答えはすべて選択され、選ばれています。「大多数が単純な答えを選択した」という理由だけで誰かが間違った方向に進むのを避けるために、これを適切なコーディングガイドラインで再検討することが重要だと思います。

それでは、最初に、このスレッドで勝者が選択した回答である単純な遅延投稿の回答について説明します。

考慮すべきいくつかのこと。ポスト遅延の後、メモリリーク、デッドオブジェクト、なくなったライフサイクルなどに遭遇する可能性があります。したがって、適切に処理することも重要です。いくつかの方法でこれを行うことができます。

現代の開発のために、KOTLINで供給します

以下は、コールバックでUIスレッドを使用し、コールバックを押したときにアクティビティがまだ正常であることを確認する簡単な例です。

  Handler(Looper.getMainLooper()).postDelayed({
            if(activity != null && activity?.isFinishing == false){
                txtNewInfo.visibility = View.GONE
            }
        }, NEW_INFO_SHOW_TIMEOUT_MS)

ただし、アクティビティがなくなった場合にコールバックを実行する理由がないため、これはまだ完全ではありません。したがって、より良い方法は、それへの参照を保持し、このようなコールバックを削除することです。

    private fun showFacebookStylePlus1NewsFeedOnPushReceived(){
        A35Log.v(TAG, "showFacebookStylePlus1NewsFeedOnPushReceived")
        if(activity != null && activity?.isFinishing == false){
            txtNewInfo.visibility = View.VISIBLE
            mHandler.postDelayed({
                if(activity != null && activity?.isFinishing == false){
                    txtNewInfo.visibility = View.GONE
                }
            }, NEW_INFO_SHOW_TIMEOUT_MS)
        }
    }

そしてもちろん、コールバックをヒットしないようにonPauseでクリーンアップを処理します。

    override fun onPause() {
        super.onPause()
        mHandler.removeCallbacks(null)
    }

明白な話をしたので、今日のコルーチンとkotlinを使ったよりクリーンなオプションについて話しましょう:)。これらをまだ使用していない場合は、本当に見落としていることになります。

   fun doActionAfterDelay() 
        launch(UI) {
            delay(MS_TO_DELAY)           
            actionToTake()
        }
    }

または、そのメソッドで常にUI起動を実行する場合は、次のように簡単に実行できます。

  fun doActionAfterDelay() = launch(UI){ 
      delay(MS_TO_DELAY)           
      actionToTake()
  }

もちろん、PostDelayedと同じように、キャンセルを確実に処理する必要があります。これにより、遅延呼び出しの後にアクティビティチェックを行うか、他のルートと同じようにonPauseでキャンセルできます。

var mDelayedJob: Job? = null
fun doActionAfterDelay() 
   mDelayedJob = launch(UI) {
            try {
               delay(MS_TO_DELAY)           
               actionToTake()
            }catch(ex: JobCancellationException){
                showFancyToast("Delayed Job canceled", true, FancyToast.ERROR, "Delayed Job canceled: ${ex.message}")
            }
        }
   }
}

//クリーンアップを処理する

override fun onPause() {
   super.onPause()
   if(mDelayedJob != null && mDelayedJob!!.isActive) {
      A35Log.v(mClassTag, "canceling delayed job")
      mDelayedJob?.cancel() //this should throw CancelationException in coroutine, you can catch and handle appropriately
   }
}

launch(UI)をメソッドシグネチャに入れると、ジョブをコードの呼び出し行に割り当てることができます。

ストーリーのモラルは、遅延したアクションで安全であること、コールバックを削除すること、またはジョブをキャンセルすることを確認してください。もちろん、遅延したコールバックの項目に触れるための適切なライフサイクルがあることを確認してください。コルーチンはキャンセル可能なアクションも提供します。

また、コルーチンで発生する可能性のあるさまざまな例外を通常処理する必要があることにも注意してください。たとえば、キャンセル、例外、タイムアウトなど、使用することにしたものは何でも。コルーチンを実際に使い始めることにした場合の、より高度な例を次に示します。

   mLoadJob = launch(UI){
            try {
                //Applies timeout
                withTimeout(4000) {
                    //Moves to background thread
                    withContext(DefaultDispatcher) {
                        mDeviceModelList.addArrayList(SSDBHelper.getAllDevices())
                    }
                }

                //Continues after async with context above
                showFancyToast("Loading complete", true, FancyToast.SUCCESS)
            }catch(ex: JobCancellationException){
                showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
            }catch (ex: TimeoutCancellationException) {
                showFancyToast("Timed out saving, please try again or press back", true, FancyToast.ERROR, "Timed out saving to database: ${ex.message}")
            }catch(ex: Exception){
                showFancyToast("Error saving to database, please try again or press back", true, FancyToast.ERROR, "Error saving to database: ${ex.message}")
            }
        }

1
ラジブさん、問題ありません。もう1歩進んで、ライブデータを使用すると、コルーチンはライフサイクルを認識し、クリーンアップ呼び出しを回避するために自己キャンセルできるが、1つの答えにあまり多くの学習曲線を投げたくないと思います;)
サム

3

これを呼び出す簡単なメソッドを作成しました。

public static void CallWithDelay(long miliseconds, final Activity activity, final String methodName)
    {
        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                try {
                    Method method =  activity.getClass().getMethod(methodName);
                    method.invoke(activity);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }, miliseconds);
    }

それを使用するには、次を呼び出すだけです: .CallWithDelay(5000, this, "DoSomething");


3
このような基本的なタスクの反射?
Max Ch

iOSと同様のメソッドを呼び出す質問以来performSelector。これが最善の方法です。
HelmiB 2016年

3

あなたが得るとき、1つの下で働きます、

java.lang.RuntimeException:Looper.prepare()を呼び出していないスレッド内にハンドラを作成できません

final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);



2

RxAndroidを使用すると、スレッドとエラーの処理がはるかに簡単になります。次のコードは遅延後に実行されます

   Observable.timer(delay, TimeUnit.SECONDS)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(aLong -> {
           // Execute code here
        }, Throwable::printStackTrace);

1

ハンドラーを新しくする前にハンドラーをクリーンアップすることを忘れているようです。そうでなければ、それらは潜在的に蓄積し、悪い行動を引き起こす可能性があります。

handler.removeMessages(int what);
// Remove any pending posts of messages with code 'what' that are in the message queue.

handler.removeCallbacks(Runnable r)
// Remove any pending posts of Runnable r that are in the message queue.

1

次に、別のトリッキーな方法を示します。実行可能なUI要素を変更しても例外はスローされません。

public class SimpleDelayAnimation extends Animation implements Animation.AnimationListener {

    Runnable callBack;

    public SimpleDelayAnimation(Runnable runnable, int delayTimeMilli) {
        setDuration(delayTimeMilli);
        callBack = runnable;
        setAnimationListener(this);
    }

    @Override
    public void onAnimationStart(Animation animation) {

    }

    @Override
    public void onAnimationEnd(Animation animation) {
        callBack.run();
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
}

このようなアニメーションを呼び出すことができます:

view.startAnimation(new SimpleDelayAnimation(delayRunnable, 500));

アニメーションは任意のビューにアタッチできます。



1

私はよりクリーンなものが好きです:これが私の実装です、あなたのメソッド内で使用するインラインコードです

new Handler().postDelayed(new Runnable() {
  @Override
  public void run() {
    //Do something after 100ms
  }
}, 100);

0

Androidでの適切なソリューション:

private static long SLEEP_TIME = 2 // for 2 second
.
.
MyLauncher launcher = new MyLauncher();
            launcher.start();
.
.
private class MyLauncher extends Thread {
        @Override
        /**
         * Sleep for 2 seconds as you can also change SLEEP_TIME 2 to any. 
         */
        public void run() {
            try {
                // Sleeping
                Thread.sleep(SLEEP_TIME * 1000);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
            //do something you want to do
           //And your code will be executed after 2 second
        }
    }

0

同様のソリューションですが、使用するのによりクリーンです

この関数をクラス外に記述します

fun delay(duration: Long, `do`: () -> Unit) {

    Handler().postDelayed(`do`, duration)

}

使用法:

delay(5000) {
    //Do your work here
}

`は何をしますか?
Skizo-ozᴉʞS

名前だけで、何でもそこに保管してください。doは組み込みのメソッドなので、変数名として使用するには `を使用する必要があります
Manohar Reddy

おかげで、なぜこの変数名が使用されるのですか?私はそれの機能が何であるかを意味します。
Skizo-ozᴉʞS

1
do3秒遅れてこう思いました
Manohar Reddy

0

Androidでは、関数の実行を遅延させるために、kotlinコードの下に次のように記述できます。

class MainActivity : AppCompatActivity() {

private lateinit var handler: Handler

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    handler= Handler()
    handler.postDelayed({
        doSomething()
    },2000)
}

private fun doSomething() {
    Toast.makeText(this,"Hi! I am Toast Message",Toast.LENGTH_SHORT).show()
}
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.