作为 Android四大组件之一, 服务也少不了有很多非常重要的知识点,那自然要从最基本的用法开始学习了。

定义一个服务

public class MyService extends Service {/*** onBind是继承Service后唯一的一个抽象方法所以必须要重写的一个方法*/@Overridepublic IBinder onBind(Intent intent) {return null;}/*** 服务每次启动的时候调用*/@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i("MyService", "onStartCommand");return super.onStartCommand(intent, flags, startId);}/*** 在服务创建的时候调用*/@Overridepublic void onCreate() {Log.i("MyService", "onCreate");super.onCreate();}/*** 会在服务销毁的时候调用*/@Overridepublic void onDestroy() {Log.i("MyService", "onDestroy");super.onDestroy();}

启动和停止服务

public class MyServiceActivity extends Activity{@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.androidservice_activity);Button start=(Button) findViewById(R.id.start);start.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(MyServiceActivity.this,MyService.class);startService(intent);//启动服务}});Button stop=(Button) findViewById(R.id.stop);stop.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(MyServiceActivity.this,MyService.class);stopService(intent);//停止服务}});}
}

注意,这里完全是由活动来决定服务何时停止的,如果没有点击Stop Service 按钮, 服务就会一直处于运行状态。 那服务有没有什么办法让自已停止下来呢?当然可以, 只需要在 MyService 的任何一个位置调用 stopSelf()方法就能让这个服务停止下来了。

我们可以看到Logcat打印的信息:

点击start服务成功启动,点击stop然后成功销毁, 运行成功后可以在正在运行的应用列表当中找到这个应用,停止掉之后就找不到了:

已经学会了启动服务以及停止服务的方法,不知道你心里现在有没有一个疑惑,那就是 onCreate()方法和 onStartCommand()到底有什么区别呢?因为刚刚点击Start Service按钮后两个方法都执行了。其实 onCreate()方法是在服务第一次创建的时候调用的,而 onStartCommand()方法则在每次启动服务的时候都会调用,由于刚才我们是第一次点击 Start Service 按钮,服务此时还未创建过,所以两个方法都会执行,之后如果你再连续多点击几次 Start Service 按钮,你就会发现只有 onStartCommand()方法可以得到执行了。

活动和服务进行通信

我们在活动里调用了 startService()方法来启动 MyService这个服务,然后 MyService的 onCreate()和onStartCommand()方法就会得到执行。之后服务会一直处于运行状态,但具体运行的是什么逻辑,活动控制不了了。这就类似于活动通知了服务一下: “你可以启动了! ”然后服务就去忙自己的事情了,但活动并不知道服务到底去做了什么事情,以及完成的如何。那么有没有什么办法能让活动和服务的关系更紧密一些呢?例如在活动中指挥服务去干什么,服务就去干什么。当然可以,这就需要借助我们刚刚忽略的 onBind()方法了。
比如说目前我们希望在 MyService里提供一个下载功能,然后在活动中可以决定何时开始下载, 以及随时查看下载进度。 实现这个功能的思路是创建一个专门的 Binder对象来对下载功能进行管理,修改 MyService中的代码,如下所示:

public class MyService extends Service {/*** 创建binder对象*/DownLoadBind bind = new DownLoadBind();class DownLoadBind extends Binder {/*** 一个开始下载的方法*/public void startDownload() { Log.i("DownLoadBind", "startDownload");}/*** 一个获取进度的方法* @return*/public int getProgress() {Log.i("DownLoadBind", "getProgress");return 0;}}/*** onBind是继承Service后唯一的一个抽象方法所以必须要重写的一个方法* 该方法是为了服务可以与服务进行通信,例如在活动中指挥服务去干什么,服务就去干什么* 返回binder对象*/@Overridepublic IBinder onBind(Intent intent) {return bind;}/*** 服务每次启动的时候调用*/@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i("MyService", "onStartCommand");return super.onStartCommand(intent, flags, startId);}/*** 在服务创建的时候调用*/@Overridepublic void onCreate() {Log.i("MyService", "onCreate");super.onCreate();}/*** 会在服务销毁的时候调用*/@Overridepublic void onDestroy() {Log.i("MyService", "onDestroy");super.onDestroy();}

接下来看下MyServiceActivity中的代码,在MyServiceActivity新增了两个按钮

