定时每天晚上开启android

2016-07-24 10:20:43 hester_hester 阅读数 7001

目标效果:

  

运行打开开关,下边的时间选择会显示,当前时间09:56,选择09:57后,会发现马上弹出选择的时间日志数据,过一会到了09:57后,会发现每一秒都调用打印日志信息的方法,点击关闭开关,停止打印。


1.activity_main.xml页面设置布局,并隐藏下方的时间选择。

activity_main.xml页面:

<RelativeLayout 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"
    tools:context=".MainActivity" >

   <Switch
        android:id="@+id/swOnOfOff"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="30dp"
        android:textOn="开启"
        android:textOff="关闭"
        android:text="定时" />

    <LinearLayout
        android:id="@+id/llSelectTime"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:padding="40dp"
        android:visibility="gone"
        android:orientation="horizontal" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:gravity="right"
            android:text="时间       " />

        <TextView
            android:id="@+id/tvSelectTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:gravity="left"
            android:text="00:00" />
    </LinearLayout>
</RelativeLayout>


2.新建Task.java页面,继承TimerTask,作为每次调用触发的方法。
package com.example.time;

import java.util.TimerTask;

import android.util.Log;

public class Task extends TimerTask{

	@Override
	public void run() {
		Log.i("wxy", "提示");
		
	}

}


3.MainActivity.java页面获取选择时间并进行调用。
MainActivity.java页面:
package com.example.time;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.app.Activity;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class MainActivity extends Activity implements OnClickListener {

	private LinearLayout llSelectTime; // 显示选择时间的一层
	private Switch swOnOfOff; // 开关
	private TextView tvSelectTime;

	private Timer timer; // 定时器

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		llSelectTime = (LinearLayout) findViewById(R.id.llSelectTime);
		tvSelectTime = (TextView) findViewById(R.id.tvSelectTime);
		tvSelectTime.setOnClickListener(this);
		// 开关点击事件
		swOnOfOff = (Switch) findViewById(R.id.swOnOfOff);
		swOnOfOff.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(CompoundButton compoundButton,
					boolean checked) {
				if (checked) {
					llSelectTime.setVisibility(View.VISIBLE); // 设置可见
				} else {
					llSelectTime.setVisibility(View.GONE); // 设置不可见,留了位置
					timer.cancel();// 关闭定时器
				}
			}
		});
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.tvSelectTime:
			// 显示选择时间对话框
			showSelectDailog();
			break;

		default:
			break;
		}
	}

	// 定时触发事件
	private void timeTrigger(int hour, int minute) {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR_OF_DAY, hour);
		calendar.set(Calendar.MINUTE, minute);
		calendar.set(Calendar.SECOND, 0);
		Date date = calendar.getTime(); // 第一次执行任务的时间
		if (date.before(new Date())) { // 如果第一次执行任务的时间小于当前时间,那么要在执行任务的时间加一天,否则会立即执行
			date = this.addDay(date, 1);
		}
		Log.i("wxy", "date:" + date);
		timer = new Timer(true);
		timer.schedule(new Task(), date, 1000);//第一个参数为定时调用的方法,注意是一次性的,如果关闭Timer得重新实例化, 第二个参数为第一次调用的时间,第三个参数为两次调用方法的间隔毫秒数

	}

	// 日期加一天
	public Date addDay(Date date, int num) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, num);
		return calendar.getTime();
	}

	// 显示选择时间对话框
	private void showSelectDailog() {
		OnTimeSetListener listener = new OnTimeSetListener() {
			// 选择后返回的数据
			@Override
			public void onTimeSet(TimePicker arg0, int hour, int minute) {
				String time = "";// 时间字符串
				if (hour < 10) { // 如果小时小于10,在前边添加0
					String h = "0" + hour;
					time += h;
				} else
					time += hour;
				time += ":";
				if (minute < 10) {
					String m = "0" + minute;
					time += m;
				} else {
					time += minute;
				}
				tvSelectTime.setText(time);
				// 定时触发事件
				timeTrigger(hour, minute); // 触发并传递获取到的选择的小时和分钟,最为每天定时调用的时间
			}
		};
		TimePickerDialog dialog = new TimePickerDialog(this, listener, 0, 0,
				true); // 第三个参数为默认时间,最后一个参数为是否24小时形式
		dialog.show();

	}

}


