热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android_Service(2)前台服务(service)和远程服务(service)

一、前台服务service基本都是在后台进行运行的,一直都是在默默地工作,不爱表现自己(没有界面),可是这样一个基层的工作人员(service)在android系统的待遇(优先级)还是比

一、前台服务

       service基本都是在后台进行运行的,一直都是在默默地工作,不爱表现自己(没有界面),可是这样一个基层的工作人员(service)在android系统的待遇(优先级)还是比较差的,在系统内存不足的情况下,就有可能回收掉正在后台运行的service,因此service就会停止运行。如果希望service一直保持运行,不因系统内存不足而回收,该怎么做呢?可以先考虑使用前台service,前台service和普通service的区别在于,前台service一直有一个正在运行的图标在系统的状态栏中显示。但有一点要注意的是使用前台service不代表service不能被杀死,在应用程序管理那里可以停止前台service,状态栏通知被删除了也能解除service!
       那前台service有什么可以用来干什么呢?通常来说,一个音乐的播放器可以设置前台service,在状态栏中可以显示播放的歌曲相关的信息并可以作为启动按钮,打开音乐播放器,而且用户也是明确知道音乐播放器在运行的。还有天气相关的app也可以用前台service,在状态栏中实时同步更新的天气信息。

       那么我们先来看看前台service的效果吧:


       效果图可以看到前台service的界面,基本和一个通知信息界面差不多,然后点击停止前台service,状态栏的图标就消失了!此时前台service也就关闭了!当然用户想要停止前台service,也跟普通service一样,可以在程序管理器那里进行停止,具体看下面的效果图!


       看完效果图,我们来看下代码的实现,其实基本跟普通的service差不多,就是多了需要调用startForeground()方法,这个方法需要两个参数:一个唯一标识通知的整数和给状态栏的通知!如果需要删除前台service需要调用stopForeground()方法!

主界面的代码:

package com.liangdianshui.service2;

import com.example.service2.R;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

private Button mBtStartFrontService;
private Button mBtStopFrontService;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();
}

private void initView() {
mBtStartFrOntService= (Button) findViewById(R.id.bt_start_front_server);
mBtStopFrOntService= (Button) findViewById(R.id.bt_stop_front_server);
mBtStartFrontService.setOnClickListener(this);
mBtStopFrontService.setOnClickListener(this);
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent2 = new Intent(MainActivity.this, MyService2.class);
switch (v.getId()) {
case R.id.bt_start_front_server:
startService(intent2);
break;
case R.id.bt_stop_front_server:
stopService(intent2);
break;
}
}

}
Service类的代码:

package com.liangdianshui.service2;

import com.example.service2.R;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyService2 extends Service {

private static final String TAG = MyService2.class.getSimpleName();

private MyBinder mBinder = new MyBinder();

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.i(TAG, "onCreate");
frontService();
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.i(TAG, "onDestroy");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}

class MyBinder extends Binder {

public void toDo() {
Log.i(TAG, "toDo");
}
}

/**
* 前台服务
*/
private void frontService() {
Notification notification = new Notification(R.drawable.ic_launcher,
"Notification", System.currentTimeMillis());
Intent notificatiOnIntent= new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification
.setLatestEventInfo(this, "Title", "Content", pendingIntent);
startForeground(1, notification);
Log.d(TAG, "onCreate() executed");
}
}
       最后记得跟普通service一样,在配置文件中声明!

       Demo的下载地址:http://download.csdn.net/detail/two_water/9591717

      因为电脑有加密系统,所以只要把上面的类复制到对应的java文件就可以运行了。

二、远程服务
       说到远程服务(remote service),我们怎么创建远程servie呢?
       其实在普通的service基础上,我们只要在配置文件中注册Service的时候将它的android:process属性指定成:remote就可以了!
       注意:remote前面是有个冒号的!如下图:

       之后我们了解下Activity怎么和远程service进行通信?为什么要了解这个呢?难道远程服务不能像普通服务那样和Activity那样进行通信吗?
       其实远程服务跟启动远程服务的程序不是同一个进程的,而且他们的包名也是不一样的!(后面运行Demo的时候,看效果图,打印的log信息可以看到他们进程ID号不同,包名不同,具体在后面验证)
       在Android中, 每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢? 显然, Java中是不支持跨进程内存共享的。因此要传递对象, 需要把对象解析成操作系统能够理解的数据格式, 以达到跨界对象访问的目的。在JavaEE中,采用RMI通过序列化传递对象。在Android中, 则采用AIDL(Android Interface Definition Language:接口描述语言)方式实现。
那么什么是AIDL呢?
       AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。AIDL的IPC 机制和EJB所采用的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应 的对象。由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员 来说是透明的。
