Service的详情使用

什么是Service,启动Service的三种方式,如何利用AIDL实现跨进程(APP)访问Service

Service 组件

1.Service 是什么

  • Service 是Android 中的一个应用组件?(生命周期方法)
  • Service 是Android 中的一个后台服务?(可以长时间运行于后台)

2.为什么启动Service执行耗时操作而不在activity启工作线程执行耗时操作呢?
因为当activity工作于后台处于停止状态时,它所在进程的生命力就会比较薄弱,在内存不足时可能会被杀死。

在Android 中的进程可以分为如下几种类型
1.前台进程(可见,可以与用户交互)
2.可见进程(可见,但不能与用户交互)
3.服务进程(后台有service在运行)
4.后台进程(没有service组件,所有的activity都处于停止状态)
5.空进程(没有任何组件在运行的进程)
以上进程的生命力,从高到低。

3.Android 中Activity与Service 交互的方式
1.启动模式:这种方式activity不能直接与service进行交互,activity需要借助broadcast从service中获取数据
2.绑定模式:需要在service中准备一个IBinder接口的实现类,并将该对象作为onBind的返回值在activity 中需要一个ServiceConnection对象,它会有两个回调方法,在其中一个方法中获得service内onBind方法返回的IBinder对象,通过IBinder对象与Service进行交互
3.AIDL模式:AIDL的方式与Service交互,bind方式进行交互式有前提的,就是activity和service时处于同一个APP中(同一个进程)通过ALDL可以实现跨进程的调用,一个APP的activity可以调用另一个APP中的service(跨进程的通信的方式: 广播,contentprovider,AIDL),进行ALDL跨进程调用,必须使用service的一个.aidl文件

一.启动模式

启动模式:这种方式activity不能直接与service进行交互,activity需要借助broadcast从service中获取数据
创建Service的两种方式
1.IDE工具生成,如下图:好处是不需要自己再清单配置文件中进行注册


2.新建一个类继承Service ,然后在清单配置文件中进行注册,注册如下:

1
2
3
4
5
<service
    android:name=".MyService01"
    android:enabled="true"
    android:exported="true" >
</service>

demo:activity通过启动的方式启动一个Service,Service每隔一秒获取一个系统时间,并通过广播发送出去,
activity如果想获得Service发出的数据需要注册一个广播接收者,接收Service发出的广播
Activity 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class MainActivity extends AppCompatActivity {
    TextView tv;
    MyReciver reciver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化view
        tv= (TextView) findViewById(R.id.textview01);
    }
    //在此方法中注册广播接收者
    @Override
    protected void onResume() {
        super.onResume();
        reciver= new MyReciver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.myService.getTime");
        registerReceiver(reciver,filter);
    }

    //启动Service
    public void startService(View v){
        Intent intent = new Intent(this,MyService01.class);
        startService(intent);
    }
    //停止Service
    public void stopService(View v){
        Intent intent = new Intent(this,MyService01.class);
        stopService(intent);
        tv.setText("Service停止");
    }
    //广播接收者 处理接收到的广播 并显示在view上
    public class  MyReciver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            String action =intent.getAction();
            if("com.myService.getTime".equals(action)){
                tv.setText(intent.getStringExtra("time"));
            }
        }
    }
}

Service 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class MyService01 extends Service {
    //用来发消息
    Handler handler= new Handler();
    public MyService01() {
    }
    //获取系统时间
    public String getServiceTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return  sdf.format(System.currentTimeMillis());
    }

    @Override
    public void onStartCommand(Intent intent, int flags, int startId) {
        super.onCreate();
        //发送延迟消息,每秒一次
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //发送广播
                Intent intent = new Intent("com.myService.getTime");
                intent.putExtra("time",getServiceTime());
                sendBroadcast(intent);
                //递归调用实现循环发送
                handler.postDelayed(this,1000);
            }
        },1000);

 //关于返回值 粘性
        //START_STICKY Service被非正常kill 还会自动启动,但是不会重新传递Intent
        //START_NOT_STICKY Service被非正常kill 还不会自动启动
        //START_REDELIVER_INTENT Service被非正常kill 还会自动启动  同时重新传递Intent
        //START_STICKY_COMPATIBILITY Service被非正常kill 不保证能正常启动
        return START_REDELIVER_INTENT;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //此方法销毁handle 否则即使关闭Service handler依然可以运行
        handler.removeCallbacksAndMessages(null);
    }

    //此方法在绑定模式下使用
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

}

