在开发应用中,或多或少都会遇到Service有关知识。今天就来分析Service的使用。

一、概述。

首先看看官网是如何描述的。

A Service is an application component representing either an application's desire to perform a
longer-running operation while not interacting with the user or to supply functionality for
other applications to use. Each service class must have a corresponding <service> declaration
in its package's AndroidManifest.xml. Services can be started with Context.startService()
and Context.bindService(). 

Service是一个应用组件,它表示一个应用期望去执行一个不与用户交互的较长的操作或者通过一些功能为其他应用去使用。每一个Service都必须在AndroidManifest.xml中有<service>声明,Service可以使用Context.startService() 和 Context.bindService()启动。

What is a Service?
Most confusion about the Service class actually revolves around what it is not:
A Service is not a separate process. The Service object itself does not imply
it is running in its own process; unless otherwise specified, it runs in the
same process as the application it is part of.
A Service is not a thread. It is not a means itself to do work off of the main
thread (to avoid Application Not Responding errors). 

Service不是一个单独的进程。Service对象并不意味着它运行在自己的进程中;除非另有说明,否则它运行在同一进程中作为应用的一部分。

Service不是一个线程。这不意味着它可以在主线程中之外工作(去避免应用无响应错误)。

Thus a Service itself is actually very simple, providing two main features:
A facility for the application to tell the system about something it wants
to be doing in the background (even when the user is not directly interacting
with the application). This corresponds to calls to Context.startService(),
which ask the system to schedule work for the service, to be run until the
service or someone else explicitly stop it.
A facility for an application to expose some of its functionality to other
applications. This corresponds to calls to Context.bindService(), which
allows a long-standing connection to be made to the service in order to
interact with it. 

因此,Service自身实际上是非常简单的,提供了两个特征:

应用程序告诉系统它想要在后台工作(即使用户和应用不直接交互),这对应会调用Context.startService(),要求系统为Service调度工作,去运行直到Service或其他人明确停止它。

应用程序暴露了一些功能给其他应用。这对应会调用Context.bindService(),这样允许对Service一个长连接以便与它交互。

When a Service component is actually created, for either of these reasons,
all that the system actually does is instantiate the component and call
its onCreate() and any other appropriate callbacks on the main thread.
It is up to the Service to implement these with the appropriate behavior,
such as creating a secondary thread in which it does its work.
Note that because Service itself is so simple, you can make your
interaction with it as simple or complicated as you want: from treating
it as a local Java object that you make direct method calls on
(as illustrated by Local Service Sample), to providing a full remoteable
interface using AIDL.

当一个Service组件完全创建,系统实际上初始化该组件并且调用了它的onCreate()方法,在主线程中有适当的回调。这些由Service来实现适当的行为,例如创建一个辅助线程来工作。

注意,由于Service它自身比较简单,可以使你和它的交互是简单或复杂;将它看作一个Java本地对象,你可以直接调用方法,提供一个远程接口使用AIDL。