4.运行就能显示目标效果了。


2017-12-06 11:56:45 qq_28260521 阅读数 1785

前言

最近项目上有这么一个需求,实时监控车辆信息,要求每隔3秒钟刷新一次地图上的车辆位置信息。我的想法是先定时从服务端获取数据存储到SharedPreferences中,然后再定时从SharedPreferences中获取数据显示到地图。对这个逻辑我不满意,但是一时也找不到别的方法,望大神指教。

在使用定时任务的时候,最开始想到的是Timer。无意中看到一种Handler加Runnable方法,觉得还是有必要记录一下。

Timer方法

Timer一般结合TimerTask使用。先看TimerTask,它是一个抽象类,里面有一个run()方法。

public abstract class TimerTask implements Runnable {

......
/**
 * The action to be performed by this timer task.
 */
public abstract void run();

......

}
查看TimerTask的源码,可以看到TimerTask其实就是实现了Runnable方法,也就是说,通过Timer执行定时任务,其实就是通过一个线程做到的。

再看Timer,它其实就是一个线程管理器,通过schedule方法来开启一个线程,并实现任务调度。Timer工作机制下篇文章再撸,这里简单理解并记录使用方法。

/**
* A facility for threads to schedule tasks for future execution in a
* background thread. Tasks may be scheduled for one-time execution, or for
* repeated execution at regular intervals.

……

  • After the last live reference to a Timer object goes away

  • and all outstanding tasks have completed execution, the timer’s task
  • execution thread terminates gracefully (and becomes subject to garbage
  • collection). However, this can take arbitrarily long to occur. By
  • default, the task execution thread does not run as a daemon thread,
  • so it is capable of keeping an application from terminating. If a caller
  • wants to terminate a timer’s task execution thread rapidly, the caller
  • should invoke the timer’s cancel method.

    ……

  • This class is thread-safe: multiple threads can share a single

  • Timer object without the need for external synchronization.
    *
  • This class does not offer real-time guarantees: it schedules

  • tasks using the Object.wait(long) method.

    ……
    */
    截几段源码注释

当所有TimerTask任务完成,并且Timer引用为空的时候,会被GC回收。
一般程序退出时,TimerTask任务会跟随着终止,主动结束则用Timer的cancel方法。
多个线程可共用一个Timer,也就是多个TimerTask可以共用一个Timer。
Timer不能保证实时任务,所有的任务都得等待调度。
说人话,来个比喻。Timer是一个码头大哥(简称T老大),手底下有一帮小弟(Thread,简称w)跟一个管家(schedule,简称S管家)。TimerTask是一个商人(简称K老板),手底下有一帮业务经理(实例化的timerTask,负责某个具体的任务,简称p经理)。他有一批货要在码头卸载。于是乎,K老板找到了T老大。

商人:T老大,我有一批货要在贵码头卸载,能不能帮帮忙,价钱好商量!
老大:路过的都是朋友,好说!好说!
商人:我这批货很急,能不能立马就下?(想要实时)
老大:先来后到,这是规矩啊!能不能马上卸货,就要看K老板您的运气了。要是运气好,就能立马卸货,要是运气不好,等个一年半载都有可能啊。哈哈哈、、、还望海涵!(无法保证实时)
商人:那就只能等T老大的好消息了。
商人就只能在码头排队等候了。某天,轮到K老板卸货了。

老大:K老板久等了!接下来在下静候吩咐。
商人:岂敢!只是鄙人的货有点杂,需要送到不同的地方,还要麻烦T老大啊。
老大:小事一桩!只管说给我的S管家听,保证K老板满意!(多个任务可共用一个Timer)
管家:K老板只管吩咐,老夫一定保质保量完成。
商人:那就多谢S管家!具体的任务我让我的经理们给您汇报。

得到老板的指示,S管家跟p经理们开始干活了。一个经理代表一个具体的任务,一个w代表一个线程。

schedule的四个方法

