Android 之 Service 详解

来源:互联网 发布:软件生存周期是什么 编辑:程序博客网 时间:2024/06/04 18:33

前言:
Android四大组件,Activity,Service,BroadcastReceiver和ContentProvider。最近在工作中遇到很多网络处理操作都用线程来处理,想想好像Service就是用来进行这类操作的,这两者的区别和使用场合有点模糊了,最近主要研究了service并进行总结,以备后用。

一.Service 定义

1.根据官网对于Service的定义翻译为中文:

Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。

2.加深对Service的理解,可以看下这段描述:

(1).A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.

(2).A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).

(个人英语一般,但总感觉这段描述的英文好像有问题)
可以译为:
(1).Service并不是一个单独的进程,Service对象如果不明确指明,不意味着运行在它自身的进程中,它运行在Application的系统进程中,是进程的一部分。
(2).Service不是一个线程,不意味着可以在主线程之外执行其它工作(避免应用ANR)。

关于第二点需要重点说明一下:网上的文章很多都把耗时的操作直接放在Service的onStart方法中,而且没有强调这样会出现Application Not Responding!Service不是一个线程,不能直接处理耗时的操作,如果非要在Service中进行耗时处理,就必须开启一个单独的线程来处理或者采用IntentService来实现。
关于IntentService,后面会加以总结。

二. 与Activity的区别

1.不能与用户交互,对用户透明。
2.不能自己启动。
3.当我们退出应用时,Service进程并没有结束,它仍然可以在系统后台运行。

Service有两种状态:“启动的”和“绑定”。就是当调用服务的startService()和bindService()之后出现的状态。可以简单理解为:”started”和“binded”。

三 Service的启动

有两种方式可以启用一个Service。

a、Context.startService()
使用这个方法时,service与启动者是没有关系的,只是单纯的启动service,若启动者退出了,service依旧在后台运行。(如音乐播放,即使退出了程序,音乐还在播放着)

b、Context.bindService()
使用此方法时,顾名思义,就是把启动者与service绑定在一起了,启动者退出,service也跟着停止。

四 Service的生命周期

服务启用的方式不同,生命周期也不一样.

1.startService()方式启用的Service:

onCreate()—>>onStart()—>>onDestroy();

这里写图片描述

2.bindService()方式启用的Service:

onCreate()—>>onBind()—>>onUnBind()—>>onDestroy();

这里写图片描述

两种方式下的Service生命周期如下图展示:
这里写图片描述

五 一个后台开启音乐的ServiceDemo

类似的Demo网上很多,随便改了一个,写在下面,仅供参考:

1.MusicService.java
继承Service类,必须重写onBind()方法。
Service类的业务处理,写在onCreate()方法内部。

注意:R.raw.ccnnian 要在Res文件夹下面创建raw文件夹,将ccnnian(匆匆那年.mp3)放进去,修改名字。
package com.elvis.musicService;import com.example.servicedemo.R;import android.app.Service;import android.content.Intent;import android.media.MediaPlayer;import android.os.IBinder;import android.util.Log;import android.widget.Toast;public class MusicService extends Service{    //为日志工具设置标签    String tag = "MusicService";    //定义音乐播放器变量    MediaPlayer mPlayer;    //其他对象通过bindService方法通知该Service时该方法会被调用    @Override    public IBinder onBind(Intent arg0)     {        // TODO Auto-generated method stub        Toast.makeText(this, "MusicService onBind() ",                Toast.LENGTH_LONG).show();        Log.i(tag,"MusicService onBind()");        mPlayer.start();        return null;            }    //其他对象通过unbindService方法通知该Service时该方法会被调用    @Override    public boolean onUnbind(Intent intent) {        // TODO Auto-generated method stub        Toast.makeText(this, "MusicService onUnbind()   ",                Toast.LENGTH_LONG).show();        Log.i(tag, "MusicService onUnbind()");        mPlayer.stop();        return false;    }    @Override    public void onCreate() {        // TODO Auto-generated method stub        Toast.makeText(this, "MusicService onCreate()   ",                Toast.LENGTH_LONG).show();        //创建一个音乐播放器        //mPlayer = MediaPlayer.create(getApplicationContext(),R.);        mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.ccnnian);        mPlayer.setLooping(true);        Log.i(tag, "MusicService onCreate()");        super.onCreate();    }    @Override    public void onDestroy() {        // TODO Auto-generated method stub        Toast.makeText(this, "MusicSevice onDestroy()"                , Toast.LENGTH_SHORT).show();        Log.e(tag, "MusicService onDestroy()");        mPlayer.stop();        super.onDestroy();    }    @Override    @Deprecated    public void onStart(Intent intent, int startId) {        // TODO Auto-generated method stub        Toast.makeText(this, "MusicSevice onStart()"                , Toast.LENGTH_SHORT).show();        Log.e(tag, "MusicSerice onStart()");        mPlayer.start();        super.onStart(intent, startId);    }}

2.ServiceActivity.java

两种方式开启服务。注意Intent intent = new Intent(ServiceActivity.this,MusicService.class);通过Intent对象实现Service启动。
package com.example.servicedemo;import com.elvis.musicService.MusicService;import android.os.Bundle;import android.os.IBinder;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;public class ServiceActivity extends Activity {    //为日志工具设置标签    private static String tag = "MusicService";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_service);         Toast.makeText(this, "ServiceActivity",                    Toast.LENGTH_LONG).show();            Log.e(tag, "MusicServiceActivity");        initView();    }    //定义服务链接对象    final ServiceConnection conn = new ServiceConnection()    {        @Override        public void onServiceConnected(ComponentName arg0, IBinder arg1) {            // TODO Auto-generated method stub             Toast.makeText(ServiceActivity.this, "MusicServiceActivity onServiceConnected"                        ,Toast.LENGTH_SHORT).show();                Log.e(tag, "MusicServiceActivity onServiceConnected");        }        @Override        public void onServiceDisconnected(ComponentName arg0) {            // TODO Auto-generated method stub            Toast.makeText(ServiceActivity.this, "MusicServiceActivity onSeviceDisconnected"                    , Toast.LENGTH_SHORT).show();            Log.e(tag, "MusicServiceActivity onSeviceDisconnected");        }    };    private void initView()    {        Button btnStart = (Button)findViewById(R.id.Button01);        Button btnStop = (Button)findViewById(R.id.Button02);        Button btnBind = (Button)findViewById(R.id.Button03);        Button btnUnbind = (Button)findViewById(R.id.Button04);        OnClickListener ocl = new OnClickListener(){            @Override            public void onClick(View v) {                // TODO Auto-generated method stub                //显示指定, intent 所指的对象是  service                Intent intent = new Intent(ServiceActivity.this,MusicService.class);                switch(v.getId())                {                case R.id.Button01:                    startService(intent);                    break;                 case R.id.Button02:                        //停止服务                        stopService(intent);                        break;                case R.id.Button03:                    //绑定服务                    bindService(intent, conn, Context.BIND_AUTO_CREATE);                    break;                case R.id.Button04:                    //解绑服务                    unbindService(conn);                    break;                }            }        };        btnStart.setOnClickListener(ocl);        btnStop.setOnClickListener(ocl);        btnBind.setOnClickListener(ocl);        btnUnbind.setOnClickListener(ocl);    }}

3.注册Service

在AndroidManifest.xml文件中,添加 <service android:name="com.elvis.musicService.MusicService"/> 到<application>标签内部。

六 总结

startService()方式开启的音乐,在程序退出时依然播放。
bindService()方式开启的音乐,程序退出时停止播放。

0 0