运行效果:

注意:
1.Service不用一定要关闭
2.当一个循环的Handler绑定了Service时,关闭Service并不能关闭Handler ,需要在关闭Service的同时关闭Handler!

绑定模式

绑定模式:需要在service中准备一个IBinder接口的实现类,并将该对象作为onBind的返回值在activity 中需要一个ServiceConnection对象,它会有两个回调方法,在其中一个方法中获得service内onBind方法返回的IBinder对象,通过IBinder对象与Service进行交互
Activity 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class MainActivity extends AppCompatActivity {
    ServiceConnection conn;
    Handler handler;
    MyService01.MyBinder binder;
    TextView tv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv= (TextView) findViewById(R.id.textview02);
        handler =new Handler();
        conn = new ServiceConnection() {
          //当绑定成功时执行此方法
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
               //将返回的IBinder接口类型的对象强转为子类对象
                binder = (MyService01.MyBinder) service;
                //还是利用handler循环读取时间
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        tv.setText(binder.getTime());
                        handler.postDelayed(this,1000);
                    }
                },1000);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
    }
    public  void bindStart(View v){
        Intent intent = new Intent(this,MyService01.class);
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }
    public void bindStop(View v){
        unbindService(conn);
        //手动关闭handler
        handler.removeCallbacksAndMessages(null);
        tv.setText("Service停止");
    }
}

Service代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyService01 extends Service {
    public MyService01() {
    }
    //在这个方法中返回一个实现了IBinder接口的实现类对象
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    //新建类继承Binder类
    public class  MyBinder extends Binder {
        //这个方法在activity那边进行获取
        public String getTime(){
            return getServiceTime();
        }
    }
    //获取系统时间
    public String getServiceTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
        return  sdf.format(System.currentTimeMillis());
    }
}

注意:绑定模式下如果没有执行解绑,将一直保持绑定状态

AIDL模式

AIDL模式:AIDL的方式与Service交互,bind方式进行交互式有前提的,就是activity和service时处于同一个APP中(同一个进程)通过ALDL可以实现跨进程的调用,一个APP的activity可以调用另一个APP中的service(跨进程的通信的方式: 广播,contentprovider,AIDL),进行ALDL跨进程调用,必须使用service的一个.aidl文件
demo:利用AIDL实现跨APP的两个程序之间的通信,其中一个为provider一个为receiver
第一步
在provider的程序中创建一个AIDL文件,AIDL文件里面的内容就是一个接口,接口里面定义若干方法,注意接口和方法不能是public的 ,建议用IDE工具生成,在Servic中创建一个类继承AIDL中的接口实现其中的方法,并在onBind方法中将实现类的对象返回。

注意!在android studio 中使用AIDL文件在文件创建完成需要手动编译项目,把AIDL文件编译成.java文件,否则service中无法使用!
创建ALDL文件以及编译请看下图:

第二步
在provider的程序配置文件中配置隐式action因为reciver程序想要访问provider程序只能隐式调用

1
2
3
4
5
6
7
8
<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true" >
    <intent-filter>
        <action android:name="com.intent.getServiceTime2"/>
    </intent-filter>
</service>

第三步
重新创建一个APP来访问这个程序,也就是receiver程序,将AIDL文件按照包结构原封不动的拷贝到新的APP中,依然运行build–>make project 重新编译项目。
注意:一定要相同的包结构,否则报错!