schedule(task, date),指定时间执行一次
经理1:S管家,这批布匹要晚上6点往城东的布衣店送去。
管家:w1,你来,把这个送到城东的布衣店去。晚上6点就去。
schedule(task, delay), 从现在起,delay毫秒后,执行一次
经理2:S管家,这批水果过两个小时往城东的水果店送去。
管家:w2,你来,两个小时后,开始往城东的水果店送。
schedule(task, firstTime, period),firstTime时刻开始,每隔period毫秒执行一次
经理3:S管家,这批黄金要明天凌晨4点开始,每隔1小时往城南的金铺送一次。
管家:w3,你来,明天早起,凌晨4点开始干活,没喊停,就一直干。
schedule(task, delay, period),现在开始,delay毫秒后,每隔period毫秒执行一次
经理4:S管家,这批书要往城北的陈家送去,2个小时后他们家才有人,每隔一个小时送一次。
管家:w4,你来,吃点东西,2个小时后往陈家送书,一个小时送一次,没喊停,就一直干。

若干天后,S管家没有收到K老板的支付款,便向T老大汇报。

管家:老大,K老板不守信用啊,款项没有及时到账,如何处理?
老大:不守规矩,以后不跟他玩了,让他找别人。(cancel方法,主动结束timerTask)
商人:那我不得重新找码头了?T老大,通融通融吧。
老大:没门儿!(一旦取消,要想继续只能重新new一个Timer)
待K老板交足款项后,只能重新排队等待卸货。某天,海啸来了,码头被毁(程序退出),一切都没了(timerTask被动结束)。
啰嗦了半天,不知道说明白没有。还是上代码,直观显示。

......
private Timer timer = new Timer();
......
private void useTimer() {
    //多个任务可共享一个timer
    timer.schedule(new MarkerTask(), 1000, 2000);
    timer.schedule(new MapTask(), 1000, 3000);
}
......
@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.stopRefresh://取消定时任务
            Log.d("MainActivity", "onClick: stopRefresh");
            timer.cancel();
            break;
        case R.id.continueRefresh://继续定时任务
            Log.d("MainActivity", "onClick: continueRefresh");
            Timer timer1 = new Timer();
            timer1.schedule(new MarkerTask(), 1000, 2000);
            timer1.schedule(new MapTask(), 1, 3000);
            break;
        default:
            break;
    }
}
......
private class MapTask extends TimerTask {

    @Override
    public void run() {
        refreshMapViewDetail();
    }
}

private class MarkerTask extends TimerTask {

    @Override
    public void run() {
        randomMarkerDetail();
    }
}
......

Handler加Runnable方法

这个方法的核心思想就是在Runnable内部,将本runnable继续插入主线程队列中。理解了Handler的工作机制,这个方法就更好理解,这里直接贴代码。

......
    mapRefreshRun = new Runnable() {
        @Override
        public void run() {
            //更新地图上的数据
            refreshMapViewDetail();
            //将本runnable继续插入主线程中,再次执行。
            handler.postDelayed(this, 3000);
        }
    };
    handler.postDelayed(mapRefreshRun, 1);

......

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.stopRefresh:
            Log.d("MainActivity", "onClick: stopRefresh");
            handler.removeCallbacks(mapRefreshRun);
            break;
        case R.id.continueRefresh:
            Log.d("MainActivity", "onClick: continueRefresh");
            handler.postDelayed(mapRefreshRun, 1);
            break;
        default:
            break;
    }
}

……

要取消任务直接用Handler的removeCallbacks方法,要继续任务,则将任务继续插入主线程中。

总结

Timer方法是新建子线程,在子线程中执行想要的动作,故不可以直接更改UI;
Handler方法是在主线程中,插入Runnable,可以直接更改UI。对界面的操作,比如点击、滑动这些都是要在主线程中排队进行的,如果我们这个定时任务的period太短,比如设为0,会否影响用户的操作响应速度呢?在这个简单的Demo中,试了下,没有太明显的感觉,但这个问题还是要留意。

转自:http://www.jianshu.com/p/45fe8b5ca21e

2016-05-07 00:09:43 zhangyihui1986 阅读数 24288

介绍

android官方文档:AlarmManager
在Android平台,除了使用AlarmManger外,还可以使用Timer或者Handler来实现定时任务,但这两种方式定时并不会太准确;因此如果我们需要实现精准定时任务,使用AlarmManger更为合理。
AlarmManager类提供对系统闹钟服务(或称为定时器服务)的访问接口,使用它既可以指定单次执行的定时任务,也可以指定重复运行的任务。
当闹钟指定触发时间到达时,实际上是系统发出为这个闹钟注册的广播,因此我们需要实现一个针对特定闹钟事件的广播接口器。
从API 19开始,alarm的机制都是非准确传递,操作系统将会转换闹钟,来最小化唤醒和电池使用。

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

