转载请注明出处: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(); } }
接下来需要实现关闭软件和提示的功能了,新建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>
下载源码,点击这里!