Service的使用

Service分为本地服务(LocalService)和远程服务(RemoteService):
1、本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程,因此不需要IPC,也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。
2、远程服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。
按使用方式可以分为以下三种:
1、startService 启动的服务:主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService;
2、bindService 启动的服务:该方法启动的服务可以进行通信。停止服务使用unbindService;
3、startService 同时也 bindService 启动的服务:停止服务应同时使用stopService与unbindService
Service 与 Thread 的区别
很多时候,你可能会问,为什么要用 Service,而不用 Thread呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下。
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。
Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进
行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册
BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。
Service的生命周期
onCreate  onStart  onDestroy  onBind
1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。
该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。
2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。
3). 被启动又被绑定的服务的生命周期:如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。
4). 当服务被停止时清除服务:当一个Service被终止(1、调用stopService;2、调用stopSelf;3、不再有绑定的连接(没有被启动))时,onDestroy方法将会被调用,在这里你应当做一些清除工作,如停止在Service中创建并运行的线程。
特别注意:
1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自动解除,并且Service会自动停止);
2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService;
3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;
4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。
5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。

一个本地服务的例子,注意了:通过startService和stopService启动关闭服务的,适用于服务和activity之间没有调用交互的情况。如果之间需要传递参数或者方法调用,需要使用bind和unbind方法。代码如下所示:

public class MainActivity extends AppCompatActivity {
    TextView text;
    Button button1;
    private Intent intent;
    private ServiceConnection r;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button1= (Button) findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bindService(intent, r, Context.BIND_AUTO_CREATE);
            }
        });
        text= (TextView) findViewById(R.id.textView3);
        intent = new Intent(this, fuwu.class);
        r = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {//第二个参数iBinder就是fuwu中onBind方法return的那个u实例,可以利用这个来传递数据
                text.setText(((fuwu.u) iBinder).geta());
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {

            }
        };
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(r);
    }
}
public class fuwu extends Service {
    public class u extends Binder {
        public String geta() {
            return "收到了";
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        new Thread() {//新建了一个线程来执行计时功能
            @Override
            public void run() {
                super.run();
                int ia = 0;
                for (int i = 0; i < 11; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ia++;
                    Log.i("xinxi", String.valueOf(ia));
                }
            }
        }.start();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("xinxi", "onBind");
        return new u();
    }
}

远程服务和本地服务的区别就是是否在androidmanifest.xml文件中的service中设置了android:process属性,因为startService启动的service不能传递信息给activity,所以可以直接给service添加process属性,让其运行在不同的进程,而bindService启动的service会传递信息给activity,所以如果给service添加process属性的话,需要使用到aidl,具体的代码如下所示:

public class MainActivity extends AppCompatActivity {
    private android.widget.Button button;

    private ServiceConnection serviceConnection;
    private Button button1;
    private LinearLayout activitymain;
    private Button button2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button2 = (Button) findViewById(R.id.button2);
        activitymain = (LinearLayout) findViewById(R.id.activity_main);
        button1 = (Button) findViewById(R.id.button1);
        button = (Button) findViewById(R.id.button);
        serviceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                try {
                    button.setText((IAidlBinder.Stub.asInterface(iBinder)).getInfo());
                    Toast.makeText(MainActivity.this,(IAidlBinder.Stub.asInterface(iBinder)).getxuesheng().getDizhi()+(IAidlBinder.Stub.asInterface(iBinder)).getxuesheng().getXuehao()+(IAidlBinder.Stub.asInterface(iBinder)).getxuesheng().getName(),Toast.LENGTH_SHORT).show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {

            }
        };
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, AidlService.class);
                bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
            }
        });
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getfuwu();
            }
        });
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(MainActivity.this, bendi.class);
                bindService(intent, new ServiceConnection() {
                    @Override
                    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                        button2.setText(((bendi.u)iBinder).geta());
                    }

                    @Override
                    public void onServiceDisconnected(ComponentName componentName) {

                    }
                },Context.BIND_AUTO_CREATE);
                 //startService(intent);//用startService启动的服务可以设置android:process属性,将其运行在不同的进程中,因为用startService启动的服务不与activity进行通信,但是如果是bindService启动的服务,不可以设置android:process,不然会报错,只有使用aidl就可以给用bindService启动的服务设置android:process属性了,因为进程之间通信要用到aidl
            }
        });
    }

    void getfuwu() {
        ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
       /* for (ActivityManager.RunningServiceInfo serviceInfo : activityManager.getRunningServices(Integer.MAX_VALUE)) {
            Log.i("xinxi", serviceInfo.process);//RunningServiceInfo是用来查看运行的服务的信息的,远程服务能在这里显示
        }*/
        for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : activityManager.getRunningAppProcesses()) {
            Log.i("xinxi", runningAppProcessInfo.processName);//RunningAppProcessInfo是用来查看当前运行的app的进程的信息的,本地服务不创建新的进程,所以不能在这里显示,远程服务在这里能显示进程,就是通过android:process属性设置好的进程名字
        }
    }
}
public class AidlService extends Service {