说明

本文中的代码使用Kotlin来编写,Kotlin是JVM上的一种编程语言,可以与Java无缝对接,由JetBrains公司研发,官方介绍:

Statically typed programming language for the JVM, Android and the browser
100% interoperable with Java™

刚实现定时任务我就写了本文,因此对这方面的知识并没有完全掌握,文中可能会有错误,有机会还会更新。
本文没有将完整的示例代码贴出来,只是贴了关键代码,主要是闹钟的设置和取消,以及与Settings部分的交互。

定时任务实现

常量

首先定义几个常量,包括用于Settings部分的key、用于PendingIntent的requestCode和用于Intent中的action,代码如下:

const val ACTION_ALARM_REPLENISH_STOCK = "witmoon.auto.replenish.stock.action"
const val ACTION_ALARM_SYNCHRONIZE = "witmoon.auto.synchronize.action"
const val ALARM_REPLENISH_STOCK_CODE = 11
const val ALARM_SYNCHRONIZE_CODE = 12

const val KEY_SETTING_AUTO_SYNCHRONIZE = "auto_synchronize_status"
const val KEY_SETTING_SYNCHRONIZE_TIME = "auto_synchronize_time"
const val KEY_SETTING_AUTO_SUBMIT = "auto_submit_status"
const val KEY_SETTING_AUTO_SUBMIT_TIME = "auto_submit_time"

BroadcastReceiver

接下来是闹钟事件广播接收器,作为示例代码非常简单,收到广播事件后首先判断action,根据不同的action使用Toast打印出不同的内容:

/**
 * 闹钟广播接收器
 * Created by chuxin on 2016/5/4.
 */
class AlarmBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        var action = intent?.action
        when {
            ACTION_ALARM_SYNCHRONIZE.equals(action) -> doSynchronizeAction(context)
            ACTION_ALARM_REPLENISH_STOCK.equals(action) -> doReplenishStockAction(context)
        }
    }

    private fun doSynchronizeAction(context: Context?) {
        Toast.makeText(context!!, "同步", Toast.LENGTH_SHORT).show()
    }

    /**
     * 执行补充库存动作, 即下单/定货
     */
    private fun doReplenishStockAction(context: Context?) {
        Toast.makeText(context!!, "定货", Toast.LENGTH_SHORT).show()
    }
}

不要忘记在AndroidManifest.xml文件中注册接收器:

<receiver android:name=".receiver.AlarmBroadcastReceiver">
      <intent-filter>
           <action android:name="witmoon.auto.replenish.stock.action"/>
           <action android:name="witmoon.auto.synchronize.action"/>
      </intent-filter>
</receiver>

设置闹钟

由于我需要在App启动时就设置定时任务,因此我将代码放置到了Application中,并结合了Settings部分重新设置任务执行时间(每天一次),关于Settings部分后面说,此处只关心设置闹钟。

class HomeDoorApplication : Application() {

    companion object {
        // 自定义委托实现单例
        var instance: HomeDoorApplication by DelegatesExt.notNullSingleValue()
    }

    override fun onCreate() {
        super.onCreate()
        instance = this

        // 启动定时服务
        startAlarm()
    }

