Android 以延时重复任务?

Android 以延时重复任务?,android,android-thread,Android,Android Thread,我的代码中有一个变量,表示它是“status” 我想根据这个变量值在应用程序中显示一些文本。这必须在特定的时间延迟内完成 就像 检查状态变量值 显示一些文本 等待10秒钟 检查状态变量值 显示一些文本 等待15秒 等等。时间延迟可能会发生变化,并且在显示文本后设置 我尝试了Thread.sleep(延时),但失败了。是否有更好的方法来完成此任务?为此,您应该使用处理程序的postDelayed函数。它将在主UI线程上以指定的延迟运行代码,因此您将能够更新UI控件 private int mI

我的代码中有一个变量,表示它是“status”

我想根据这个变量值在应用程序中显示一些文本。这必须在特定的时间延迟内完成

就像

  • 检查状态变量值

  • 显示一些文本

  • 等待10秒钟

  • 检查状态变量值

  • 显示一些文本

  • 等待15秒

等等。时间延迟可能会发生变化,并且在显示文本后设置


我尝试了
Thread.sleep(延时)
,但失败了。是否有更好的方法来完成此任务?

为此,您应该使用
处理程序
postDelayed
函数。它将在主UI线程上以指定的延迟运行代码,因此您将能够更新UI控件

private int mInterval = 5000; // 5 seconds by default, can be changed later
private Handler mHandler;

@Override
protected void onCreate(Bundle bundle) {

    // your code here

    mHandler = new Handler();
    startRepeatingTask();
}

@Override
public void onDestroy() {
    super.onDestroy();
    stopRepeatingTask();
}

Runnable mStatusChecker = new Runnable() {
    @Override 
    public void run() {
          try {
               updateStatus(); //this function can change value of mInterval.
          } finally {
               // 100% guarantee that this always happens, even if
               // your update method throws an exception
               mHandler.postDelayed(mStatusChecker, mInterval);
          }
    }
};

void startRepeatingTask() {
    mStatusChecker.run(); 
}

void stopRepeatingTask() {
    mHandler.removeCallbacks(mStatusChecker);
}

对于任何感兴趣的人,这里有一个我使用inazaruk的代码创建的类,它创建了所需的一切(我称之为UIUpdater,因为我使用它定期更新UI,但您可以随意调用它):

然后,您可以在类中创建UIUpdater对象,并像这样使用它:

...
mUIUpdater = new UIUpdater(new Runnable() {
         @Override 
         public void run() {
            // do stuff ...
         }
    });

// Start updates
mUIUpdater.startUpdates();

// Stop updates
mUIUpdater.stopUpdates();
...

如果您想将其用作活动更新程序,请将开始调用放在onResume()方法中,将停止调用放在onPause()中,以便根据活动可见性启动和停止更新。

我认为新的热点是使用。像这样:

private final ScheduledThreadPoolExecutor executor_ = 
        new ScheduledThreadPoolExecutor(1);
this.executor_.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
    update();
    }
}, 0L, kPeriod, kTimeUnit);

试试下面的例子吧

在onCreate()方法中使用[Handler],该方法使用postDelayed()方法,将Runnable添加到消息队列中,并在给定示例中为0的指定时间后运行

请参阅此代码:

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
    //------------------
    //------------------
    android.os.Handler customHandler = new android.os.Handler();
            customHandler.postDelayed(updateTimerThread, 0);
}

private Runnable updateTimerThread = new Runnable()
{
        public void run()
        {
            //write here whaterver you want to repeat
            customHandler.postDelayed(this, 1000);
        }
};

定时器是完成工作的另一种方式,但如果您正在使用UI,请确保添加
runOnUiThread

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://android-er.blogspot.com/"
    android:textStyle="bold" />
<CheckBox 
    android:id="@+id/singleshot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Single Shot"/>
xml是

new CountDownTimer(30000, 1000) {

     public void onTick(long millisUntilFinished) {
         mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
     }

     public void onFinish() {
         mTextField.setText("done!");
     }
  }.start();
安排一个倒计时,直到将来某个时间,并定期通知沿途的时间间隔。在文本字段中显示30秒倒计时的示例:


您可以使用处理程序发布可运行代码。这里很好地介绍了这项技术:

定时器工作正常。在这里,我使用定时器搜索1.5s后的文本并更新UI。希望有帮助

class MyActivity {
    private ScheduledThreadPoolExecutor mDialogDaemon;

    private void initDebugButtons() {
        Button btnSpawnDialogs = (Button)findViewById(R.id.btn_spawn_dialogs);
        btnSpawnDialogs.setVisibility(View.VISIBLE);
        btnSpawnDialogs.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                spawnDialogs();
            }
        });
    }

    private void spawnDialogs() {
        if (mDialogDaemon != null) {
            mDialogDaemon.shutdown();
            mDialogDaemon = null;
        }
        mDialogDaemon = new ScheduledThreadPoolExecutor(1);
        // This process will execute immediately, then execute every 3 seconds.
        mDialogDaemon.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // Do something worthwhile
                    }
                });
            }
        }, 0L, 3000L, TimeUnit.MILLISECONDS);
    }
}

基于以上关于的帖子,我想出了一个适合我需要的实用程序(希望每3秒触发一个方法):


在我的例子中,如果其中一个条件为真,我必须执行一个进程:如果前一个进程已经完成,或者如果已经过了5秒。因此,我做了以下工作,并且做得很好:

   //----------------------SCHEDULER-------------------------
    private final ScheduledThreadPoolExecutor executor_ =
            new ScheduledThreadPoolExecutor(1);
     ScheduledFuture<?> schedulerFuture;
   public void  startScheduler() {
       schedulerFuture=  executor_.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                //DO YOUR THINGS
                pageIndexSwitcher.setVisibility(View.GONE);
            }
        }, 0L, 5*MILLI_SEC,  TimeUnit.MILLISECONDS);
    }


    public void  stopScheduler() {
        pageIndexSwitcher.setVisibility(View.VISIBLE);
        schedulerFuture.cancel(false);
        startScheduler();
    }
私有可运行mStatusChecker;
私人经理人;
阶级{
方法(){
mStatusChecker=new Runnable(){
整数倍=0;
@凌驾
公开募捐{
如果(次数<5){
if(process1.isRead()){
executeProcess2();
}否则{
时代++;
mHandler.postDelayed(mStatusChecker,1000);
}
}否则{
executeProcess2();
}
}
};
mHandler=新处理程序();
startRepeatingTask();
}
void startRepeatingTask(){
mStatusChecker.run();
}
void stopRepeatingTask(){
mHandler.removeCallbacks(mStatusChecker);
}
}

如果读取了process1,它将执行process2。如果不是,则递增变量时间,并使处理程序在一秒钟后执行。它保持一个循环,直到读取process1或times为5。当时间为5时,表示经过了5秒,每秒执行process1.isRead()的if子句。

有3种方法:

使用ScheduledThreadPoolExecutor 有点过分,因为你不需要一个线程池

    //----------------------TIMER  TASK-------------------------

    private Timer carousalTimer;
    private void startTimer() {
        carousalTimer = new Timer(); // At this line a new Thread will be created
        carousalTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                //DO YOUR THINGS
                pageIndexSwitcher.setVisibility(INVISIBLE);
            }
        }, 0, 5 * MILLI_SEC); // delay
    }

    void stopTimer() {
        carousalTimer.cancel();
    }
使用Handler和Runnable 现代安卓风格

    //----------------------HANDLER-------------------------

    private Handler taskHandler = new android.os.Handler();

    private Runnable repeatativeTaskRunnable = new Runnable() {
        public void run() {
            //DO YOUR THINGS
        }
    };

   void startHandler() {
        taskHandler.postDelayed(repeatativeTaskRunnable, 5 * MILLI_SEC);
    }

    void stopHandler() {
        taskHandler.removeCallbacks(repeatativeTaskRunnable);
    }
/**
     * Instances of static inner classes do not hold an implicit
     * reference to their outer class.
     */
    private static class NonLeakyHandler extends Handler {
        private final WeakReference<FlashActivity> mActivity;

        public NonLeakyHandler(FlashActivity activity) {
            mActivity = new WeakReference<FlashActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            FlashActivity activity = mActivity.get();
            if (activity != null) {
                // ...
            }
        }
    }
