Android的Service使用
来源:互联网 发布:淘宝的免费模板在哪里 编辑:程序博客网 时间:2024/05/27 20:51
Service
Service属于Android的四大组件(只要是安卓四大组件就必须在AndroidMainFest中进行注册才可以使用),Service运行不赖于界面,即使退出应用,Service也将运行在后台中。服务在创建后,默认运行在主线程中,所以我们需要自己去开辟子线程,如果不开辟就有可能出现主线程被阻塞。
Android多线程
对于很多耗时操作(比如:发起网络请求,由于网络很慢,服务器不一定立刻响应),我们一般把操作放在子线程中进行。
线程基本用法
- 定义一个线程需要继承Thread类,重写run()方法:
class XXThread extends Thread { @Override public void run() { // 处理具体的逻辑 }}
启动该线程:
new XXThread().start();
- 使用Runable接口方法来定义一个线程
class XXThread implements Runnable{ @Override public void run() { }}
启动该线程
XXThread mThread = new XXThread(); new Thread(mThread).start();
- 使用匿名类的方法
new Thread(new Runnable() { @Override public void run() { // 处理具体的逻辑 } }).start();
异步消息处理机制
我们是不能在子线程中更新UI中的内容,但是有时候我们却需要把子线程的内容更新到UI,Android提供一套异步消息处理机制来解决这个问题。
从图中可以发现,异步消息处理有4部分,分别是Message,Handle,MessageQuery,Looper四部分组成。在线程中我们调用 hanler.setMessage() 方法来发送消息给 MessageQuery,然后通过 Looper 来取出带处理消息,并且传回给 handler,然后调用在 UI 中的 handler.handleMessage() 方法来实现对 UI中的内容更新。
代码示例
TEXT_UPDATE
自己定义的一个常量
- UI线程中的代码
private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case TEXT_UPDATE: tvShow.setText("你改变了TextView的内容"); break; default: break; } } };
- 子线程中的代码
@Override public void onClick(View v) { switch (v.getId()) { case R.id.btnUpdate: new Thread(new Runnable() { @Override public void run() { Message message = new Message(); message.what = TEXT_UPDATE; handler.sendMessage(message); } }).start(); break; default: break; } }
Service应用
前面讨论这么多关于多线程编程的问题都为在Service的使用上做准备的。先讨论最简单的基本用法
基本用法
Service和Activity一样都拥有 onCreate(),onDestroy()方法,来实现Service的创建和销毁。当然他们也有区别,在Service中我们必须实现 onBind() 方法,该方法用于与UI绑定(先不讨论)。在Service还有一个方法叫 onStartCommand(),这个方法和 onCreate() 区别是:onStartCommand()每次Service启动(包括第一次创建)都会启动这个方法,但是onCreate()只会在第一次创建的时候启动,之后不会再启动该方法
代码示例
- 创建一个Service
public class TestService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId); }}
- 启动一个Service
Intent startIntent = new Intent(this, TestService.class); startService(startIntent);
- 停止一个Service
停止Service需要注意,如果Service不仅被创建了,而且被绑定了,那么如果要停止这个Service,就需要同时执行 stopService() 和 unbindService(),才可以停止Service。
Intent stopIntent = new Intent(this, TestService.class); stopService(stopIntent);
将Service绑定到UI中
如果要将Service绑定到UI中去,必须在 onBind() 方法中传回一个对象,使得UI可以操作Service中的方法,这个对象就好比一座桥梁连接着UI和Service。
代码示例
- 创建一个Biner对象,来实现Service中的公共方法
private DownloadBinder mBinder = new DownloadBinder(); class DownloadBinder extends Binder { public void startDownload() { Log.e(TAG, "开始下载"); } public int getProgress() { Log.e(TAG, "获取进度表"); return 0; } public void stopDownload() { Log.e(TAG, "停止下载"); } }
- 桥梁的建立
@Nullable @Override public IBinder onBind(Intent intent) { //返回一个连接通道给service return mBinder; }
到此UI还没有和Service建立真正的桥梁,在UI中必须调用 bindService() 方法来绑定服务,在使用此方法之前
,我们还需要 ServiceConnection的实现,来建立UI与Ser的连接。ServiceConnection 中有两个方法需要实现分别是 onServiceConnected() 和 onServiceDisconnected(),前者在调用bindService() 来建立连接的时候,会去调用此方法,但是在解除绑定的时候,却不会调用onServiceDisconnected(),只要发生系统意外的时候,才会调用此方法。
我们在onServiceConnected()中来调用Service中的公共方法
- ServiceConnection的实现
private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { downloadBinder = (TestService.DownloadBinder) service; downloadBinder.startDownload(); downloadBinder.getProgress(); } @Override public void onServiceDisconnected(ComponentName name) { //系统发生意外中断的时候才会调用此方法 //客户端取消绑定的时候不会调用 } };
到此我们还是不能调用Service中的方法,因为我们还没有使用onServiceConnected()来绑定。BIND_AUTO_CREATE 代表自动完成绑定。
- 桥梁的完成
Intent bindIntent = new Intent(this, TestService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE);
到此我们就可以任意调用Service中的公共方法了
- 桥梁的爆破
解除绑定是非常简单的,只需要调用 unbindService() 方法,需要注意的是:如果已经解除绑定了,再次调用会报错
unbindService(connection);
到这我们就已经学习了Service的创建、删除、绑定、取消绑定。但是这些都是在UI主线程中进行,就像我们前面提到如果遇到了耗时任务,将会被阻塞。所以我们要使用多线程技术。
IntendService的应用
IntendService的使用,可以使得开发者不必去停止服务,系统会在请求结束后自动停止服务。我们只需要在 onHandleIntent() 来完成UI所提出的任务即可,不过我们还需要为IntendService提供一个构造函数
代码示例
public class IntentServiceDemo extends IntentService { private static final String TAG_INTENT_SERVICE = "IntentService"; public IntentServiceDemo() { super("IntentServiceDemo"); } @Override protected void onHandleIntent(Intent intent) { Log.e(TAG_INTENT_SERVICE, "线程id是:" + Thread.currentThread().getId()); } @Override public void onDestroy() { super.onDestroy(); Log.e(TAG_INTENT_SERVICE,"服务已经被销毁"); }}
启动IntendService
Log.e("MainActivity", "线程id:" + Thread.currentThread().getId()); Intent intentService = new Intent(this, IntentServiceDemo.class); startService(intentService);
这样Service就运行在子线程中。当然我们也可以不使用IntendService来实现,我们可以自己在 onStartCommand() 方法中,开启一个子线程。但是这样开启一个子线程将永远在执行,所以我们必须在任务完成后,调用 stopSelf() 或者 stopService()方法来关闭。
代码示例
@Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(new Runnable() { @Override public void run() { Log.e(TAG,"每次服务被创建"); stopSelf(); } }).start(); return super.onStartCommand(intent, flags, startId); }
前台Service
应用场景,如果一个天气app,当后台数据更新后,会一直在前台显示更新后的数据情况。这就可以使用前台Service来实现。要在前台一直显示数据,这有点类似于Notification,当时我们不使用NotificationManger来显示出来,而是使用 startForeground()来实现。要注意 startForeground() 方法中的第一个参数id,不能使用0作为id。
代码示例
@Override public void onCreate() { super.onCreate(); // Log.e(TAG, "服务被创建"); //前台服务 NotificationCompat.Builder builder = new NotificationCompat.Builder(this); Intent notificationIntent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); builder.setContentTitle("通知"); builder.setContentText("吃饭了么"); builder.setContentIntent(pendingIntent); builder.setSmallIcon(R.drawable.ic_launcher); builder.setDefaults(Notification.DEFAULT_ALL); builder.setAutoCancel(true); startForeground(1, builder.build()); }
后台定时执行任务
通过AlarmManager(在这不多说)来实现定时功能,同样首先我们通过 getSystemService()方法获得系统服务。然后通过set() 方法来定时唤醒 PendingIntent.getBroadcast()* 方法来发送一个广播,然后再广播内启动Service。整个流程如下图
代码示例
- Service
@Override public int onStartCommand(Intent intent, int flags, int startId) { new Thread(new Runnable() { @Override public void run() { Log.e(TAG, "执行时间:" + new Date().toString()); } }).start(); AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); int aSecond = 60 * 1000;//1分钟 long triggerAtTime = SystemClock.elapsedRealtime() + aSecond; Intent i = new Intent(this, AlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, i, 0); manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent); //Log.e(TAG,"每次服务被创建"); return super.onStartCommand(intent, flags, startId); }
- Broadcoast
public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.e("AlarmReceiver", "接收到了"); Intent i = new Intent(context, ServiceDemo.class); context.startService(i); }}
最后还是感谢《第一行代码》的作者,郭神,文中很多都是来自于这本书。
- Android Service的使用
- Android Service 的使用
- Android service的使用
- Android Service的使用
- Android Service 的使用
- Android Service 的使用
- Android -- Service的使用
- Android Service的使用
- Android service的使用
- Android Service的使用
- Android的Service使用
- Android Service的使用
- android Service 的简单使用
- Android 关于Service 的使用
- Android中service的使用
- Android中的Service的使用
- Android Service的使用解析
- android service的简单使用
- RxBus学习之旅--从入门到提高
- 1024. Palindromic Number (25)
- Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset(字典树模板)
- Python类和对象
- POJ 1703 并查集的应用 关系并查集l两种方法
- Android的Service使用
- 分块算法讲解
- Oulipo poj3461 简单的KMP
- POJ 1416 - Shredding Compan
- 大牛经历
- 如何转载别人的博客
- priority_queue<int,vector<int>,greater<int>>优先队列 按照由小到大顺序
- C语言printf函数输出表达式中的计算顺序
- 源码阅读之Vector