那么具体我们是怎么操作的呢?
  (1)在工程的src下,新建立一个文本文件,将要实现的函数放在这个文件中,后缀为.aidl。(主要是一个接口,定义方法)
  (2)刷新工程后,就会发现在gen包下,有一个同名的java文件,这是aidl工具自动生成的,里面,就有我们要实现的函数。
  (3)Aidl定义好后,我们就要实现我们的remote service了。它也是继承自service的。
  (4)Service实现后,要将它在mainfest.xml设置为remote.注意,客户端服务端在同个App中,android:process=":remote",代表在应用程序里,当需要该service时,会自动创建新的进程。而如果是android:process="remote",没有“:”分号的,则创建全局进程,不同的应用程序共享该进程。
  (5)最后,来实现我们的客户端,也就是Activity,来调用service。
       最后,我们来看下代码:
       首先需要新建一个AIDL文件,在这个文件中定义好Activity需要与Service进行通信的方法。新建MyAIDL.aidl文件,代码如下所示:
package com.liangdianshui.service3;

interface MyAIDL {
String combineString(String str1,String str2);
int countChar(String str);
}
       在服务类中,通过MyAIDL.Stub来实现MyAIDL.aidl中的两个方法,然后在onBind()方法中将MyAIDLService.Stub的实现返回,其他的跟普通service差不多!因为Stub其实就是Binder的子类,所以在onBind()方法中可以直接返回Stub的实现。
package com.liangdianshui.service3;

import com.liangdianshui.service3.MyAIDL.Stub;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;

public class MyService3 extends Service {

private static final String TAG = MyService3.class.getSimpleName();

MyAIDL.Stub mBinder = new Stub() {

@Override
public String combineString(String str1, String str2)
throws RemoteException {
// TODO Auto-generated method stub
return str1 + str2;
}

@Override
public int countChar(String str) throws RemoteException {
// TODO Auto-generated method stub
return str.length();
}

};

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mBinder;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.i(TAG, "onCreate");
Log.i(TAG, "MyService3 process ID:" + Process.myPid());
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.i(TAG, "onDestroy");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.i(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}

}
       在MainActivity中,ServiceConnection中的代码。可以看到,这里首先使用了MyAIDLService.Stub.asInterface()方法将传入的IBinder对象传换成了MyAIDLService对象,接下来就可以调用在MyAIDLService.aidl文件中定义的所有接口!
package com.liangdianshui.service3;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

private final static String TAG = MainActivity.class.getSimpleName();

private Button mBtStartRemoteService;
private Button mBtStopRemoteService;
private Button mBtBindRemoteService;
private Button mBtUnbindRemoteService;

private MyAIDL mAIDL;

private ServiceConnection mCOnnection= new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mAIDL = MyAIDL.Stub.asInterface(service);
try {
int result = mAIDL.countChar("liangdianshui");
String str = mAIDL.combineString("liangdianshui", "hello");
Log.d(TAG, "countChar: " + result);
Log.d(TAG, "combineString : " + str);
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

initView();

Log.i(TAG, "MainActivity process ID:" + Process.myPid());
}

private void initView() {
// TODO Auto-generated method stub
mBtStartRemoteService = (Button) findViewById(R.id.bt_start_remote_server);
mBtStopRemoteService = (Button) findViewById(R.id.bt_stop_remote_server);
mBtBindRemoteService = (Button) findViewById(R.id.bt_bind_remote_server);
mBtUnbindRemoteService = (Button) findViewById(R.id.bt_unbind_remote_server);
mBtStartRemoteService.setOnClickListener(this);
mBtStopRemoteService.setOnClickListener(this);
mBtBindRemoteService.setOnClickListener(this);
mBtUnbindRemoteService.setOnClickListener(this);
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent3 = new Intent(MainActivity.this, MyService3.class);
switch (v.getId()) {
case R.id.bt_start_remote_server:
startService(intent3);
break;
case R.id.bt_stop_remote_server:
//点击后会发现不能停止远程service,因为远程service和本程序不在同一个进程
stopService(intent3);
break;
case R.id.bt_bind_remote_server:
bindService(intent3, mConnection, BIND_AUTO_CREATE);
break;
case R.id.bt_unbind_remote_server:
unbindService(mConnection);
break;
}
}

}
       运行我们的程序,并点击“开启远程Server”,看下打印出来的Log:
       不难发现,它们的进程ID不同了,而且包名也是不一样的,包名后面还跟上了:remote标识。

       其实远程service跟普通service开启和关闭基本是一样的,就是绑定服务那里不同,因为是建立在不同进程间的通信!那我们来看下绑定远程服务和解绑的效果图吧:


       可以看出,打印出来的log信息,把远程服务的方法的结果打印出来了!


        Demo的下载地址:http://download.csdn.net/detail/two_water/9592054

           因为电脑有加密系统,所以只要把上面的类复制到对应的java文件就可以运行了。



推荐阅读
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • (三)多表代码生成的实现方法
    本文介绍了一种实现多表代码生成的方法,使用了java代码和org.jeecg框架中的相关类和接口。通过设置主表配置,可以生成父子表的数据模型。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
author-avatar
liu100897
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有