android service 学习

    技术2022-05-20  45

    Service是android 系统中的一种组件,它跟Activity的级别差不多,但是他不能自己运行,只能后台运行,并且可以和其他组件进行交互。Service的启动有两种方式:context.startService() context.bindService()。 使用context.startService() 启动Service是会会经历:context.startService()  ->onCreate()- >onStart()->Service runningcontext.stopService() | ->onDestroy() ->Service stop  如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。  stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。 所以调用startService的生命周期为:onCreate --> onStart(可多次调用) --> onDestroy 使用使用context.bindService()启动Service会经历:context.bindService()->onCreate()->onBind()->Service runningonUnbind() -> onDestroy() ->Service stop onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind->onDestroy相应退出。       所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。 在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。 service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。 下面我做了一个简单的音乐播放的应用,分别使用startService和bindService来启动本地的服务。而在下一篇《android service 学习(下) 》会介绍通过AIDL对Service进行远程调用。 下面是整个应用启动界面:先从使用startService启动Service学起  首先编写一个Activity

     

    view source print ? 01public class PlayMusic extends Activity implements OnClickListener { 02    private static final String TAG = "PlayMusic"; 03    private Button playBtn; 04    private Button stopBtn; 05    private Button pauseBtn; 06    private Button exitBtn; 07    private Button closeBtn; 08   09    //....(详见源码) 10   11@Override 12    public void onClick(View v) { 13        int op = -1; 14        Intent intent = new Intent("org.allin.android.musicService"); 15           16        //广播用 17//      Intent intent = new Intent("org.allin.android.musicReceiver"); 18           19        switch (v.getId()) { 20        case R.id.play: 21            Log.d(TAG, "onClick: playing muic"); 22            op = 1; 23            break; 24        case R.id.stop: 25            Log.d(TAG, "onClick: stoping music"); 26            op = 2; 27            break; 28        case R.id.pause: 29            Log.d(TAG, "onClick: pausing music"); 30            op = 3; 31            break; 32        case R.id.close: 33            Log.d(TAG, "onClick: close"); 34            this.finish(); 35            break; 36        case R.id.exit: 37            Log.d(TAG, "onClick: exit"); 38            op = 4; 39            stopService(intent); 40            this.finish(); 41            break; 42        } 43           44        Bundle bundle  = new Bundle(); 45        bundle.putInt("op", op); 46        intent.putExtras(bundle); 47        startService(intent); 48           49//      sendBroadcast(intent); 50    } 51   52   53}

     通过重写onClick方法来实现对播放音乐的控制。这里把播放音乐的各种操作用数字的方式通过Intent传递给service。 构造一个Intent ,ntent intent = new Intent("org.allin.android.musicService");"org.allin.android.musicService"是在AndroidManifest.xml文件中对service类的定义

    view source print ? 1<service android:enabled="true" android:name=".MusicService"> 2<intent-filter> 3<action android:name="org.allin.android.musicService" /> 4</intent-filter> 5</service>

    把操作码放在Bundle中 Bundle bundle  = new Bundle();bundle.putInt("op", op);intent.putExtras(bundle);最后使用startService(intent);启动服务。 下面看看Service是怎么实现的。 MusicService.java 

    view source print ? 01/** 02 * @author allin.dev 03 * http://allin.cnblogs.com/ 04  05 */ 06public class MusicService extends Service { 07   08    private static final String TAG = "MyService"; 09    private MediaPlayer mediaPlayer; 10   11    /* 12     * (non-Javadoc) 13      14     * @see android.app.Service#onBind(android.content.Intent) 15     */ 16    @Override 17    public IBinder onBind(Intent arg0) { 18        return null; 19    } 20   21    @Override 22    public void onCreate() { 23        Log.v(TAG, "onCreate"); 24        if (mediaPlayer == null) { 25            mediaPlayer = MediaPlayer.create(this, R.raw.tmp); 26            mediaPlayer.setLooping(false); 27        } 28    } 29   30    @Override 31    public void onDestroy() { 32        Log.v(TAG, "onDestroy"); 33        if (mediaPlayer != null) { 34            mediaPlayer.stop(); 35            mediaPlayer.release(); 36        } 37    } 38   39    @Override 40    public void onStart(Intent intent, int startId) { 41        Log.v(TAG, "onStart"); 42        if (intent != null) { 43            Bundle bundle = intent.getExtras(); 44            if (bundle != null) { 45   46                int op = bundle.getInt("op"); 47                switch (op) { 48                case 1: 49                    play(); 50                    break; 51                case 2: 52                    stop(); 53                    break; 54                case 3: 55                    pause(); 56                    break; 57                } 58   59            } 60        } 61   62    } 63   64    public void play() { 65        if (!mediaPlayer.isPlaying()) { 66            mediaPlayer.start(); 67        } 68    } 69   70    public void pause() { 71        if (mediaPlayer != null && mediaPlayer.isPlaying()) { 72            mediaPlayer.pause(); 73        } 74    } 75   76    public void stop() { 77        if (mediaPlayer != null) { 78            mediaPlayer.stop(); 79            try { 80                // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数 81                mediaPlayer.prepare(); 82            } catch (IOException ex) { 83                ex.printStackTrace(); 84            } 85        } 86    } 87   88}

      服务 使用了系统自带MediaPlayer进行音乐的播放控制。 当调用了startService后服务会先调用onCreate,我们在里面对MediaPlayer进行初始化。接着会调用onStart,可以看到传递给startService()的Intent对象会传递给onStart()方法,这样我们就可以得到intent里面的操作码: Iundle bundle = intent.getExtras(); int op = bundle.getInt("op");然后更具定义好的操作码进行相应的f播放操作。启动后界面如下图:  图中的”close”和“exit”是不同的,close只是调用finish()退出当前的Activity,但是Service并没有关掉,音乐会继续播放。而exit就是调用了stopService(intent);来停止服务,Service会调用onDestroy()方法来对mediaPlayer进行停止和释放资源。 有时候如果服务只提供一些操作接口,我们也可以通过广播的g方式来启动服务。首先要定义一个Receiver,并继承BroadcastReceiver,然后在AndroidManifest.xml中进行注册:

    view source print ? 1<receiver android:name=".MusicReceiver"> 2<intent-filter> 3<action android:name="org.allin.android.musicReceiver" /> 4</intent-filter> 5</receiver>

     Receiver的实现: MusicReceiver.java

    view source print ? 01/** 02 * @author allin.dev 03 * http://allin.cnblogs.com/ 04 * 05 */ 06public class MusicReceiver extends BroadcastReceiver { 07   08    private static final String TAG = "MusicReceiver"; 09    @Override 10    public void onReceive(Context context, Intent intent) { 11        Log.d(TAG, "onReceive"); 12        Intent it = new Intent("org.allin.android.musicService"); 13        Bundle bundle = intent.getExtras(); 14        it.putExtras(bundle); 15           16        if(bundle != null){ 17            int op = bundle.getInt("op"); 18            if(op == 4){ 19                context.stopService(it); 20            }else{ 21                context.startService(it); 22            } 23        } 24           25    } 26   27}

     然后对PlayMusic中的onclick方法进行些改造,把Intent指向ReceiverIntent intent = new Intent("org.allin.android.musicReceiver");intent中绑定的操作码都不变,再调用sendBroadcast(intent);把intentg广播出去。MusicReceiver接受到广播后根据操作码进行相应的操作。接下来的例子就是使用bindService来启动Service首先一样是写一个Activity

    view source print ? 01public class PlayBindMusic extends Activity implements OnClickListener { 02   03    private static final String TAG = "PlayBindMusic"; 04    private Button playBtn; 05    private Button stopBtn; 06    private Button pauseBtn; 07    private Button exitBtn; 08       09    private BindMusicService musicService; 10   11    @Override 12    public void onClick(View v) { 13   14        switch (v.getId()) { 15        case R.id.play: 16            Log.d(TAG, "onClick: binding srvice"); 17            musicService.play(); 18            break; 19        case R.id.stop: 20            Log.d(TAG, "onClick: stoping srvice"); 21            if(musicService != null){ 22                musicService.stop(); 23            } 24            break; 25        case R.id.pause: 26            Log.d(TAG, "onClick: pausing srvice"); 27            if(musicService != null){ 28                musicService.pause(); 29            } 30            break; 31        case R.id.exit: 32            Log.d(TAG, "onClick: exit"); 33            this.finish(); 34            break; 35        } 36    } 37   38   39private void connection(){ 40        Log.d(TAG, "connecting....."); 41        Intent intent = new Intent("org.allin.android.bindService"); 42        bindService(intent, sc, Context.BIND_AUTO_CREATE); 43           44    } 45private ServiceConnection sc = new ServiceConnection() { 46        @Override 47        public void onServiceDisconnected(ComponentName name) { 48            musicService = null; 49            Log.d(TAG, "in onServiceDisconnected"); 50        } 51           52        @Override 53        public void onServiceConnected(ComponentName name, IBinder service) { 54            musicService = ((BindMusicService.MyBinder)(service)).getService(); 55            if(musicService != null){ 56                musicService.play(); 57            } 58               59            Log.d(TAG, "in onServiceConnected"); 60        } 61    }; 62}

     

     

     

    这里使用了bindService(intent, sc, Context.BIND_AUTO_CREATE);来启动服务的,我们需要定义ServiceConnectionnn,并实现里面的方法,当服务绑定成功后会调用ServiceConnectionnn中的回调函数:public void onServiceConnected(ComponentName name, IBinder service),回调函数里面使用musicService = ((BindMusicService.MyBinder)(service)).getService();来获取BindMusicService服务对象,有了BindMusicService实例对象,就可以调用服务提供的各种控制音乐播放的哦功能。

    注意要在Activity的onCrate方法中调用connect(),这里顺便说下顺序:

    调用connect()函数后就绑定服务,触发Service的onCreate方法,然后调用Service的onBind()方法,绑定完成后又回到Activity的onServiceConnected()方法,在这个方法中的参数IBinder server就是onBind()中返回的,此时我们就可以利用这个IBinder来操作service了。下面看看BindMusicService.java的实现:

     

     

    view source print ? 01/** 02 * @author allin.dev 03 * http://allin.cnblogs.com/ 04 */ 05public class BindMusicService extends Service { 06   07    private static final String TAG = "MyService"; 08    private MediaPlayer mediaPlayer; 09   10    private final IBinder binder = new MyBinder(); 11   12    public class MyBinder extends Binder { 13        BindMusicService getService() { 14            return BindMusicService.this; 15        } 16    } 17   18    /* 19     * (non-Javadoc) 20      21     * @see android.app.Service#onBind(android.content.Intent) 22     */ 23    @Override 24    public IBinder onBind(Intent intent) { 25        Log.d(TAG, "onBind"); 26        play(); 27        return binder; 28    } 29   30    @Override 31    public void onCreate() { 32        super.onCreate(); 33           34        Log.d(TAG, "onCreate"); 35        Toast.makeText(this, "show media player", Toast.LENGTH_SHORT).show(); 36           37           38    } 39   40    @Override 41    public void onDestroy() { 42        super.onDestroy(); 43           44        Log.d(TAG, "onDestroy"); 45        Toast.makeText(this, "stop media player", Toast.LENGTH_SHORT); 46        if(mediaPlayer != null){ 47            mediaPlayer.stop(); 48            mediaPlayer.release(); 49        } 50    } 51   52       53    public void play() { 54        if (mediaPlayer == null) { 55            mediaPlayer = MediaPlayer.create(this, R.raw.tmp); 56            mediaPlayer.setLooping(false); 57        } 58        if (!mediaPlayer.isPlaying()) { 59            mediaPlayer.start(); 60        } 61    } 62   63    public void pause() { 64        if (mediaPlayer != null && mediaPlayer.isPlaying()) { 65            mediaPlayer.pause(); 66        } 67    } 68   69    public void stop() { 70        if (mediaPlayer != null) { 71            mediaPlayer.stop(); 72            try { 73                // 在调用stop后如果需要再次通过start进行播放,需要之前调用prepare函数 74                mediaPlayer.prepare(); 75            } catch (IOException ex) { 76                ex.printStackTrace(); 77            } 78        } 79    } 80   81}

    我们看到Service中有个返回IBinder对象的onBind方法,这个方法会在Service被绑定到其他程序上时被调用,而这个IBinder对象和之前看到的onServiceConnected方法中传入的那个IBinder是同一个东西。应用和Service间就依靠这个IBinder对象进行通信。启动后的界面如下图:[源码下载]


    最新回复(0)