public class MyServiceActivity extends Activity{private MyService.DownLoadBind down;/*** 创建ServiceConnection的匿名内部类并重写两个方法*/private ServiceConnection connection=new ServiceConnection() {/*** 在与服务解除绑定的时候调用*/@Overridepublic void onServiceDisconnected(ComponentName name) {}/*** 绑定成功的时候调用*/@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {down=(DownLoadBind) service;//通过向下转型得到DownLoadBind的实例有了这个实例活动与服务的关系就变得非常紧密了down.startDownload();down.getProgress();}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.androidservice_activity);Button start=(Button) findViewById(R.id.start);start.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {Intent intent=new Intent(MyServiceActivity.this,MyService.class);startService(intent);//开始服务}});Button stop=(Button) findViewById(R.id.stop);stop.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(MyServiceActivity.this,MyService.class);stopService(intent);//停止服务}});Button bind=(Button) findViewById(R.id.BindService);bind.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(MyServiceActivity.this,MyService.class);/*** 第一个参数刚刚构建出的 Intent对象  第二个参数前面创建出的 ServiceConnection的实例,第三个则是一个标志位* 这里传入 BIND_AUTO_CREATE 表示在活动和服务进行绑定后自动创建服务。这会使得 * MyService 中的 onCreate()方法得到执行,但 onStartCommand()方法不会执行。*/bindService(intent, connection, BIND_AUTO_CREATE);//绑定服务}});Button unbind=(Button) findViewById(R.id.UnbindService);unbind.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {unbindService(connection);//解绑服务点击了就会服务就会停止运行}});}
}

到此为止activity可以调用服务当中任何public方法。实现了在活动当中去控制服务当中的方法,想让服务干嘛就干嘛。
运行下程序:

Logcat当中可以看到成功运行服务当中的两个方法以及onCreate方法。另外需要注意,任何一个服务在整个应用程序范围内都是通用的,即 MyService不仅可以和 MainActivity 绑定,还可以和任何一个其他的活动进行绑定,而且在绑定完成后它们都可以获取到相同的 DownloadBinder实例。

服务的生命周期

学习过了活动以及碎片的生命周期。类似地,服务也有自己的生命周期,前面我们使用到的

onCreate()、onStartCommand()、onBind()和 onDestroy()等方法都是在服务的生命周期内可能回调的方法。一旦在项目的任何位置调用了 Context 的startService()方法,相应的服务就会启动起来,并回调 onStartCommand()方法。

如果这个服务之前还没有创建过,onCreate()方法会先于onStartCommand()方法执行。服务启动了之后会一直保持运行状态,直到stopService()或stopSelf()方法被调用。注意虽然每调用一次 startService()方法,onStartCommand()就会执行一次, 但实际上每个服务都只会存在一个实例。

所以不管你调用了多少次 startService()方法,只需调用一次 stopService()或stopSelf()方法,服务就会停止下来了。另外,还可以调用 Context 的bindService()来获取一个服务的持久连接,这时就会回调服务中的onBind()方法

类似地,如果这个服务之前还没有创建过,onCreate()方法会先于onBind()方法执行。之后,调用方可以获取到onBind()方法里返回的 IBinder对象的实例,这样就能自由地和服务进行通信了。只要调用方和服务之间的连接没有断开,服务就会一直保持运行状态。当调用了 startService()方法后,又去调用 stopService()方法

这时服务中的 onDestroy()方法就会执行,表示服务已经销毁了。类似地,当调用了 bindService()方法后,又去调用unbindService()方法,
onDestroy()方法也会执行,这两种情况都很好理解。但是需要注意,我们是完全有可能对一个服务既调用了 startService()方法,又调用了 bindService()方法的,

这种情况下该如何才能让服务销毁掉呢?根据 Android系统的机制,一个服务只要被启动或 者被绑定了之后,就会一直处于运行状态,必须要让以上两种条件同时不满足,服务才能被 销毁。所以,这种情况下要同时调用stopService()和 unbindService()方法,onDestroy()方法才 会执行。

这样你就已经把服务的生命周期完整地走了一遍。

使用 IntentService

服务中的代码都是默认运行在主线程当中的,如果直接在服务里去处理一些耗时的逻辑,就很容易出现 ANR(Application NotResponding)的情况。所以这个时候就需要用到 Android多线程编程的技术了,我们应该在服务的每个具体的方法里开启一个子线程,然后在这里去处理那些耗时的逻辑。因此,一个比较标准的服务就可以写成如下形式:

public class MyService extends Service {@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}

虽说这种写法并不复杂, 但是总会有一些程序员忘记开启线程, 或者忘记调用 stopSelf()
方法。为了可以简单地创建一个异步的、会自动停止的服务,Android 专门提供了一个
IntentService 类,这个类就很好地解决了前面所提到的两种尴尬,下面我们就来看一下它的
用法。

public class MyIntentService extends IntentService{/*** 调用父类的有构造函数* @param name*/public MyIntentService() {super("MyIntentService");}/*** 这个方法可以去处理一些具体的逻辑问题,不用担心ARN问题* 这个方法已经是在子线程中运行的了*/@Overrideprotected void onHandleIntent(Intent intent) {// 打印当前线程的idLog.d("MyIntentService", "子线程ID" + Thread.currentThread().getId());}/*** 在创建服务后是会自动停止的*/@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();Log.i("MyIntentService", "onDestroy");}
}

在MyServiceActivity新增一个按钮分别打印子线程ID以及主线程ID

Button startintent=(Button) findViewById(R.id.startintent);startintent.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Log.i("MyServiceActivity", "主线程ID"+Thread.currentThread().getId());Intent intent=new Intent(MyServiceActivity.this,MyIntentService.class);startService(intent);}});