    /**
     * 启动定时器(使用系统闹铃服务)
     */
    private fun startAlarm() {
        var preferences = PreferenceManager.getDefaultSharedPreferences(this)
        // 判断是否需要启动定时提交任务
        var isAutoSubmitEnable = preferences.getBoolean(KEY_SETTING_AUTO_SUBMIT, true)
        if (isAutoSubmitEnable) {
            var hourMinuteArray = preferences.getString(KEY_SETTING_AUTO_SUBMIT_TIME, "00:00").split(":")
            setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(), hourMinuteArray[1].toInt(),
                    AlarmManager.INTERVAL_DAY, ALARM_REPLENISH_STOCK_CODE, ACTION_ALARM_REPLENISH_STOCK)
        }
        // 判断是否需要启动定时同步任务
        var isAutoSynchronizeEnable = preferences.getBoolean(KEY_SETTING_AUTO_SYNCHRONIZE, true)
        if (isAutoSynchronizeEnable) {
            var hourMinuteArray = preferences.getString(KEY_SETTING_SYNCHRONIZE_TIME, "00:00").split(":")
            setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(), hourMinuteArray[1].toInt(),
                    AlarmManager.INTERVAL_DAY, ALARM_SYNCHRONIZE_CODE, ACTION_ALARM_SYNCHRONIZE)
        }
    }

    /**
     * 取消闹钟
     */
    fun cancelAlarm(requestCode: Int, action: String) {
        var alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmManager.cancel(
                PendingIntent.getBroadcast(this, requestCode, Intent(action), PendingIntent.FLAG_UPDATE_CURRENT))
    }

    fun setAlarm(type: Int, hour: Int, minute: Int, intervalMillis: Long, requestCode: Int, action: String) {
        var now = Calendar.getInstance()
        var targetTime = now.clone() as Calendar
        targetTime.set(Calendar.HOUR_OF_DAY, hour)
        targetTime.set(Calendar.MINUTE, minute)
        targetTime.set(Calendar.SECOND, 0)
        targetTime.set(Calendar.MILLISECOND, 0)
        if (targetTime.before(now))
            targetTime.add(Calendar.DATE, 1)
        // 方便测试,这里指定即时启动,每20秒执行一次
        setAlarm(type, 0, 20 * 1000, requestCode, action)
//        setAlarm(type, targetTime.timeInMillis, intervalMillis, requestCode, action)
    }

    /**
     * 设置闹钟
     */
    fun setAlarm(type: Int, triggerAtMillis: Long, intervalMillis: Long, requestCode: Int, action: String) {
        var alarmManager: AlarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmManager.setRepeating(type, triggerAtMillis, intervalMillis, PendingIntent.getBroadcast(this,
                requestCode, Intent(action), PendingIntent.FLAG_UPDATE_CURRENT))
    }
}

这段代码实际上是同时设置了两个定时任务,自动提交订单和自动同步,为了更容易读懂代码,我们只看其中一个就可以。
在startAlarm方法中首先我读取了Settings部分的设置,判断是否需要启动闹钟,如果设置值为true,则去读取设置的任务执行时间;时间格式是每天的几点几分(如22:30表示每天晚上10点半执行)。
读取时间后拆分为小时和分钟,调用setAlarm方法,该方法参数包括闹钟类型、首次触发时间、任务间隔、以及requestCode和Action;在该方法中我使用拆分出的小时和分钟找到该时间点的毫秒数(如果时间在当前时间之前,即触发时间已是过去,则到明天这个时间再触发),调用setAlarm重载方法。
在setAlarm重载方法中,构建出PendingIntent对象并设置好闹钟。

设置

首先看一下最终的设置界面
这里写图片描述
本文不介绍Settings部分内容,仅仅是记述重新设置任务执行时间的逻辑。
有关Android中Settings部分内容请参考官方文档:Settings

settings.xml

设置界面XML文件,其中用到了一个自定义的Preference用于选择时间,为了不显得太乱这部分代码不再贴出。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory android:title="同步">

        <SwitchPreference
            android:defaultValue="true"
            android:key="auto_synchronize_status"
            android:summary="自动与服务器同步数据"
            android:title="自动同步"/>

        <com.witmoon.homedoor.ui.preference.TimePickPreference
            android:defaultValue="22:30"
            android:key="auto_synchronize_time"
            android:summary="每天22点30分"
            android:title="提交时间"/>
    </PreferenceCategory>

    <PreferenceCategory android:title="下单">

        <SwitchPreference
            android:defaultValue="true"
            android:key="auto_submit_status"
            android:summary="开启后会在指定时间点自动提交缺货商品订单"
            android:title="自动提交订单"/>

        <com.witmoon.homedoor.ui.preference.TimePickPreference
            android:defaultValue="23:30"
            android:key="auto_submit_time"
            android:summary="每天23点30分"
            android:title="提交时间"/>
    </PreferenceCategory>
</PreferenceScreen>

SettingFragment

设置部分使用PreferenceFragment,在3.0以后官方建议使用PreferenceFragment来代替PreferenceActivity,定义好SettingFragment后将其放置到一个普通的Activity即可。

class SettingFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        addPreferencesFromResource(R.xml.setting)
    }

    override fun onResume() {
        super.onResume()
        preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
    }

    override fun onPause() {
        super.onPause()
        preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
    }

    // 设置改变响应
    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String) {
        when {
            KEY_SETTING_AUTO_SYNCHRONIZE.equals(key) -> onAutoSynchronizeChanged(sharedPreferences, key)
            KEY_SETTING_SYNCHRONIZE_TIME.equals(key) -> onSynchronizeTimeChanged(sharedPreferences, key)
            KEY_SETTING_AUTO_SUBMIT.equals(key) -> onAutoSubmitChanged(sharedPreferences, key)
            KEY_SETTING_AUTO_SUBMIT_TIME.equals(key) -> onSubmitTimeChanged(sharedPreferences, key)
        }
    }

    private fun onSubmitTimeChanged(preferences: SharedPreferences?, key: String) {
        // 取消定时任务
        HomeDoorApplication.instance.cancelAlarm(ALARM_REPLENISH_STOCK_CODE, ACTION_ALARM_REPLENISH_STOCK)
        var hourMinuteArray = preferences?.getString(KEY_SETTING_AUTO_SUBMIT_TIME, "00:00")!!.split(":")
        HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),
                hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_REPLENISH_STOCK_CODE,
                ACTION_ALARM_REPLENISH_STOCK)
    }

    private fun onSynchronizeTimeChanged(preferences: SharedPreferences?, key: String) {
        // 取消定时任务
        HomeDoorApplication.instance.cancelAlarm(ALARM_SYNCHRONIZE_CODE, ACTION_ALARM_SYNCHRONIZE)
        // 设置定时任务
        var hourMinuteArray = preferences?.getString(KEY_SETTING_SYNCHRONIZE_TIME, "00:00")!!.split(":")
        HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),
                hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_SYNCHRONIZE_CODE,
                ACTION_ALARM_SYNCHRONIZE)
    }

    // 自动提交订单设置有变化,启用则绑定闹钟,禁用则取消闹钟
    private fun onAutoSubmitChanged(preferences: SharedPreferences?, key: String) {
        var isAutoSubmit = preferences?.getBoolean(key, true)!!
        if (isAutoSubmit) {
            preferenceScreen.findPreference(KEY_SETTING_AUTO_SUBMIT_TIME).isEnabled = true
            var hourMinuteArray = preferences?.getString(KEY_SETTING_AUTO_SUBMIT_TIME, "00:00")!!.split(":")
            HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),
                    hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_REPLENISH_STOCK_CODE,
                    ACTION_ALARM_REPLENISH_STOCK)
        } else {
            preferenceScreen.findPreference(KEY_SETTING_AUTO_SUBMIT_TIME).isEnabled = false
            // 取消定时任务
            HomeDoorApplication.instance.cancelAlarm(ALARM_REPLENISH_STOCK_CODE, ACTION_ALARM_REPLENISH_STOCK)
        }
    }

    private fun onAutoSynchronizeChanged(preferences: SharedPreferences?, key: String) {
        var isAutoSynchronize = preferences?.getBoolean(key, true)!!
        if (isAutoSynchronize) {
            preferenceScreen.findPreference(KEY_SETTING_SYNCHRONIZE_TIME).isEnabled = true
            // 设置定时任务
            var hourMinuteArray = preferences?.getString(KEY_SETTING_SYNCHRONIZE_TIME, "00:00")!!.split(":")
            HomeDoorApplication.instance.setAlarm(AlarmManager.RTC_WAKEUP, hourMinuteArray[0].toInt(),
                    hourMinuteArray[1].toInt(), AlarmManager.INTERVAL_DAY, ALARM_SYNCHRONIZE_CODE,
                    ACTION_ALARM_SYNCHRONIZE)
        } else {
            preferenceScreen.findPreference(KEY_SETTING_SYNCHRONIZE_TIME).isEnabled = false
            // 取消定时任务
            HomeDoorApplication.instance.cancelAlarm(ALARM_SYNCHRONIZE_CODE, ACTION_ALARM_SYNCHRONIZE)
        }
    }
}

SharedPreferences.OnSharedPreferenceChangeListener接口用于监听设置项的改变,从代码中可以看出,如果是关闭自动任务,则直接调用取消闹钟;如果是重新设置了任务执行时间,则先取消闹钟,再用新的时间重新设置闹钟。取消和设置都在前面的Application中定义了,这里只是简单地调用即可。