第四步
在activity中获取对象启动服务
provider–service代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
       return new MyBinder2();
    }

   public class MyBinder2 extends  IMyAidlInterface.Stub{

       @Override
       public String getTime() throws RemoteException {
           return getServiveTime();
       }
   }
    public String getServiveTime(){
        SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
        return sdf.format(System.currentTimeMillis());
    }
}

receiver-activity代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class MainActivity extends AppCompatActivity {
    TextView tv;
    ServiceConnection conn;
    Handler handler;
    IMyAidlInterface ibinder;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv= (TextView) findViewById(R.id.textview03);
        //利用Handler循环获取时间
        handler = new Handler();

        conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //用这种方法获取另外APP中返回的IBinder对象
                ibinder=IMyAidlInterface.Stub.asInterface(service);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            tv.setText(ibinder.getTime());
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                        handler.postDelayed(this,1000);
                    }
                },1000);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
    }
    //启动跨进程的APP服务
    public  void start(View v){
        //这个action需要跟被访问的程序的action一致
        Intent intent = new Intent("com.intent.getServiceTime2");
        //绑定Service
        bindService(intent,conn, Context.BIND_AUTO_CREATE);
    }
    //停止跨进程的APP服务
    public  void stop(View v ){
        //解绑Service
        unbindService(conn);
        //解绑Service的同时关闭handler
        handler.removeCallbacksAndMessages(null);
        tv.setText("服务停止");
    }

}

程序运行效果:

使用Axis2调用WebService服务需要以下步骤: 1. 下载Axis2库 首先需要下载Axis2库,可以从官方网站或者Maven仓库中获取到Axis2的jar包。下载好后,需要在项目中引入Axis2相关的jar包。 2. 创建客户端代理 使用wsdl2java命令,可以根据服务端的wsdl文件生成客户端代码。命令格式如下: ``` wsdl2java -uri http://localhost:8080/axis2/services/MyService?wsdl -p com.example.client -d /path/to/output ``` 其中,-uri参数指定服务端的wsdl文件地址,-p参数指定生成的客户端代码的包名,-d参数指定生成的客户端代码的输出目录。 生成的客户端代码包括服务端的接口类、接口实现类、客户端代理类等。 3. 创建客户端 创建客户端的代码如下: ``` // 创建服务地址 String url = "http://localhost:8080/axis2/services/MyService"; // 创建服务代理 MyServiceStub stub = new MyServiceStub(url); // 调用服务方法 MyServiceStub.MyMethod request = new MyServiceStub.MyMethod(); request.setParam1("param1"); request.setParam2("param2"); MyServiceStub.MyMethodResponse response = stub.myMethod(request); ``` 其中,url参数指定服务地址,MyServiceStub是客户端代理类,MyMethod是服务端的方法,MyMethodResponse是服务端方法的返回值。 4. 调用服务 调用服务的代码如下: ``` // 创建请求消息 OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace("http://example.com", "ns"); OMElement method = fac.createOMElement("myMethod", omNs); OMElement param1 = fac.createOMElement("param1", omNs); param1.setText("param1"); method.addChild(param1); OMElement param2 = fac.createOMElement("param2", omNs); param2.setText("param2"); method.addChild(param2); // 创建服务客户端 ServiceClient serviceClient = new ServiceClient(); Options options = new Options(); options.setTo(new EndpointReference(url)); serviceClient.setOptions(options); // 调用服务 OMElement response = serviceClient.sendReceive(method); ``` 其中,OMFactory和OMNamespace是Axis2提供的类,用于构建SOAP消息。OMElement是SOAP消息的元素,addChild方法用于添加子元素。ServiceClient是Axis2提供的服务客户端类,Options类用于设置服务调用的选项,包括服务地址、超时时间等。sendReceive方法用于发送请求消息并接收服务端的响应消息。 以上就是使用Axis2调用WebService服务的基本步骤。需要注意的是,调用服务时需要根据服务端的要求构建SOAP消息,具体内容需要根据服务端的接口文档进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值