如需转载,请注明出处,谢谢!
这篇文章是主要是把剩下的Service和BroadcastReceiver讲完,即倒计时的具体实现。因为代码中有一些比较细节的地方,我讲得不够清楚的欢迎提问。
我写了一个继承自Service的TimerService类,除了默认要实现的onBind方法外,还重写了onCreate、onStartCommand、onDestroy方法。
onCreate方法中主要做一些初始化的操作:
@Override
public void onCreate() {
super.onCreate();
mTimer = new Timer();
preferences = getSharedPreferences(ConstantUtil.PREFERENCE, Context.MODE_PRIVATE);
}
需要注意的是,这里的preference与MainActivity中的preference不是同一个。在这里顺带讲一下Sharedpreferences:
Sharedpreferences本身是一个接口,可通过以下几个方法获得:
getPreferences(int mode); // 只属于该Activity,一个Activity只有一个
PreferenceManager.getDefaultSharedPreferences(this); // 属于整个应用程序,只有一个
getSharedpreferences(String name, int mode); // 属于整个应用程序,可以有多个
这里用到preference的原因下面会讲到。
onDestroy方法主要做一些变量的销毁,没什么好讲的。
@Override
public void onDestroy() {
super.onDestroy();
if (mTimer != null) {
mTimer = null;
}
if (mTask != null) {
mTask.cancel();
mTask = null;
}
if (preferences != null) {
preferences = null;
}
}
主要的代码在 onStartCommand中:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 必须判断一下,否则可能导致程序无法运行
if (intent == null) {
return super.onStartCommand(intent, flags, startId);
}
String action = intent.getAction();
if (action.equals(ConstantUtil.START)) {
currentProgress = intent.getIntExtra(ConstantUtil.CURRENT_PROGRESS, 0);
progress = intent.getIntExtra(ConstantUtil.PROGRESS, 0);
start();
} else if (action.equals(ConstantUtil.PAUSE)) {
pause();
} else if (action.equals(ConstantUtil.STOP)) {
stop();
}
return super.onStartCommand(intent, flags, startId);
}
程序中可能会出现这种情况:倒计时任务正在进行,但用户继续点击开始按钮,因此在这里先判断一下mTask是否为空再进一步操作。(为了防止这种情况出现,也可以让任务在进行的时候讲开始按钮设置为不可点击。)然后再通过mTimer启动mTask任务进行倒计时。关于Timer和TimerTask,这里就不做介绍了。
private void start() {
// 有任务正在进行,发送广播通知Activity
if (mTask != null) {
Intent intent = new Intent(ConstantUtil.ALREADY_RUN);
sendBroadcast(intent);
return;
}
mTask = new MyTimerTask();
mTimer.schedule(mTask, 1000, 1000);
}
pause方法中,我没找到可以使TimerTask暂停的方法,所以就直接cancel掉了,然后把状态保存下来。
private void pause() {
if (mTask != null) {
mTask.cancel();
mTask = null;
}
// 将当前进度发回activity保存
Intent intent = new Intent(ConstantUtil.PAUSE);
intent.putExtra(ConstantUtil.CURRENT_PROGRESS, currentProgress);
sendBroadcast(intent);
}
关于stop方法,这里指的是点击停止按钮强行停止倒计时。
/**
* 人为停止计时器
*/
private void stop() {
if (mTask != null) {
mTask.cancel();
mTask = null;
}
}
private class MyTimerTask extends TimerTask {
@Override
public void run() {
if (++currentProgress >= progress) {
timeout();
} else {
running();
}
}
}
running方法中,只是向Activity发送广播,通知Activity更新UI
private void running() {
// 发送广播使activity更新UI
Intent intent = new Intent(ConstantUtil.RUNNING);
intent.putExtra(ConstantUtil.CURRENT_PROGRESS, currentProgress);
sendBroadcast(intent);
}
timeout方法中要做的工作就比较多了,上面在onCreate方法中声明的preferences在这里就要用到了。
/**
* 倒计时完成,停止计时器
*/
private void timeout() {
if (mTask != null) {
mTask.cancel();
mTask = null;
}
Intent intent = new Intent(ConstantUtil.TIMEOUT);
sendBroadcast(intent);
// 当activity无法收到倒计时完成的消息时,将停止状态保存在sharedpreference中
// activity再次启动时便可以判断倒计时是否已完成
Editor editor = preferences.edit();
editor.putBoolean(ConstantUtil.STOP, true);
editor.commit();
// 创建通知
createNotification();
}
private void createNotification() {
Intent contentIntent = new Intent();
contentIntent.setClass(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, contentIntent, 0);
if (MainActivity.isDestroy) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification.Builder(getApplicationContext())
.setContentTitle("Timeout")
.setContentText("恭喜你,消耗了" +progress +"秒")
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
mNotificationManager.notify(0, notification);
}
// 发出系统通知声音和调用震动
ringAndVibrator();
}
private void ringAndVibrator() {
// 控制震动
Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long pattern[] = {100, 300, 100, 400};
vibrator.vibrate(pattern, -1);
// 获取系统通知声音
Uri alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
MediaPlayer player = new MediaPlayer();
try {
player.setDataSource(this, alert);
} catch (Exception e) {
e.printStackTrace();
}
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION) != 0) {
player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
player.setLooping(false);
try {
player.prepare();
} catch (Exception e) {
e.printStackTrace();
}
player.start();
}
}
在service中发送的广播都是发给Activity的,因此,在Activity中创建一个BroadcastReceiver,然后在onCreate中注册并在onDestroy中注销掉。
private class ServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ConstantUtil.ALREADY_RUN)) {
toast = Toast.makeText(getApplicationContext(), "任务正在进行中...", SHORT);
toast.show();
} else if (action.equals(ConstantUtil.PAUSE)) {
int data = intent.getIntExtra(ConstantUtil.CURRENT_PROGRESS, 0);
currentProgress = data;
} else if (action.equals(ConstantUtil.RUNNING)) {
int data = intent.getIntExtra(ConstantUtil.CURRENT_PROGRESS, 0);
currentProgress = data;
showView.setText((progress - currentProgress) + "");
} else if (action.equals(ConstantUtil.TIMEOUT)) {
currentProgress = 0;
showView.setText(getResources().getString(R.string.default_text));
AlertDialog dialog = new AlertDialog.Builder(MainActivity.this)
.setTitle("Timeout")
.setMessage("恭喜你消耗了" + progress + "秒")
.setPositiveButton("好的", null)
.create();
dialog.show();
}
}
}
好了,到了这里,整个应用就算完成了! 附上源码链接: 源码下载
如果发现Bug或者是对代码的实现有什么建议,欢迎大家指出来~~