《服务的最佳实践》再实践——定时关闭程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chengbao315/article/details/50997218

转载请注明出处:http://blog.csdn.net/chengbao315/article/details/50997218

最近读书读到了安卓的服务组件(再次推荐偶像的书,郭霖《第一行代码》),读过之后,忽然有种想要编写安卓四大组件小案例的冲动。与大家分享的同时,也能考核自己的学习成果。那么今天就开始第一篇吧:《服务的最佳实践》再实践——定时关闭程序。

作为一名传统的程序猿,编程之前首先想到的是设计需求:仿照一些播放器软件,可以定时关闭应用程序,在界面中可以设置定时时间,退出界面后还可以在系统状态栏显示软件运行状态,后台继续运行程序,直到定时结束给出提示关闭软件。就比如下面这个网上随便找的软件:

 

看到这,许多跟我一样的菜鸟可能跃跃欲试了,但是想必老鸟们又对此不屑一顾了吧。。。小弟新手一枚,不足之处请各位前辈多多指教,大神不喜勿喷,呵呵哒大笑了解了设计需求,软件的设计思路就比较清晰了,无非是几个子功能的组合:界面设置定时时间,前台服务启动,安卓Alarm机制定时,关闭软件和提示。

首先来实现设置定时时间界面,在Eclipse中新建一个Android项目,然后写布局文件,布局比较简单,只需要一个TextView控件和Spinner控件就可以,具体设计根据个人喜好随意,打开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"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/test" />

    <Spinner
        android:id="@+id/degrees"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"
        android:entries="@array/degrees" />

</RelativeLayout> 

接着需要添加下拉列表项,打开values文件夹下string.xml文件,加入下拉列表item内容,加入如下代码:

   <string-array name="degrees">
        <item>请选择</item>
        <item>10s钟</item>
        <item>20s钟</item>
        <item>30s钟</item>
        <item>60s钟</item>
    </string-array>

以上代码即可实现通过下拉列表选择设置定时时间的功能。界面布局有了,接下来实现前台服务的基本功能。新建AlarmService类继承Service,这个类中会在重写onCreate()方法中设置服务为前台服务,并在onStartCommand()方法中启动Alarm计时,AlarmService.java代码如下:

package com.example.servicetest;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;


public class AlarmService extends Service{
	//设置定时时间
	public static int timelong = 0;
	// 定时计数器
	public static int tickCount = 0;
	
	@Override
	public IBinder onBind(Intent intent){
		return null;
	}
	
	@Override
	public void onCreate(){
		super.onCreate();
		Notification notification = new Notification(R.drawable.ic_launcher,
				"启动定时服务", System.currentTimeMillis());
		Intent notificationIntent = new Intent(this, MainActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
				notificationIntent, 0);
		notification.setLatestEventInfo(this, "ServerTest_app", "定时关闭应用程序",
				pendingIntent);
		// 设置为前台服务
		startForeground(1, notification);
	}
	
	@Override
	public int onStartCommand(Intent intent,int flags,int startId){
		AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);
		// 设置1秒定时
		long setTime = 1000 + SystemClock.elapsedRealtime();
		Intent i = new Intent(this,AlarmReceiver.class);
		PendingIntent p = PendingIntent.getBroadcast(this,0,i,0);
		//设置定时任务
		manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,setTime,p);
		return super.onStartCommand(intent, flags, startId);
	}
	
	@Override
	public void onDestroy(){
		super.onDestroy();
	}
}

在onCreate()方法中,先创建了一个通知,将通知作为一个参数传递到startForeground()方法中,这个方法可以将Service变成一个前台服务。关于通知的使用方法可以阅读郭霖《第一行代码》第八章。在onStartCommand()方法中,首先获取一个AlarmManager实例,设置定时时间为1秒钟,并且获取一个广播的PendingIntent 作为参数,当定时任务触发时会广播给应用程序。其实安卓有多种方法可以实现定时任务,使用Alarm机制可以有效避免CPU休眠时造成定时器停止工作,大家可以参考原书郭霖《第一行代码》9.6章节《服务的最佳实践——后台执行的定时任务》中的解释。

接下来需要实现关闭软件和提示的功能了,新建AlarmReceiver类继承BroadcastReceiver,重写onReceive()方法,实现在定时前3秒钟通过Toast提示关闭软件,在定时结束时关闭软件,AlarmReceiver.java 代码如下:

package com.example.servicetest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 小于定时时间,重新启动定时服务
        if (AlarmService.tickCount++ < AlarmService.timelong) {
            Intent start = new Intent(context, AlarmService.class);
            context.startService(start);
        } else {
            // 等于定时时间关闭服务,关闭程序
            Intent stop = new Intent(context, AlarmService.class);
            context.stopService(stop);
            System.exit(0);
        }
        // 前3秒给出提示
        if (AlarmService.tickCount == AlarmService.timelong - 3)
            Toast.makeText(context, "即将关闭程序", Toast.LENGTH_LONG).show();
    }
}

当1秒定时结束时,广播接收器会接收到服务的广播,在onReceive()方法中对tickCount进行累加,通过与定时时间的比较,做出相应的处理。这种方法可以有效实现需求的功能,但是如果长时间定时的话,1秒钟一启动服务感觉会比较浪费资源,但是小弟确实新手,暂时还没有更好的解决方法,以后会继续努力,也请有经验的大神指点指点。

文章写到这里,所有的功能模块都已经完成了,下面需要在主程序中对模块进行整理和调用了,打开MainActivity.java文件,加入如下代码:

package com.example.servicetest;

import android.app.Activity;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.Toast;

public class MainActivity extends Activity implements OnItemSelectedListener {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);
		Spinner sp = (Spinner) findViewById(R.id.degrees);
		sp.setOnItemSelectedListener(this);
	}

	@Override
	public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
			long arg3) {
		Intent i = new Intent(this, AlarmService.class);
		switch (arg2) {
		case 0:
			break;
		case 1:
			AlarmService.timelong = 10;
			this.startService(i);
			break;
		case 2:
			AlarmService.timelong = 20;
			this.startService(i);
			break;
		case 3:
			AlarmService.timelong = 30;
			this.startService(i);
			break;
		case 4:
			AlarmService.timelong = 60;
			this.startService(i);
			break;
		}

	}

	@Override
	public void onNothingSelected(AdapterView<?> arg0) {
		// TODO Auto-generated method stub
	}
}

代码比较简单,需要实现接口 Spinner 的OnItemSelectedListener 接口即可,在重写onItemSelectd()方法,在方法中根据选择项设置定时时间,并启动前台服务。写到这如果你觉得结束了,那么你也就太粗心了,非常重要的地方你忘记了,打开AndroidManifest.xml文件,需要加入注册服务和广播的代码,不懂回去看书,代码如下:
        <service android:name=".AlarmService" >
        </service>

        <receiver android:name=".AlarmReceiver" >
        </receiver>
这样,所有的问题都解决了,看下运行结果吧!

 

下载源码,点击这里!

猜你喜欢

转载自blog.csdn.net/chengbao315/article/details/50997218
今日推荐