使用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