运行程序:Logcat打印信息:

可以看到, 不仅 MyIntentService和 MainActivity 所在的线程 id 不一样, 而且 onDestroy()方法也得到了执行, 说明 MyIntentService在运行完毕后确实自动停止了。 集开启线程和自动停止于一身IntentService 还是博得了不少程序员的喜爱。

后台执行的定时任务

下面我们就来创建一个可以长期在后台执行定时任务的服务。Android中的定时任务一般有两种实现方式,一种是使用 Java API 里提供的 Timer 类,一种是使用 Android的 Alarm机制。我们来看看Alarm机制。

public class LongRunningService extends Service{@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {new Thread(new Runnable() {@Overridepublic void run() {//打印时间信息Log.d("LongRunningService", "executed at " + new Date().toString());}}).start();AlarmManager manager=(AlarmManager) getSystemService(ALARM_SERVICE);int hour=3000;//每隔三秒刷新一次/*** 使用 SystemClock.elapsedRealtime()方法可以获取到系统开机至今所经历时间的毫秒数,* 使用 System.currentTimeMillis()方法可以获取到 1970年 1 月 1日 0点至今所经历时间的毫秒数。*/long triggerAtTime = SystemClock.elapsedRealtime() + hour;Intent i = new Intent(this, AlarmReceiver.class);PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);/*** set第一个参数整型参数,用于指定 AlarmManager的工作类型,有四种值可选* ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC 和 RTC_WAKEUP* ELAPSED_REALTIME: 表示让定时任务的触发时间从系统开机开始算起,但不会唤醒 CPU* ELAPSED_REALTIME_WAKEUP: 同样表示让定时任务的触发时间从系统开机开始算起,但会唤醒 CPU* RTC:表示让定时任务的触发时间从 1970 年 1月 1 日 0点开始算起,但不会唤醒 CPU* RTC_WAKEUP: 同样表示让定时任务的触发时间从1970 年 1 月 1 日 0 点开始算起,但会唤醒 CPU* * 第二个参数表示就是定时任务触发的时间,以毫秒为单位。* 如果第一个参数使用的是 ELAPSED_REALTIME或 ELAPSED_REALTIME_WAKEUP,* 则这里传入开机至今的时间再加上延迟执行的时间。如果第一个参数使用的是 RTC 或RTC_WAKEUP,* 则这里传入 1970年 1月 1日 0点至今的时间再加上延迟执行的时间。* * 第三个参数是一个 PendingIntent,这里我们一般会调用 getBroadcast()方法来获取一个能够执行广播的 PendingIntent。 * 这样当定时任务被触发的时候,广播接收器的 onReceive()方法就可以得到执行。*/manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);return super.onStartCommand(intent, flags, startId);}}

MyServiceActivity:

Button button=(Button) findViewById(R.id.startAlarm);button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(MyServiceActivity.this,LongRunningService.class);startService(intent);}});

AlarmReceiver :

public class AlarmReceiver extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {Intent intent2=new Intent(context,LongRunningService.class);context.startService(intent2);}}

onReceive()方法里的代码非常简单,就是构建出了一个 Intent 对象,然后去启动LongRunningService 这个服务。那么这里为什么要这样写呢?其实在不知不觉中,这就已经将一个长期在后台定时运行的服务完成了。因为一旦启动 LongRunningService,就会在onStartCommand()方法里设定一个定时任务,这样一小时后 AlarmReceiver 的 onReceive()方法就将得到执行,然后我们在这里再次启动 LongRunningService,这样就形成了一个永久的循环,保证 LongRunningService 可以每隔一段时间就会启动一次,一个长期在后台定时运行的服务自然也就完成了。

最后别忘了在AndroidManifest.xml注册

运行:
Logcat打印信息:

可以看到程序已经成功运行了,每隔3秒钟刷新一次时间。实际运用当中可以把LOG信息换成逻辑即可。

最后来看一个利用服务Service,Handler多线程异步处理机制,HttpURLConnection,写的一个通知栏版本升级的例子:

public class UpdateService extends Service {public static final String Install_Apk = "Install_Apk";/******** download progress step *********/private static final int down_step_custom = 3;private static final int TIMEOUT = 10 * 1000;// 超时private static String down_url;private static final int DOWN_OK = 1;private static final int DOWN_ERROR = 0;private String app_name;private NotificationManager notificationManager;private Notification notification;private Intent updateIntent;private PendingIntent pendingIntent;private RemoteViews contentView;@Overridepublic IBinder onBind(Intent intent) {// TODO Auto-generated method stubreturn null;}/*** 方法描述:onStartCommand方法* * @param Intent*            intent, int flags, int startId* @return int* @see UpdateService*/@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {app_name = intent.getStringExtra("Key_App_Name");down_url = intent.getStringExtra("Key_Down_Url");//create file,应该在这个地方加一个返回值的判断SD卡是否准备好,文件是否创建成功,等等!FileUtil.createFile(app_name);if (FileUtil.isCreateFileSucess == true) {createNotification();createThread();} else {Toast.makeText(this, R.string.insert_card, Toast.LENGTH_SHORT).show();/*************** stop service ************/stopSelf();}return super.onStartCommand(intent, flags, startId);}/********* update UI ******/private final Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {switch (msg.what){case DOWN_OK:/********* 下载完成,点击安装 ***********/Uri uri = Uri.fromFile(FileUtil.updateFile);Intent intent = new Intent(Intent.ACTION_VIEW);intent.setDataAndType(uri, "application/vnd.android.package-archive");pendingIntent = PendingIntent.getActivity(UpdateService.this, 0, intent, 0);notification.flags = Notification.FLAG_AUTO_CANCEL;notification.setLatestEventInfo(UpdateService.this, app_name, getString(R.string.down_sucess),pendingIntent);// notification.setLatestEventInfo(UpdateService.this,app_name,// app_name + getString(R.string.down_sucess), null);notificationManager.notify(R.layout.notification_item, notification);/***** 安装APK ******/// installApk();// stopService(updateIntent);/*** stop service *****/stopSelf();break;case DOWN_ERROR:notification.flags = Notification.FLAG_AUTO_CANCEL;// notification.setLatestEventInfo(UpdateService.this,app_name,// getString(R.string.down_fail), pendingIntent);notification.setLatestEventInfo(UpdateService.this, app_name, getString(R.string.down_fail), null);/*** stop service *****/// onDestroy();stopSelf();break;default:// stopService(updateIntent);/****** Stop service ******/// stopService(intentname)// stopSelf();break;}}};private void installApk() {// TODO Auto-generated method stub/********* 下载完成,点击安装 ***********/Uri uri = Uri.fromFile(FileUtil.updateFile);Intent intent = new Intent(Intent.ACTION_VIEW);/*********** 加这个属性是因为使用Context的startActivity方法的话,就需要开启一个新的task**********/intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setDataAndType(uri, "application/vnd.android.package-archive");UpdateService.this.startActivity(intent);}/*** 方法描述:createThread方法, 开线程下载* * @param* @return* @see UpdateService*/public void createThread() {new DownLoadThread().start();}private class DownLoadThread extends Thread {@Overridepublic void run() {// TODO Auto-generated method stubMessage message = new Message();try {long downloadSize = downloadUpdateFile(down_url, FileUtil.updateFile.toString());if (downloadSize > 0) {// down successmessage.what = DOWN_OK;handler.sendMessage(message);}} catch (Exception e) {e.printStackTrace();message.what = DOWN_ERROR;handler.sendMessage(message);}}}/*** 方法描述:createNotification方法* * @param* @return* @see UpdateService*/public void createNotification() {/*** 定义一个前台服务*/// notification = new Notification(R.drawable.dot_enable,app_name +// getString(R.string.is_downing) ,System.currentTimeMillis());notification = new Notification(// R.drawable.video_player,//应用的图标R.drawable.icon, // 应用的图标app_name + getString(R.string.is_downing), System.currentTimeMillis());notification.flags = Notification.FLAG_ONGOING_EVENT;// notification.flags = Notification.FLAG_AUTO_CANCEL;/*** 自定义 Notification 的显示 ****/contentView = new RemoteViews(getPackageName(), R.layout.notification_item);contentView.setTextViewText(R.id.notificationTitle, app_name + getString(R.string.is_downing));contentView.setTextViewText(R.id.notificationPercent, "0%");contentView.setProgressBar(R.id.notificationProgress, 100, 0, false);notification.contentView = contentView;// updateIntent = new Intent(this, AboutActivity.class);// updateIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);// //updateIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);// pendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0);// notification.contentIntent = pendingIntent;notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.notify(R.layout.notification_item, notification);}/**** down file* * @return* @throws MalformedURLException*/public long downloadUpdateFile(String down_url, String file) throws Exception {int down_step = down_step_custom;// 提示stepint totalSize;// 文件总大小int downloadCount = 0;// 已经下载好的大小int updateCount = 0;// 已经上传的文件大小InputStream inputStream;OutputStream outputStream;URL url = new URL(down_url);HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setConnectTimeout(TIMEOUT);httpURLConnection.setReadTimeout(TIMEOUT);// 获取下载文件的sizetotalSize = httpURLConnection.getContentLength();if (httpURLConnection.getResponseCode() == 404) {throw new Exception("fail!");// 这个地方应该加一个下载失败的处理,但是,因为我们在外面加了一个try---catch,已经处理了Exception,// 所以不用处理}inputStream = httpURLConnection.getInputStream();outputStream = new FileOutputStream(file, false);// 文件存在则覆盖掉byte buffer[] = new byte[1024];int readsize = 0;while ((readsize = inputStream.read(buffer)) != -1) {// /*********如果下载过程中出现错误,就弹出错误提示,并且把notificationManager取消*********/// if (httpURLConnection.getResponseCode() == 404) {// notificationManager.cancel(R.layout.notification_item);// throw new Exception("fail!");// //这个地方应该加一个下载失败的处理,但是,因为我们在外面加了一个try---catch,已经处理了Exception,// //所以不用处理// }outputStream.write(buffer, 0, readsize);downloadCount += readsize;// 时时获取下载到的大小/*** 每次增张3% **/if (updateCount == 0 || (downloadCount * 100 / totalSize - down_step) >= updateCount) {updateCount += down_step;// 改变通知栏contentView.setTextViewText(R.id.notificationPercent, updateCount + "%");contentView.setProgressBar(R.id.notificationProgress, 100, updateCount, false);notification.contentView = contentView;notificationManager.notify(R.layout.notification_item, notification);}}if (httpURLConnection != null) {httpURLConnection.disconnect();}inputStream.close();outputStream.close();return downloadCount;}
}
public class FileUtil {public static File updateDir = null;public static File updateFile = null;/***********保存升级APK的目录***********/public static final String KonkaApplication = "konkaUpdateApplication";public static boolean isCreateFileSucess;/** * 方法描述:createFile方法* @param   String app_name* @return * @see FileUtil*/public static void createFile(String app_name) {if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState())) {isCreateFileSucess = true;updateDir = new File(Environment.getExternalStorageDirectory()+ "/" + KonkaApplication +"/");updateFile = new File(updateDir + "/" + app_name + ".apk");if (!updateDir.exists()) {updateDir.mkdirs();}if (!updateFile.exists()) {try {updateFile.createNewFile();} catch (IOException e) {isCreateFileSucess = false;e.printStackTrace();}}}else{isCreateFileSucess = false;}}
}

