Service学习

使用Service的原因:这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

Demo1:基础service

(1)写服务

package com.example.server.Service;

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

import androidx.annotation.Nullable;

public class MyService extends Service {


    private static final String TAG="MyService";


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String result=intent.getStringExtra("send");
        Log.d(TAG,"onStartCommand, result="+result+"Thread="+Thread.currentThread().getName());//说明activity是可以通信的
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestory");
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBind");
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

(2)MainActivity

package com.example.server;

import androidx.appcompat.app.AppCompatActivity;

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

import com.example.server.Service.MyService;

public class MainActivity extends AppCompatActivity {

    private Button startService,stopService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService=(Button)findViewById(R.id.start_service);
        stopService=(Button)findViewById(R.id.stop_service);

        startService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent startService=new Intent(MainActivity.this, MyService.class);
                startService.putExtra("send","I am Activity");
                startService(startService);
            }
        });
        stopService.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent stopService=new Intent(MainActivity.this,MyService.class);
                stopService(stopService);
            }
        });
    }
}

(3)布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/start_service"
        android:text="开启服务"
        ></Button>


    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/stop_service"
        android:text="关闭服务"
        ></Button>
</LinearLayout>

(4)Manifest配置

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.server">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".Service.MyService"

            android:enabled="true"
            android:exported="true"
            ></service>
    </application>

</manifest>

(5)Log结果

02-28 11:25:49.795 13026-13026/com.example.server D/MyService: onCreate
02-28 11:25:49.795 13026-13026/com.example.server D/MyService: onStartCommand, result=I am ActivityThread=main
02-28 11:31:34.304 13026-13026/com.example.server D/MyService: onDestory

当多次点击开启服务

02-28 11:51:40.065 31262-31262/com.example.server D/MyService: onCreate
02-28 11:51:40.065 31262-31262/com.example.server D/MyService: onStartCommand, result=I am ActivityThread=main
02-28 11:51:41.195 31262-31262/com.example.server D/MyService: onStartCommand, result=I am ActivityThread=main
02-28 11:51:47.202 31262-31262/com.example.server D/MyService: onStartCommand, result=I am ActivityThread=main
02-28 11:51:47.930 31262-31262/com.example.server D/MyService: onStartCommand, result=I am ActivityThread=main
02-28 11:51:49.596 31262-31262/com.example.server D/MyService: onDestory

说明如果服务创建好之后,不会重复创建。

Demo2:Activity使用Service里的Binder控制Service

(1)

package com.example.server.Service;

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

import androidx.annotation.Nullable;

public class MyService extends Service {


    private static final String TAG="MyService";


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String result=intent.getStringExtra("send");
        Log.d(TAG,"onStartCommand, result="+result+"Thread="+Thread.currentThread().getName());//说明activity是可以通信的
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestory");
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {//通过这个接口将binder放出去
        Log.d(TAG,"onBind");
        return new MyBinder();
    }

    private String string="I am service's  value";
     public class MyBinder extends Binder{//Binder是自己构造出来的
      public  void getString(){
          Log.d(TAG,string.toString());
      }
  }
}

(2)

package com.example.server.Service;

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

import androidx.annotation.Nullable;

public class MyService extends Service {


    private static final String TAG="MyService";


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String result=intent.getStringExtra("send");
        Log.d(TAG,"onStartCommand, result="+result+"Thread="+Thread.currentThread().getName());//说明activity是可以通信的
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestory");
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {//通过这个接口将binder放出去
        Log.d(TAG,"onBind");
        return new MyBinder();
    }

    private String string="I am service's  value";
     public class MyBinder extends Binder{//Binder是自己构造出来的
      public  void getString(){
          Log.d(TAG,string.toString());
      }
  }
}

Service里面的Binder是创建一个类的,不是其本身就有,但是Service里可以将binder的接口提供出去。在activity可以开启服务,并通过ServiceConnection的回调返回service的binder,从而让activity可以通过binder控制service。

demo3:实现两个app(进程)通信

一,先写作为服务端的app

(1)在main包下,新建一个aidl的文件,再新建一个aidl的package,接着写一个MyAIDLService的aidl文件

// MyAIDLService.aidl
package aidl;

// Declare any non-default types here with import statements

interface MyAIDLService {
   String getString();
}

(2)点击AS的build下的rebuild,会生成一个关于MyAIDLService相关的文件,如下:。

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package aidl;
// Declare any non-default types here with import statements

public interface MyAIDLService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements aidl.MyAIDLService
{
private static final java.lang.String DESCRIPTOR = "aidl.MyAIDLService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an aidl.MyAIDLService interface,
 * generating a proxy if needed.
 */
public static aidl.MyAIDLService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof aidl.MyAIDLService))) {
return ((aidl.MyAIDLService)iin);
}
return new aidl.MyAIDLService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getString:
{
data.enforceInterface(descriptor);
java.lang.String _result = this.getString();
reply.writeNoException();
reply.writeString(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements aidl.MyAIDLService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.lang.String getString() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getString, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getString = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String getString() throws android.os.RemoteException;
}

(3)写Service

import aidl.MyAIDLService;

import androidx.annotation.Nullable;

public class MyService extends Service {


    private static final String TAG="MyService";


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String result=intent.getStringExtra("send");
        Log.d(TAG,"onStartCommand, result="+result+"Thread="+Thread.currentThread().getName());//说明activity是可以通信的
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestory");
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {//通过这个接口将binder放出去
        Log.d(TAG,"onBind");
        return new MyBinder();
    }

 public class MyBinder extends MyAIDLService.Stub {

        @Override
        public String getString() throws RemoteException {
            return "我来自于Service中继承AIDL.Stub的Binder";
        }
    }
}

(5)配置manifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.server">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".Service.MyService"

            android:enabled="true"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="com.example.server.Service.MyService" />
            </intent-filter>
        </service>
    </application>

</manifest>

这里有两点需要注意一下:

1,要将MyService注册在manifest里,服务端才能启用
2,里面有个intent-filter的设置,是将MyService的路径写进去了,写这个的目的是将MyService的访问暴露给其他的app。不然其他app访问不了这个服务。

二,在写客户端

(1)在客户端main下新建一个aidl的文件,然后在这个文件下在建一个aidl的package,接着在写一个MyAIDLService的aidl文件。

注意:这里的aidl的名字要和服务端里的aidl名字一样,然后它的包也是一样才行。
// MyAIDLService.aidl
package aidl;

// Declare any non-default types here with import statements

interface MyAIDLService {
   String getString();
}

(2)MainActivity下进行访问

package com.example.client;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import aidl.MyAIDLService;


public class MainActivity extends AppCompatActivity {

    private Button bind_service,unbind_service;
    private MyAIDLService myAIDLService;
    ServiceConnection connection=new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAIDLService=MyAIDLService.Stub.asInterface(service);
            try {
                Log.d("MyService","onServiceConnected and the transfer ans="+myAIDLService.getString());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
              myAIDLService=null;
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bind_service=(Button)findViewById(R.id.bind_service);
        unbind_service=(Button)findViewById(R.id.unbind_service);

        bind_service.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                               intent.setAction("com.example.server.Service.MyService");
                                 //从 Android 5.0开始 隐式Intent绑定服务的方式已不能使用,所以这里需要设置Service所在服务端的包名
                                 intent.setPackage("com.example.server");//这个是另外一个app的包名
                //因为当服务器的app安装到手机上后,通过这个包名,其他手机可以访问服务器的app
                                 bindService(intent, connection, BIND_AUTO_CREATE);
            }
        });

        unbind_service.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                unbindService(connection);
            }
        });
    }
}

在这里intent设置了两个参数

  intent.setAction("com.example.server.Service.MyService");
                                 //从 Android 5.0开始 隐式Intent绑定服务的方式已不能使用,所以这里需要设置Service所在服务端的包名
  intent.setPackage("com.example.server");//这个是另外一个app的包名
                //因为当服务器的app安装到手机上后,通过这个包名,其他手机可以访问服务器的app

设置setAction中的包名是因为和之前服务端里manifest中暴露的接口包名是一样的,一一对应起来。后面一个setPackage的包名是为了访问服务端的app。

在客户端不用配置manifest。

小提示:

在创建aidl文件的时候,如果是直接创建的话,它的包名会和app的包名一样。
比如我们这里是要求aidl文件在aidl这个package下。

我们在创建好aidl这个文件时,新建一个aidl的package,它这个文件会跑到com.example.client这个包下,需要将aidl文件手动复制到aidl的package下,在将那个aidl产生的com.example.client这个目录删掉。

参考链接:http://blog.csdn.net/guolin_blog/article/details/11952435

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容