2019-07-02 09:06:59 qq_34351538 阅读数 1554

Android定时关机,定时重启。这个需求主要分为两部分1.定时2.关机/重启。定时直接使用系统的定时服务(AlarmManager);关机/重启虽然系统提供了相应的api,但是该api只对系统级的应用开放,普通的应用无法使用。使用此api需要把app打包成系统应用,因此开关机功能只能在一些定制的系统中使用。

打包成系统应用方式:

1.系统对应的公钥文件platform.pk8和私钥文件platform.x509.pem以及签名工具signapk.jar;

2.将需要打包的apk和第一步里面提到的三个文件放到统一个文件夹下;

3.打开cmd进入第二步里的文件夹下执行命令:java -jar signapk.jar platform.x509.pem platform.pk8 app-release.apk new.apk

如果满足上面的条件就可以轻松实现(定时)关机重启的功能了

关机:

Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
//是否显示关机提示dialog,true显示false不显示直接关机
intent.putExtra("android.intent.extra.KEY_CONFIRM", true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

定时关机:

Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
//是否显示关机提示dialog,true显示false不显示直接关机
intent.putExtra("android.intent.extra.KEY_CONFIRM", true);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

//获取闹钟的id,给定时设置一个随机id,这样可以设置多个定时器,否则会被覆盖掉
int alarmId = getIntRandom();
long intervalMillis = 24 * 3600 * 1000;

PendingIntent pi = PendingIntent.getActivity(MainActivity.this, alarmId, intent, 0);
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

//设置重复定时,intervalMillis重复定时的间隔时间。根据自己的需求来设置定时
manager.setRepeating(AlarmManager.RTC_WAKEUP, time, intervalMillis, pi);

//设置一次定时,根据自己的需求来设置定时
//manager.set(AlarmManager.RTC_WAKEUP, time, pi);

重启:

Intent intent=new Intent(Intent.ACTION_REBOOT);
intent.putExtra("nowait", 1);
intent.putExtra("interval", 1);
intent.putExtra("window", 0);
sendBroadcast(intent);

定时重启:

Intent intent = new Intent(Intent.ACTION_REBOOT);
intent.putExtra("nowait", 1);
intent.putExtra("interval", 1);
intent.putExtra("window", 0);

//获取闹钟的id,给定时设置一个随机id,这样可以设置多个定时器,否则会被覆盖掉
int alarmId = getIntRandom();
long intervalMillis = 24 * 3600 * 1000;

PendingIntent pi = PendingIntent.getActivity(MainActivity.this, alarmId, intent, 0);
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

//设置重复定时,intervalMillis重复定时的间隔时间。根据自己的需求来设置定时
manager.setRepeating(AlarmManager.RTC_WAKEUP, time, intervalMillis, pi);

//设置一次定时,根据自己的需求来设置定时
//manager.set(AlarmManager.RTC_WAKEUP, time, pi);

//manager.setExact(AlarmManager.RTC_WAKEUP, time, pi);
//set()和setExact()两种方法都是设置定时的,区别在于set()方法定时会有误差而setExact()是精确定时

 

2016-11-04 14:20:58 deanwq 阅读数 549

#转载自 http://blog.csdn.net/lyjit/article/details/51312367


为了不占用开发的时间,我们通常会选择晚上下班后让项目自动编译,那么如何定时编译项目呢。Android5.1和Android6.0定时编译项目的方法是一样的,下面就我本地的C100H_V20(Android5.1)项目工程为例:

首先总体看一下工程下面都有那些文件:

然后打开你的编译脚本,里面的内容如下:

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #update  
  2. svn cleanup  
  3. svn up  
  4.   
  5. #compile  
  6.   
  7. chmod 777 -R ./  
  8. source build/envsetup.sh  
  9.   
  10. lunch full_gxq6735_35gc_l1-eng  
  11. #lunch full_gxq6735_35gc_l1-user  
  12.   
  13. make clean -j8 2>&1 | tee build.log  
  14.   
  15. make -j8 2>&1 | tee build.log  
1:在项目中打开终端,输入下图中的指令来加载编译环境:

2:在终端中加载项目名,下图中的指令是编译开发(Debug)版本,如果编译User版本的话执行: lunch full_gxq6735_35gc_l1-user就可以了。

3:定时编译,其中定时编译的时间自己定义。下图是凌晨一点的编译指令: