Android无界面编程之使用Service
在上节中我记录了Service的生命周期,现在就来熟悉一下如何来使用Service和Service有哪些特别需要注意的知识点。
基本流程:
一、建立Service,通过编写子类继承Service或IntentService。
二、在AndroidManifest.xml中注册<service/>。
三、在别的组件中调用startService(Intent intent)。
具体说明:
第一步:建立服务
-extends Service
子类Service必须要覆写的回调方法是onBind(Intent intent),其返回IBinder对象。如果不需要提供绑定服务直接返回null,之后在生命周期方法中处理工作。其特点是用程序的主线程,如果直接做耗时处理的话会影响程序的性能,导致程序UI线程阻塞。如在onStartCommand()中执行如下代码,让线程等待5秒,将导致主线程阻塞,界面在线程等待期间,不能作任何响应。
long endTime = System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()<endTime){ synchronized (this) { try { wait(endTime - System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } Log.v(TAG, "工作线程醒过来了!"); } }
正确的写法是为Service新开线程进行耗时处理,如下:
package com.example.test; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Process; import android.util.Log; /** * 服务开启工作线程模拟耗时工作5秒 * @author Change * */ public class MainService extends Service { public static final String TAG = "show"; private Looper looper = null; private MyHandler handler = null; public class MyHandler extends Handler{ public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.v(TAG, "工作线程睡觉中!"); long endTime = System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()<endTime){ synchronized (this) { try { wait(endTime - System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } //执行完,停止服务! stopSelf(msg.arg1); Log.v(TAG, "工作线程醒过来了!"); } } } } @Override public void onCreate() { super.onCreate(); //创建handler专用后台线程。 HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); //创建线程对应handler looper = thread.getLooper(); handler = new MyHandler(looper); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Message msg = handler.obtainMessage(); msg.arg1 = startId; handler.sendMessage(msg); //如果被系统关闭将自动重启 return START_STICKY; } @Override public IBinder onBind(Intent arg0) { // 不需要提供服务绑定的时候返回null。 return null; } @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "服务已完成任务中止了!"); } }
程序执行结果:
-extends IntentService
上面通过继承Service基类实现子类的工作服务,如果当你的服务不需要操作多个任务时有更简单的方式就是通过继承IntentService,是一个默认有后台线程的服务,只需要重写构造,调用父类构造,传入准备创建的后台线程名称:
package com.example.test; import android.app.IntentService; import android.content.Intent; import android.util.Log; /** * 简单后台线程服务 * @author Change * */ public class BackgroundService extends IntentService { public static final String TAG = "show"; //必须实现该构造 public BackgroundService() { //创建一个名为BackgroundService的后台工作线程。 super("BackgroundService"); } //该方法中执行后台操作 @Override protected void onHandleIntent(Intent i) { Log.v(TAG, "工作线程睡觉中!"); long endTime = System.currentTimeMillis()+5*1000; while(System.currentTimeMillis()<endTime){ synchronized (this) { try { wait(endTime - System.currentTimeMillis()); }catch (InterruptedException e) { e.printStackTrace(); } Log.v(TAG, "工作线程醒过来了!"); } } } }
执行结果跟extends Service一样。
第二步:注册服务
在AndroidManifest.xml中注册刚刚创建的服务。
在application内添加
<service android:name=".MainService" android:exported="false"> <intent-filter > <action .../> <category .../> <data .../> </intent-filter> </service>
最简单的注册方式只需要提供一个名称:<service android:name=".MainService"/>
exported是否为其他程序提供服务。为true的话可以给其它程序绑定使用,为false的话则不行。
Service跟Activity一样,同样可以注册intent-filter内的相关内容。
第三步:启动服务
服务不能自己启动,要通过其他组件来启动。可以是Activity、Service、BroadcastReceiver等。通过调用startService()即可。
Intent start = new Intent(this,BackgroundService.class); startService(start);
或者用adb命令启动
其它参数
这个在做与pc进行adb通信时会用到。