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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354