具有活动/上下文的非泄漏处理程序

在活动/片段类中声明一个内部处理程序类

   private Runnable repeatativeTaskRunnable = new Runnable() {
        public void run() {
            new Handler(getMainLooper()).post(new Runnable() {
                @Override
                public void run() {

         //DO YOUR THINGS
        }
    };
//Task Handler
private Handler taskHandler = new NonLeakyHandler(FlashActivity.this);
初始化活动/片段中的处理程序对象(此处FlashActivity是我的活动类)

在固定时间间隔后重复任务

taskHandler.postDelayed(RepeativeTaskRunnable,DELAY_MILLIS)

停止重复任务

taskHandler.removeCallbacks(RepeativeTaskRunnable)

更新:在科特林: 对于使用Kotlin的人来说,将无法工作,IDE将要求初始化变量,因此我们将在
Runnable
中使用
postDelayed
,而不是在
Runnable
中使用它

  • 初始化
    可运行的
    ,如下所示:

     private fun runDelayedHandler(timeToWait : Long) {
        if (!keepRunning) {
            //Stop your handler
            handler.removeCallbacksAndMessages(null)
            //Do something here, this acts like onHandlerStop
        }
        else {
            //Keep it running
            handler.postDelayed(myRunnable, timeToWait)
        }
    }
    
  • 按如下方式初始化
    runDelayedHandler
    方法:

    private var repeatableJob: Job? = null
    
  • 如您所见,这种方法将使您能够控制任务的生命周期,跟踪
    不断修剪
    ,并在应用程序的生命周期内更改它,这将为您完成任务


使用kotlin及其协同程序非常简单,首先在类中声明作业(在viewModel中更好),如下所示:

repeatableJob = viewModelScope.launch {
    while (isActive) {
         delay(5_000)
         loadAlbums(iImageAPI, titleHeader, true)
    }
}
repeatableJob?.start()
然后,当您要创建并启动它时,请执行以下操作:

repeatableJob?.cancel()
如果你想完成它:

PS:
viewModelScope
仅在视图模型中可用,您可以使用其他协同程序作用域,例如
withContext(Dispatchers.IO)


更多信息:

谢谢inazaruk,它成功运行了。发现2 v小的打字错误(顶部的“Handler”不是“Handle”,底部的“removeCallbacks”不是removecallback).但无论如何,代码正是我想要的。试着想想我能做些什么来报答你的恩惠。至少你赢得了我的尊重。向Aubrey Bourke致以亲切的问候。很好的程序,工作非常好。但是startRepeatingTask()必须从onCreate方法/UI线程调用(我花了一些时间才意识到这一点!),也许这一点可以
    //update interval for widget
    override val UPDATE_INTERVAL = 1000L

    //Handler to repeat update
    private val updateWidgetHandler = Handler()

    //runnable to update widget
    private var updateWidgetRunnable: Runnable = Runnable {
        run {
            //Update UI
            updateWidget()
            // Re-run it after the update interval
            updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
        }

    }

 // SATART updating in foreground
 override fun onResume() {
        super.onResume()
        updateWidgetHandler.postDelayed(updateWidgetRunnable, UPDATE_INTERVAL)
    }


    // REMOVE callback if app in background
    override fun onPause() {
        super.onPause()
        updateWidgetHandler.removeCallbacks(updateWidgetRunnable);
    }
private var myRunnable = Runnable {
    //Do some work
    //Magic happens here ↓
    runDelayedHandler(1000)   }
 private fun runDelayedHandler(timeToWait : Long) {
    if (!keepRunning) {
        //Stop your handler
        handler.removeCallbacksAndMessages(null)
        //Do something here, this acts like onHandlerStop
    }
    else {
        //Keep it running
        handler.postDelayed(myRunnable, timeToWait)
    }
}
private var repeatableJob: Job? = null
repeatableJob = viewModelScope.launch {
    while (isActive) {
         delay(5_000)
         loadAlbums(iImageAPI, titleHeader, true)
    }
}
repeatableJob?.start()
repeatableJob?.cancel()