    private IAidlBinder.Stub serviceBinder = new IAidlBinder.Stub(){
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public String getInfo() throws RemoteException {
            return "I'm a Service";
        }

        @Override
        public Student getxuesheng() throws RemoteException {
            Student student=new Student(11,"laowang","shanxide");
            return student;
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return serviceBinder;
    }
}
public class bendi extends Service {
    public class u extends Binder {
        public String geta() {
            return "收到了";
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i("xinxi", "onCreate");
    }

/*
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {//注意:通过startServer启动的服务才会调用onStartCommand方法,通过bindService启动的服务调用的是onBind方法
        Log.i("xinxi", "onStartCommand");
        return START_STICKY;
    }
*/

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("xinxi", "onBind");
        return new u();
    }
}
public class Student implements Parcelable {
    private int xuehao;
    private String name;
    private String dizhi;

    public Student(int xuehao, String name, String dizhi) {
        this.xuehao = xuehao;
        this.name = name;
        this.dizhi = dizhi;
    }

    public int getXuehao() {
        return xuehao;
    }

    public String getName() {
        return name;
    }

    public String getDizhi() {
        return dizhi;
    }

    public void setXuehao(int xuehao) {
        this.xuehao = xuehao;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setDizhi(String dizhi) {
        this.dizhi = dizhi;
    }

    @Override
    public String toString() {
        return "Student{" +
                "xuehao=" + xuehao +
                ", name='" + name + '\'' +
                ", dizhi='" + dizhi + '\'' +
                '}';
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.xuehao);
        dest.writeString(this.name);
        dest.writeString(this.dizhi);
    }

    public Student() {
    }

    protected Student(Parcel in) {
        this.xuehao = in.readInt();
        this.name = in.readString();
        this.dizhi = in.readString();
    }

    public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel source) {
            return new Student(source);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };
}
在IAidlBinder.aidl文件中,记得创建完成后,执行build>make project,这样才能在其中java文件中找到该接口
package com.example.liang.lianxi;
import com.example.liang.lianxi.Student;//注意了这里的bean文件必须得手动导入,不然系统会找不到
interface IAidlBinder {
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
            String getInfo();
            Student getxuesheng();
}
在Student.aidl文件中,注意再创建bean文件的aidl时,会出现interface name must be unique错误,这时只需要起个其他名字,等创建完成后再修改名字就行
package com.example.liang.lianxi;
parcelable Student;
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:theme="@style/AppTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".AidlService"
            android:process=":yuancheng"/>
        <!--进程名为:com.example.liang.lianxi:yuancheng-->
        <service android:name=".bendi"
            />
    </application>

----------------------------------------------------------------------------

android开发艺术中对IntentService的介绍:

IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,抽象方法为onHandleIntent(),IntentService用于执行后台耗时的任务,当任务执行后它会自动停止,同时由于IntentService是服务的原因,这导致它的优先级比单纯的线程要高很多,所以IntentService比较适合执行一些高优先级的后台任务,不容易被系统杀死。在实现上,IntentService封装了HandlerThread和Handler。当onHandleIntent方法执行完最后一个任务后,会自动停止服务;当有多个后台任务同时存在时,这些后台任务会按照外界发起的顺序排队执行。

IntentService的用法,代码如下所示:
public class IntentFuWu extends IntentService {//记得在androidmanifest.xml中进行服务注册

    public IntentFuWu() {
        super("IntentFuWu");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d("IntentFuWu", intent.getStringExtra("zhi"));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("IntentFuWu", "服务destroy");
    }
}
        Intent intent = new Intent(this, IntentFuWu.class);
        intent.putExtra("zhi", "我是任务1");
        startService(intent);
        intent.putExtra("zhi", "我是任务2");
        startService(intent);
        intent.putExtra("zhi", "我是任务3");
        startService(intent);
        /*输出结果为:
        05-24 23:39:35.934 13730-13773/? D/IntentFuWu: 我是任务1
        05-24 23:39:35.934 13730-13773/? D/IntentFuWu: 我是任务2
        05-24 23:39:35.934 13730-13773/? D/IntentFuWu: 我是任务3
        05-24 23:39:36.414 13730-13730/com.example.liang.arlvyou D/IntentFuWu: 服务destroy*/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容