Activity:

// 点击更新update.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(context,UpdateService.class);intent.putExtra("Key_App_Name",appName);intent.putExtra("Key_Down_Url",appUrl);         startService(intent);popupWindow.dismiss();}});

服务Service的基本用法相关推荐

  1. linux 进程间通信 dbus-glib【实例】详解三 数据类型和dteeth(类型签名type域)(层级结构:服务Service --> Node(对象、object) 等 )(附代码)

    linux 进程间通信 dbus-glib[实例]详解一(附代码)(d-feet工具使用) linux 进程间通信 dbus-glib[实例]详解二(上) 消息和消息总线(附代码) linux 进程间 ...

  2. 安卓服务Service详解

    service(服务)是安卓中的四大组件之一,它通常用作在后台处理耗时的逻辑,与Activity一样,它存在自己的生命周期,也需要在清单文件中配置相关信息,本博客将对Service的各个知识点进行详细 ...

  3. android打开位置服务,Android - 位置定位(Location)服务(Service)类的基本操作

    位置定位(Location)服务(Service)类的基本操作 本文地址: http://blog.csdn.net/caroline_wendy 定位服务(Location Service),能够确 ...

  4. Windows服务(Service)安装及启动停止方案

    目录 一.创作背景 二.问题解决 2.1 安装Windows service服务 2.2 主方法Main()主方法改写 2.3 安装service服务/卸载service服务 2.4 服务启停 2.5 ...

  5. 开机启动一个服务Service,启动后没有界面后台暗暗运行

    原文来自:http://blog.163.com/shaocpa@126/blog/static/553577572012418103732417/ 如果开机启动一个Activity,开机首先看的界面 ...

  6. ubuntu启动、关闭、重启服务service命令

    查看当前所有服务 service --status-all 结果如下: zwl@zwl-NB50TJ1-TK1:~$ service --status-all[ + ] acpid[ - ] alsa ...

  7. android创建标题栏,【Android】利用服务Service创建标题栏通知

    创建标题栏通知的核心代码 public void CreateInform() { //定义一个PendingIntent,当用户点击通知时,跳转到某个Activity(也可以发送广播等) Inten ...

  8. [云原生专题-33]:K8S - 核心概念 - 服务Service管理、服务发现、负载均衡

    作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客 本文网址:https://blog.csdn.net/HiWangWenBing/article/detai ...

  9. ROS基础(二):ros通讯之服务(service)机制

    上一章内容链接: ROS基础(一):ROS通讯之话题(topic)通讯 目录 一.概念 二.实例 1. 小乌龟例程中的service 2. 自定义service 3. 创建服务器节点与客户端节点(c+ ...

最新文章

  1. 2021-08-02 json文件批量转化mask,生成train.txt路径make_path.py
  2. SMTP 通过 ssh 通道发送垃圾邮件
  3. java 连接池连接mysql数据库需要哪些jar包_DBCP-基于Java8导入DBCP连接池所需JAR包并编写DBCPUtils工具类...
  4. Everyday is an Opportunity
  5. 一个基于Tp3.2(thinkphp3.2)的工会管理系统
  6. android 计步功能原理,Android开发——计步功能
  7. 易优EyouCMS全套插件使用说明
  8. movs 数据传送指令_数据传送指令之:MOV指令
  9. Windows驱动开发入门指引
  10. VMware ESXi 与ESX 产品之比较
  11. hive错误FAILED: SemanticException [Error 10041]: No partition predicate found for
  12. Apache Hadoop大数据集群及相关生态组件安装
  13. PHP为什么会被认为是草根语言?
  14. 都2021年了,你不会还没掌握响应式网页设计吧?
  15. MyCms 自媒体 CMS 系统 v3.1.0,新增商城接口
  16. 【密码学】费马小定理素性检测(C++代码实现)
  17. 解析光纤跳线的5大知识点,让安装使用更顺畅
  18. 年后跳槽如何准备?(前端方向)
  19. GraphX与GraphLab、Pregel的对比
  20. 云管理平台是个什么东西

热门文章

  1. 计算机办公软件实际操作题,办公软件的实操考试
  2. 微信小程序(一):微信小程序申请注册与开发流程
  3. 2023超级3D动画渲染工具——key shot“底纹云渲染”
  4. 全志A64的Android PC --Remix Mini
  5. “贴纸”型可穿戴传感器诞生,中美科学家联合研发,可远程监控健康风险-1
  6. ANNOVAR region-based annotation-上篇
  7. AWStats简介:Apache/Windows IIS的日志分析工具的下载,安装,配置样例和使用(含6.9中文定义补丁)
  8. CV | 矩形度的计算(python)
  9. matlab对服务器性能要求,服务器运行matlab
  10. fusion app远程公告(微云)