Service Lifecycle
There are two reasons that a service can be run by the system. If someone
calls Context.startService() then the system will retrieve the service
(creating it and calling its onCreate() method if needed) and then call
its onStartCommand(Intent, int, int) method with the arguments supplied
by the client. The service will at this point continue running until
Context.stopService() or stopSelf() is called. Note that multiple
calls to Context.startService() do not nest (though they do result
in multiple corresponding calls to onStartCommand()), so no matter
how many times it is started a service will be stopped once
Context.stopService() or stopSelf() is called; however,
services can use their stopSelf(int) method to ensure the
service is not stopped until started intents have been processed.For started services, there are two additional major modes of
operation they can decide to run in, depending on the value
they return from onStartCommand(): START_STICKY is used for
services that are explicitly started and stopped as needed,
while START_NOT_STICKY or START_REDELIVER_INTENT are used for
services that should only remain running while processing any
commands sent to them. See the linked documentation for more
detail on the semantics.Clients can also use Context.bindService() to obtain a persistent
connection to a service. This likewise creates the service if it
is not already running (calling onCreate() while doing so), but
does not call onStartCommand(). The client will receive the IBinder
object that the service returns from its onBind(Intent) method,
allowing the client to then make calls back to the service. The
service will remain running as long as the connection is established
(whether or not the client retains a reference on the service's IBinder).
Usually the IBinder returned is for a complex interface that has been written in aidl.A service can be both started and have connections bound to it.
In such a case, the system will keep the service running as
long as either it is started or there are one or more connections
to it with the Context.BIND_AUTO_CREATE flag. Once neither of these
situations hold, the service's onDestroy() method is called and the
service is effectively terminated. All cleanup (stopping threads,
unregistering receivers) should be complete upon returning from onDestroy(). 

调用Context.startService()时,系统将检索Service(创建它并且调用onCreate()方法如果需要的话),接着将调用onStartCommand(Intent, int, int)方法由客户端。此时服务将继续允许,直到调用了Context.stopService() 和stopSelf()。注意,多次调用Context.startService()并不会重复创建(即使它相应的调用了多次onStartCommand()),因此,不管启动一个service多少次,一旦调用Context.stopService() 和stopSelf()将会停止;services能使用它的stopSelf(int)方法确保 Service不会停止直到启动intents被处理。

为了启动一个services,他们有两个额外的主要模式操作,它能决定运行,依靠的是从onStartCommand()返回的值:START_STICKY用于根据需要显示启动或者停止,而START_NOT_STICKY和START_REDELIVER_INTENT用于services应当仅仅保留运行当进程发送任何指令给他们的时候。

客户端可以使用Context.bindService()来获得一个持久连接到一个service。这样同样创建了一个service如果它没有运行(当运行时会调用onCreate()),但是不会调用onStartCommand()方法。客户端将接受到一个IBinder对象从service的onBind(Intent)方法返回,允许客户端回调service。service将继续运行只要连接建立(无论客户端是否保留对service的IBinder引用)。通常IBinder返回的是一个复杂的用AIDL写的接口。

service能够启动并且绑定连接。在这种情况下,系统将保持service运行只要它启动或者它有一个或者多个连接通过Context.BIND_AUTO_CREATE标志。一旦这些情况都没有保持,那么service 的onDestroy()方法会调用,并且service 被终止。所有的清理(停止线程、注销接收器)都应当从onDestroy()返回时完成。

PermissionsGlobal access to a service can be enforced when it is declared in its manifest's <service> tag.
By doing so, other applications will need to declare a corresponding <uses-permission> element
in their own manifest to be able to start, stop, or bind to the service.As of GINGERBREAD, when using Context.startService(Intent), you can also set
Intent.FLAG_GRANT_READ_URI_PERMISSION and/or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
on the Intent. This will grant the Service temporary access to the specific URIs in the Intent.
Access will remain until the Service has called stopSelf(int) for that start command or a later one,
or until the Service has been completely stopped. This works for granting access to the other apps
that have not requested the permission protecting the Service, or even when the Service is not exported at all.In addition, a service can protect individual IPC calls into it with permissions, by calling
the checkCallingPermission(String) method before executing the implementation of that call.See the Security and Permissions document for more information on permissions and security in general. 

权限

当在manifest中声明<service>标签后,可以强制全局访问service。通过这样做,其他应用需要声明一个相应的<uses-permission>权限在自己的manifest文件中,以至于可以开启、停止或者绑定service。

随着GINGERBREAD的发布,当使用Context.startService(Intent)时,可以在Intent中设置Intent.FLAG_GRANT_READ_URI_PERMISSION 或者Intent.FLAG_GRANT_WRITE_URI_PERMISSION 。这将给予service临时访问特定URIs。访问会继续保留知道Service调用了stopSelf(int),启动命令后者下一个命令,或者直到Service完全停止。这适用于其他应用获取访问没有请求包含服务的权限,或者

此外,service可以保护私有IPC在拥有权限才能调用,在执行实现之前调用checkCallingPermission(String)。

有关权限和安全性的更多信息,请参阅安全和权限文档。

Process LifecycleThe Android system will attempt to keep the process hosting a service around as long as the service has been started
or has clients bound to it. When running low on memory and needing to kill existing processes, the priority of a
process hosting the service will be the higher of the following possibilities:If the service is currently executing code in its onCreate(), onStartCommand(), or onDestroy() methods, then the hosting process will be a foreground process to ensure this code can execute without being killed.If the service has been started, then its hosting process is considered to be less important than any processes that are currently visible to the user on-screen, but more important than any process not visible. Because only a few processes are generally visible to the user, this means that the service should not be killed except in low memory conditions. However, since the user is not directly aware of a background service, in that state it is considered a valid candidate to kill, and you should be prepared for this to happen. In particular, long-running services will be increasingly likely to kill and are guaranteed to be killed (and restarted if appropriate) if they remain started long enough.If there are clients bound to the service, then the service's hosting process is never less important than the most important client. That is, if one of its clients is visible to the user, then the service itself is considered to be visible. The way a client's importance impacts the service's importance can be adjusted through BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, BIND_WAIVE_PRIORITY, BIND_IMPORTANT, and BIND_ADJUST_WITH_ACTIVITY.A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.) Note this means that most of the time your service is running, it may be killed by the system if it is under heavy memory
pressure. If this happens, the system will later try to restart the service. An important consequence of this is that if
you implement onStartCommand() to schedule work to be done asynchronously or in another thread, then you may want to use
START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is
killed while processing it.Other application components running in the same process as the service (such as an Activity) can, of course, increase
the importance of the overall process beyond just the importance of the service itself. 

Android系统将尝试保持在主进程中service只要service启动或者有客户端绑定它。当运行内存较低,需要杀死当前存在的进程,service所在进程的优先级可能会遵循以下可能性:

如果service目前正在执行onCreate(), onStartCommand(), 或者onDestroy() 方法,它所在的进程变为一个前台进程,确保执行这些代码时不被杀死。

如果service已经启动,那么它所在的进程相对于当前用户在屏幕上可见的任务进程来说都是不重要的,但是比任何不可见的进程都重要。因为通常来说只有一些进程是可见的,这意味着service不应当被杀死,除非内存不足。然而,由于用户没有直接意识到后台service,在这种状态下,被认为是处于等待杀死,并且需要为这样做好准备。特别的,长期运行的services被杀死的可能性较大,保证被杀死(在适当的时候重启)如果他们已经启动了好长时间。

如果客户端绑定了service,这个service的宿主进程永远都不重要,但是比客户端更重要。也就是说,一个客户端是可见的,那么service自身被认为就是可见的。客户端的重要性会影响service的重要性,可以通过BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, BIND_WAIVE_PRIORITY, BIND_IMPORTANT, and BIND_ADJUST_WITH_ACTIVITY调整。

一个启动的service可以使用startForeground()将一个service变为前台状态。系统认为这是用户主动触发,所以在低内存是不会变为待杀死。(在极端内存压力下,一个前台应用中的service在理论上也是可能被杀死的,但是在实践中,这不应当成为一个问题)

请注意,在大部分情况下,正在运行的service,可能被系统杀死在很重的内存压力下。如果发生了,系统将尝试重启service。一个重要的结果是,如果你实现了onStartCommand()去执行一个异步任务或者在一个线程中,那么你可以在Intent中设置START_FLAG_REDELIVERY,以至于不会丢失它当你的service在处理它是被杀死。

在同一个进程中运行的不同应用组件,service(例如Activity),增加整个进程的重要性要超过service本身的重要性。
二、代码示例。

下面,我们看看官网给出的使用service的情景,

public class LocalService extends Service {private NotificationManager mNM;// Unique Identification Number for the Notification.// We use it on Notification start, and to cancel it.private int NOTIFICATION = R.string.local_service_started;/*** Class for clients to access.  Because we know this service always* runs in the same process as its clients, we don't need to deal with* IPC.*/public class LocalBinder extends Binder {LocalService getService() {return LocalService.this;}}@Overridepublic void onCreate() {mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);// Display a notification about us starting.  We put an icon in the status bar.showNotification();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i("LocalService", "Received start id " + startId + ": " + intent);return START_NOT_STICKY;}@Overridepublic void onDestroy() {// Cancel the persistent notification.mNM.cancel(NOTIFICATION);// Tell the user we stopped.Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();}@Overridepublic IBinder onBind(Intent intent) {return mBinder;}// This is the object that receives interactions from clients.  See// RemoteService for a more complete example.private final IBinder mBinder = new LocalBinder();/*** Show a notification while this service is running.*/private void showNotification() {// In this sample, we'll use the same text for the ticker and the expanded notificationCharSequence text = getText(R.string.local_service_started);// The PendingIntent to launch our activity if the user selects this notificationPendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, LocalServiceActivities.Controller.class), 0);// Set the info for the views that show in the notification panel.Notification notification = new Notification.Builder(this).setSmallIcon(R.drawable.stat_sample)  // the status icon.setTicker(text)  // the status text.setWhen(System.currentTimeMillis())  // the time stamp.setContentTitle(getText(R.string.local_service_label))  // the label of the entry.setContentText(text)  // the contents of the entry.setContentIntent(contentIntent)  // The intent to send when the entry is clicked.build();// Send the notification.mNM.notify(NOTIFICATION, notification);}
}

创建了一个service,在它的onCreate()方法中定义了一个通知,并且定义了一个内部类LocalBinder,返回service本身。

接着是绑定该service的代码,

private LocalService mBoundService;private ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className, IBinder service) {// This is called when the connection with the service has been// established, giving us the service object we can use to// interact with the service.  Because we have bound to a explicit// service that we know is running in our own process, we can// cast its IBinder to a concrete class and directly access it.mBoundService = ((LocalService.LocalBinder)service).getService();// Tell the user about this for our demo.Toast.makeText(Binding.this, R.string.local_service_connected,Toast.LENGTH_SHORT).show();}public void onServiceDisconnected(ComponentName className) {// This is called when the connection with the service has been// unexpectedly disconnected -- that is, its process crashed.// Because it is running in our same process, we should never// see this happen.mBoundService = null;Toast.makeText(Binding.this, R.string.local_service_disconnected,Toast.LENGTH_SHORT).show();}
};void doBindService() {// Establish a connection with the service.  We use an explicit// class name because we want a specific service implementation that// we know will be running in our own process (and thus won't be// supporting component replacement by other applications).bindService(new Intent(Binding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE);mIsBound = true;
}void doUnbindService() {if (mIsBound) {// Detach our existing connection.unbindService(mConnection);mIsBound = false;}
}@Override
protected void onDestroy() {super.onDestroy();doUnbindService();
}

绑定service以及解除绑定。

有两个地方需要注意:

1.onServiceDisconnected()什么时候调用?

 This is called when the connection with the service has been unexpectedly disconnected -- that is,its process crashed.Because it is running in our same process, we should never see this happen.

当被意外断开连接时service会调用该方法,也就是说,进程崩溃了。因为它运行在我们同一个进程中,我们应当永远不要看到这样的问题发生。

换句话说,就是当应用意外崩溃了,才导致service连接断开,才会调用该方法。正常情况下,该方法是不会被调用的。

2.绑定以及解绑的时候,加入标志。

Messenger的使用demo,

public class MessengerService extends Service {/** For showing and hiding our notification. */NotificationManager mNM;/** Keeps track of all current registered clients. */ArrayList<Messenger> mClients = new ArrayList<Messenger>();/** Holds last value set by a client. */int mValue = 0;/*** Command to the service to register a client, receiving callbacks* from the service.  The Message's replyTo field must be a Messenger of* the client where callbacks should be sent.*/static final int MSG_REGISTER_CLIENT = 1;/*** Command to the service to unregister a client, ot stop receiving callbacks* from the service.  The Message's replyTo field must be a Messenger of* the client as previously given with MSG_REGISTER_CLIENT.*/static final int MSG_UNREGISTER_CLIENT = 2;/*** Command to service to set a new value.  This can be sent to the* service to supply a new value, and will be sent by the service to* any registered clients with the new value.*/static final int MSG_SET_VALUE = 3;/*** Handler of incoming messages from clients.*/class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_REGISTER_CLIENT:mClients.add(msg.replyTo);break;case MSG_UNREGISTER_CLIENT:mClients.remove(msg.replyTo);break;case MSG_SET_VALUE:mValue = msg.arg1;for (int i=mClients.size()-1; i>=0; i--) {try {mClients.get(i).send(Message.obtain(null,MSG_SET_VALUE, mValue, 0));} catch (RemoteException e) {// The client is dead.  Remove it from the list;// we are going through the list from back to front// so this is safe to do inside the loop.mClients.remove(i);}}break;default:super.handleMessage(msg);}}}/*** Target we publish for clients to send messages to IncomingHandler.*/final Messenger mMessenger = new Messenger(new IncomingHandler());@Overridepublic void onCreate() {mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);// Display a notification about us starting.showNotification();}@Overridepublic void onDestroy() {// Cancel the persistent notification.mNM.cancel(R.string.remote_service_started);// Tell the user we stopped.Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();}/*** When binding to the service, we return an interface to our messenger* for sending messages to the service.*/@Overridepublic IBinder onBind(Intent intent) {return mMessenger.getBinder();}/*** Show a notification while this service is running.*/private void showNotification() {// In this sample, we'll use the same text for the ticker and the expanded notificationCharSequence text = getText(R.string.remote_service_started);// The PendingIntent to launch our activity if the user selects this notificationPendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, Controller.class), 0);// Set the info for the views that show in the notification panel.Notification notification = new Notification.Builder(this).setSmallIcon(R.drawable.stat_sample)  // the status icon.setTicker(text)  // the status text.setWhen(System.currentTimeMillis())  // the time stamp.setContentTitle(getText(R.string.local_service_label))  // the label of the entry.setContentText(text)  // the contents of the entry.setContentIntent(contentIntent)  // The intent to send when the entry is clicked.build();// Send the notification.// We use a string id because it is a unique number.  We use it later to cancel.mNM.notify(R.string.remote_service_started, notification);}
}
/** Messenger for communicating with service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mIsBound;
/** Some text view we are using to show state information. */
TextView mCallbackText;/*** Handler of incoming messages from service.*/
class IncomingHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MessengerService.MSG_SET_VALUE:mCallbackText.setText("Received from service: " + msg.arg1);break;default:super.handleMessage(msg);}}
}/*** Target we publish for clients to send messages to IncomingHandler.*/
final Messenger mMessenger = new Messenger(new IncomingHandler());/*** Class for interacting with the main interface of the service.*/
private ServiceConnection mConnection = new ServiceConnection() {public void onServiceConnected(ComponentName className,IBinder service) {// This is called when the connection with the service has been// established, giving us the service object we can use to// interact with the service.  We are communicating with our// service through an IDL interface, so get a client-side// representation of that from the raw service object.mService = new Messenger(service);mCallbackText.setText("Attached.");// We want to monitor the service for as long as we are// connected to it.try {Message msg = Message.obtain(null,MessengerService.MSG_REGISTER_CLIENT);msg.replyTo = mMessenger;mService.send(msg);// Give it some value as an example.msg = Message.obtain(null,MessengerService.MSG_SET_VALUE, this.hashCode(), 0);mService.send(msg);} catch (RemoteException e) {// In this case the service has crashed before we could even// do anything with it; we can count on soon being// disconnected (and then reconnected if it can be restarted)// so there is no need to do anything here.}// As part of the sample, tell the user what happened.Toast.makeText(Binding.this, R.string.remote_service_connected,Toast.LENGTH_SHORT).show();}public void onServiceDisconnected(ComponentName className) {// This is called when the connection with the service has been// unexpectedly disconnected -- that is, its process crashed.mService = null;mCallbackText.setText("Disconnected.");// As part of the sample, tell the user what happened.Toast.makeText(Binding.this, R.string.remote_service_disconnected,Toast.LENGTH_SHORT).show();}
};void doBindService() {// Establish a connection with the service.  We use an explicit// class name because there is no reason to be able to let other// applications replace our component.bindService(new Intent(Binding.this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);mIsBound = true;mCallbackText.setText("Binding.");
}void doUnbindService() {if (mIsBound) {// If we have received the service, and hence registered with// it, then now is the time to unregister.if (mService != null) {try {Message msg = Message.obtain(null,MessengerService.MSG_UNREGISTER_CLIENT);msg.replyTo = mMessenger;mService.send(msg);} catch (RemoteException e) {// There is nothing special we need to do if the service// has crashed.}}// Detach our existing connection.unbindService(mConnection);mIsBound = false;mCallbackText.setText("Unbinding.");}
}

通过Messenger可以实现IPC(跨进程访问),此处就不再多说了,有关Messenger,详情请看, Android IPC之Messenger浅谈。

三、小结。

我们大致可以得知,

1.Service是可以用来处理一些不需要和用户交互的任务,它没有界面,在后台运行,并且在它的内部如果需要执行耗时操作的话,需要开启子线程;

2.启动一个Service,可以使用Context.startService()和Context.bindService();

3.使用Service,可以实现IPC。

这篇文章只是翻译了官网有关Service的内容,下篇文章,将通过实例来说明Service的启动、声明状态等特征。详情,请查看Android Service(二) 使用。

推荐文章,Android Service(三) IntentService详解。

Android Service(一) Service初识相关推荐

  1. Android中的service全面总结

    文章出处:http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html 1.Service的种类 按运行地点分类: 类别 区别  优点 缺点 ...

  2. android notification 定时显示,Android编程使用Service实现Notification定时发送功能示例...

    本文实例讲述了android编程使用service实现notification定时发送功能.分享给大家供大家参考,具体如下: /** * 通过启动或停止服务来管理通知功能 * * @descripti ...

  3. Android之旅---Service

    Service介绍 首先让我们来假设这样一种情况:用户正在使用你的音乐播放器播放着优美的歌曲,突然用户听说日本现在9级地震了想去浏览器中看看相关的新闻.也就是说用户想边听音乐边看新闻.如果按照我们前面 ...

  4. 自动生成Android界面,面向Android的Web Service界面自动生成技术研究

    摘要: 据统计,开发人员在开发应用程序的过程中,接近一半的代码用于用户界面部分,大约一半的运行时间用于执行这一部分.所以,减少用户界面部分的开发代码和运行时间,能有效提高程序的运行效率.智能家居中,由 ...

  5. Android开发之Service与Activity数据交互(源代码分享)

    Service想要与Activity进行数据交互,首先Activity先得绑定Service.bound service是service 的实现,它允许其他应用程序绑定到它并与之交互.要提供bound ...

  6. Android 中的 Service 全面总结

    1.Service的种类   按运行地点分类: 类别 区别 优点 缺点 应用 本地服务(Local) 该服务依附在主进程上, 服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Loc ...

  7. Android 中的 Service 全面总结(转)

    转自:http://www.cnblogs.com/newcj/archive/2011/05/30/2061370.html# Android 中的 Service 全面总结 1.Service的种 ...

  8. Android学习笔记-Service

    * 1.Service是一个应用程序组件 * 2.Service没有图形化界面 * 3.Service通常用来处理一些耗时比较长的操作 * 4.可以使用Service更新ContentProvider ...

  9. 【Android开发日记】第一个任务Android Service!Service靴+重力感应器+弹出窗口+保持执行...

    前言: 近期在写一个小程序,需求是手机摇一摇就弹窗出来.第一次使用了Service,学习了两天,实现了Service弹窗,开机启动,Service启动和销毁,Service保持一直执行. 满足了自己的 ...

  10. android 组件(activity,service,content provider,broadcast receiver,intent)详解

    Android应用程序由若干个不同类型的组件组合而成,每一个组件具有其特定的安全保护设计方式,它们的安全直接影响到应用程序的安全.Android应用程序组件的主要类型有:活动(Activity),服务 ...

最新文章

  1. 整数阶贝塞尔函数c语言,第二类整数阶贝塞尔函数(诺伊曼函数)
  2. mysql的主从复制是如何实现的
  3. 第十五次发博不知道用什么标题好
  4. jar 包又冲突了?如何快速确定与哪个 jar 包冲突?
  5. DataURL:实现原理及优缺点分析
  6. Java网络编程从入门到精通(21):HTTP消息的格式
  7. UML介绍--用例图
  8. ZK 6中的MVVM初探
  9. 标记偏见_分析师的偏见
  10. 获取Class对象方式
  11. Python编程进阶,Python如何实现多进程?
  12. 两个简单的Demo示例向读者展示Flash和ASP.NET交互原理以及过程
  13. 自学it18大数据笔记-第二阶段Hive-day4——会持续更新……
  14. [poj] 1235 Farm Tour || 最小费用最大流
  15. Playmaker节点工具使用(二)—Odin绘制支持
  16. 法宝合成时的五行位置分配是什么
  17. Hibernate 的检索策略
  18. 大数据分析服务器硬件配置如何选择
  19. 解决Matplotlib中Times New Roman字体无法改变字体
  20. Tekla structures深入定制开发篇(一)

热门文章

  1. java设计九宫格拼图软件哪个好用_十亿人都在拼的拼图软件,这八款最好用
  2. 智能体重秤方案/案列/APP/小程序
  3. 两年多工作心得和体会
  4. iphone计算机的声音怎么办,苹果耳机插电脑上没声音怎么办_苹果耳机插win10电脑没声音如何解决-win7之家...
  5. wifidog 配置中文说明
  6. paired-end reads的拼接
  7. OHS简单安装与系统配置
  8. python报错(一):takes no arguments
  9. 初始化失败_Destroying singletons
  10. Java实现在图片上添加文字(水印)