如何每 X 秒运行一次方法

Posted

技术标签:

【中文标题】如何每 X 秒运行一次方法【英文标题】:How to run a method every X seconds 【发布时间】:2012-07-11 03:41:33 【问题描述】:

我正在开发一个 android 2.3.3 应用程序,我需要每 X 秒运行一个方法。

ios 中,我有 NSTimer,但在 Android 中我不知道该使用什么。

有人推荐我Handler;另一个推荐我AlarmManager,但我不知道哪种方法更适合NSTimer。

这是我想在 Android 中实现的代码:

timer2 = [
    NSTimer scheduledTimerWithTimeInterval:(1.0f/20.0f)
    target:self
    selector:@selector(loopTask)
    userInfo:nil
    repeats:YES
];

timer1 = [
    NSTimer scheduledTimerWithTimeInterval:(1.0f/4.0f)
    target:self
    selector:@selector(isFree)
    userInfo:nil
    repeats:YES
];

我需要类似NSTimer 的东西。

你有什么推荐给我的?

【问题讨论】:

定义“最好的”。您希望它以何种方式做到最好? 我不知道哪种方法更适合 NSTimer。 @VansFannel 你想要多长时间的间隔? 我已经更新了问题,详细说明了我正在尝试做的事情。 这个问题:***.com/questions/6242268/…,和这个类似,答案很好。 【参考方案1】:

您将使用的解决方案实际上取决于您在每次执行函数之间需要等待多长时间。

如果您等待的时间超过 10 分钟,我建议您使用AlarmManager

// Some time when you want to run
Date when = new Date(System.currentTimeMillis());

try 
    Intent someIntent = new Intent(someContext, MyReceiver.class); // intent to be launched

    // Note: this could be getActivity if you want to launch an activity
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
        context,
        0, // id (optional)
        someIntent, // intent to launch
        PendingIntent.FLAG_CANCEL_CURRENT // PendingIntent flag
    );

    AlarmManager alarms = (AlarmManager) context.getSystemService(
        Context.ALARM_SERVICE
    );

    alarms.setRepeating(
        AlarmManager.RTC_WAKEUP,
        when.getTime(),
        AlarmManager.INTERVAL_FIFTEEN_MINUTES,
        pendingIntent
    );
 catch(Exception e) 
    e.printStackTrace();

一旦您广播了上述Intent,您就可以通过实现BroadcastReceiver 来接收您的Intent。请注意,这需要在您的应用程序清单中或通过context.registerReceiver(receiver, intentFilter); 方法进行注册。 For more information on BroadcastReceiver's please refer to the official documentation..

public class MyReceiver extends BroadcastReceiver 
    @Override
    public void onReceive(Context context, Intent intent)
    
        System.out.println("MyReceiver: here!") // Do your work here
    

如果您等待的时间少于 10 分钟,那么我建议您使用 Handler

final Handler handler = new Handler();
final int delay = 1000; // 1000 milliseconds == 1 second

handler.postDelayed(new Runnable() 
    public void run() 
        System.out.println("myHandler: here!"); // Do your work here
        handler.postDelayed(this, delay);
    
, delay);

【讨论】:

为什么会根据时间延迟提出不同的建议? 效率,在 AlarmManager 文档中声明它不应该用于任何小间隔重复任务。 @SimonAndréForsberg 在AlarmManager docs 中指出 Handler 是用于短滴答声的首选且更有效的方法:“注意:警报管理器适用于您希望拥有应用程序代码的情况在特定时间运行,即使您的应用程序当前没有运行。对于正常的计时操作(滴答声、超时等),使用 Handler 更容易、更高效。" @ahmadalibaloch 在 runnable 中您可以执行 h.removeCallbacks(this);,否则您需要维护对 runnable 的引用才能将其删除。如果需要第二种方法,此处发布的方法可能不是您的最佳途径。 这种形式的持续递归最终不会导致栈溢出吗?【参考方案2】:

每秒使用计时器...

new Timer().scheduleAtFixedRate(new TimerTask() 
    @Override
    public void run() 
        //your method
    
, 0, 1000);//put here time 1000 milliseconds=1 second

【讨论】:

我已经更新了问题,详细说明了我正在尝试做的事情。 不要使用 Timer (mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler),使用 Handler 或 ScheduledThreadPoolExecutor。 @AppiDevo Link 好像死了,试试web.archive.org/web/20200131001301/http://www.mopri.de/2010/…【参考方案3】:

您可以尝试此代码通过 o​​nResume() 每 15 秒调用一次处理程序,并在活动不可见时通过 onPause() 停止它。

Handler handler = new Handler();
Runnable runnable;
int delay = 15*1000; //Delay for 15 seconds.  One second = 1000 milliseconds.


@Override
protected void onResume() 
   //start handler as activity become visible

    handler.postDelayed( runnable = new Runnable() 
        public void run() 
            //do something

            handler.postDelayed(runnable, delay);
        
    , delay);

    super.onResume();


// If onPause() is not included the threads will double up when you 
// reload the activity 

@Override
protected void onPause() 
    handler.removeCallbacks(runnable); //stop handler when activity not visible
    super.onPause();

【讨论】:

这就是我要找的。完美。 这是完美的答案! 看准了!用于检查 TabLayout 中的 MainActivitys 当前选定选项卡与此片段匹配,如果不停止工作 - 因为当任何 TabLayout 选定选项卡位于此选定选项卡的任一侧时,onPause() 失败 这就是答案!谢谢! 正是我所寻找的,谢谢! new Handler() 现在给出弃用警告。我通过将其更改为 new Handler(Looper.getMainLooper()) 摆脱了它【参考方案4】:

如果你熟悉 RxJava,你可以使用 Observable.interval(),非常简洁。

Observable.interval(60, TimeUnits.SECONDS)
          .flatMap(new Function<Long, ObservableSource<String>>() 
                @Override
                public ObservableSource<String> apply(@NonNull Long aLong) throws Exception 
                    return getDataObservable(); //Where you pull your data
                
            );

这样做的缺点是您必须以不同的方式构建轮询数据的架构师。但是,响应式编程方式有很多好处:

    您可以创建订阅的数据流,而不是通过回调控制数据。这将“轮询数据”逻辑和“使用数据填充 UI”逻辑的关注点分开,这样您就不会将“数据源”代码和 UI 代码混在一起。

    使用 RxAndroid,您只需 2 行代码即可处理线程。

    Observable.interval(60, TimeUnits.SECONDS)
          .flatMap(...) // polling data code
          .subscribeOn(Schedulers.newThread()) // poll data on a background thread
          .observeOn(AndroidSchedulers.mainThread()) // populate UI on main thread
          .subscribe(...); // your UI code
    

请查看 RxJava。它具有很高的学习曲线,但它会让在 Android 中处理异步调用变得更加轻松和清晰。

【讨论】:

【参考方案5】:

使用 Kotlin,我们现在可以为此创建一个通用函数!

object RepeatHelper 
    fun repeatDelayed(delay: Long, todo: () -> Unit) 
        val handler = Handler()
        handler.postDelayed(object : Runnable 
            override fun run() 
                todo()
                handler.postDelayed(this, delay)
            
        , delay)
    

要使用,只需这样做:

val delay = 1000L
RepeatHelper.repeatDelayed(delay) 
    myRepeatedFunction()

【讨论】:

【参考方案6】:
    new CountDownTimer(120000, 1000) 

        public void onTick(long millisUntilFinished) 
            txtcounter.setText(" " + millisUntilFinished / 1000);

        

        public void onFinish() 

            txtcounter.setText(" TimeOut  ");
            Main2Activity.ShowPayment = false;
            EventBus.getDefault().post("go-main");

        

    .start();

【讨论】:

不要发布代码只回答。请edit你的答案并添加一些解释。【参考方案7】:

这里我在 onCreate() 一个 Activity 中重复使用了一个线程,计时器在某些情况下不允许一切,线程是解决方案

     Thread t = new Thread() 
        @Override
        public void run() 
            while (!isInterrupted()) 
                try 
                    Thread.sleep(10000);  //1000ms = 1 sec
                    runOnUiThread(new Runnable() 
                        @Override
                        public void run() 

                            SharedPreferences mPrefs = getSharedPreferences("sam", MODE_PRIVATE);
                            Gson gson = new Gson();
                            String json = mPrefs.getString("chat_list", "");
                            GelenMesajlar model = gson.fromJson(json, GelenMesajlar.class);
                            String sam = "";

                            ChatAdapter adapter = new ChatAdapter(Chat.this, model.getData());
                            listview.setAdapter(adapter);
                           // listview.setStackFromBottom(true);
                          //  Util.showMessage(Chat.this,"Merhabalar");
                        
                    );

                 catch (InterruptedException e) 
                    e.printStackTrace();
                
            
        
    ;

    t.start();

如果需要,可以停止

@Override
protected void onDestroy() 
    super.onDestroy();
    Thread.interrupted();
    //t.interrupted();

【讨论】:

请描述我的回答不起作用时的情况 你好,奥马尔。我需要一个圈子,整个应用程序处于活动状态,处理程序在活动活动期间进行重复活动,但我需要这个圈子,同时我也能够访问其他活动。所以线程是这样的解决方案,确保它也有它的斗争。【参考方案8】:

我是这样做的,效果很好(代码是用Kotlin编写的):

private lateinit var runnable: Runnable

private var handler = Handler(Looper.getMainLooper())

private val repeatPeriod: Long = 10000

然后从你的函数内部重新初始化可运行对象

runnable = Runnable 

        // Your code goes here

        handler.postDelayed(runnable, repeatPeriod)

    

    handler.postDelayed(runnable, repeatPeriod)


请注意,如果您不 postDelay 两次 handler,则循环不会是 intinity!

【讨论】:

以上是关于如何每 X 秒运行一次方法的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin Forms:即使应用程序在后台,如何每 x 秒运行一次服务?

c# 每 x 秒运行一次数据库任务

我怎样才能让我的 caroutine 每 x 秒运行一次

每 x 秒执行一次 Python 而无需重新打开选项卡

每 30 秒运行一次 cron 作业的最佳方式是啥? [复制]

如何每 20 秒执行一次 bash 脚本? ,好用睡眠和循环?