求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
深入浅出 Android核心组件Service(一)
 

发布于2012-2-20

 

在Android框架中,Service是比较难以理解的一部分,而网上的大多数资料最多就是讲述了如何去用Service,并没有对Service做一个深入的、系统的讲解。现在傻蛋将做一个系列文章,将对Service做一个由浅入深的梳理,帮助大家深入的掌握Android Service。

首先我们先来看看怎么使用Service,然后再谈Android Service的内部机制。

在Android中Service的启动方式有两种,今天先发第一种。

Service的启动方式一:

启动:Context.startService(new Intent(context,xxx.class));

停止:Context.stopService() ;

我画了一个Service启动的流程图,相信大家一看就懂。Activity通过 Intent启动Service,如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果 Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 调用stopService就会触发Service的onDestroy()方法。

这一节里面傻蛋做了一个示例程序是一个音乐播放器,界面如下,功能很简单:播放、暂停、停止音乐、关闭Activity(这时Service仍然运行,继续播放音乐)、退出程序(停止音乐退出Activity)。

由于要控制Service的动作,傻蛋写了一个播放的通用类,这样在以后的课程中还能用上,代码如下:

/**

* MyMediaController.java

* com.androidtest.service.mediaplayer

*

* Function: TODO

*

* ver date author

* ──────────────────────────────────

* 2011-5-16 Leon

*

* Copyright (c) 2011, 最牛网 All Rights Reserved.

*/

package com.zuiniuwang;

import java.io.Serializable;

import android.media.MediaPlayer;

/**

* ClassName:MyMediaController

* Function: Mediaplayer 的一个控制类,控制播放器的播放 暂停 停止 等动作

* REASON

*

* @author Leon

* @version

* @since Ver 1.1

* @Date 2011-5-16

*/

public enum MyMediaController implements Serializable {

    play {

        @Override

        public void execute() {

            if (mediaPlayer != null && !mediaPlayer.isPlaying())

            mediaPlayer.start();

            // TODO Auto-generated method stub

         }

    },

    pause {

        @Override

        public void execute() {

            // TODO Auto-generated method stub

            if (mediaPlayer != null && mediaPlayer.isPlaying()) {

                mediaPlayer.pause();

            }

        }

    },

    stop {

        @Override

        public void execute() {

            // TODO Auto-generated method stub

            if (mediaPlayer != null) {

                mediaPlayer.stop();

                try {

                    // 在stop后如果要重新Start需要prepare一下

                    mediaPlayer.prepare();

                    // 从头播放

                    mediaPlayer.seekTo(0);

                } catch (Exception e) {

                    // TODO Auto-generated catch block

                    e.printStackTrace();

                }

            }

        }

    };

    public static MediaPlayer mediaPlayer;

    public abstract void execute();

}

然后是控制播放的Activity:

/**

* MusicPlayer.java

* com.androidtest.activity

*

* Function: TODO

*

* ver date author

* ──────────────────────────────────

* 2011-5-15 Leon

*

* Copyright (c) 2011, 最牛网 All Rights Reserved.

*/

package com.androidtest.activity.musicplayer;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import com.androidtest.MyImageButton;

import com.androidtest.R;

import com.androidtest.service.mediaplayer.MyMediaController;

import com.androidtest.service.mediaplayer.NormalMusicService;

import com.androidtest.sharedpreferences.TestSharePreferences;

/**

* ClassName:MusicPlayer Function: TODO ADD FUNCTION Reason: TODO ADD REASON

*

* @author Leon

* @version

* @since Ver 1.1

* @Date 2011-5-15

*/

public class NormalMusicPlayerActivity extends Activity implements OnClickListener {

    private static final String TAG = NormalMusicPlayerActivity.class.getSimpleName();

    private Intent intent ;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);

        this.setContentView(R.layout.music_player_layout);

        Button playButton = (Button) this.findViewById(R.id.play);

        playButton.setOnClickListener(this);

        Button pauseButton =(Button) this.findViewById(R.id.pause);

        pauseButton.setOnClickListener(this);

        Button stopButton =(Button)this.findViewById(R.id.stop);

        stopButton.setOnClickListener(this);

        Button closeActivityButton =(Button)this.findViewById(R.id.close);

        closeActivityButton.setOnClickListener(this);

        Button exitActivityButton =(Button)this.findViewById(R.id.exit);

        exitActivityButton.setOnClickListener(this);

        intent = new Intent("com.androidtest.service.mediaplayer.NormalMusicService");

        TestSharePreferences testSharePreferences=(TestSharePreferences)this.getApplication();

        Log.v(TAG , ""+testSharePreferences.getSharedInteger());

    }

    private void playAction(MyMediaController playType) {

        Bundle bundle = new Bundle();

        bundle.putSerializable(NormalMusicService.INTENT_KEY, playType);

        intent.putExtras(bundle);

        NormalMusicPlayerActivity.this.startService(intent);

    }

    @Override

    public void onClick(View view) {

        // TODO Auto-generated method stub

        switch (view.getId()) {

            case R.id.play:

            Log.d(TAG, "play.......");

            playAction(MyMediaController.play);

            break;

            case R.id.pause:

            Log.d(TAG, "pause.......");

            playAction(MyMediaController.pause);

            break;

            case R.id.stop:

            Log.d(TAG, "stop.......");

            playAction(MyMediaController.stop);

            break;

            case R.id.close:

            Log.d(TAG, "close.......");

            this.finish();

            break;

            case R.id.exit:

            Log.d(TAG, "exit.......");

            stopService(intent);

            this.finish();

        }

    }

}

最后是Service类

/**

* MusicService.java

* com.androidtest.service

*

* Function: TODO

*

* ver date author

* ──────────────────────────────────

* 2011-5-15 Leon

*

* Copyright (c) 2011, 最牛网 All Rights Reserved.

*/

package com.zuiniuwang.service;

import java.io.Serializable;

import android.app.Service;

import android.content.Intent;

import android.media.MediaPlayer;

import android.os.IBinder;

import android.util.Log;

import com.zuiniuwang.*;

/**

* ClassName:MusicService

* Function: TODO ADD FUNCTION

* Reason: TODO ADD REASON

*

* @author Leon

* @version

* @since Ver 1.1

* @Date 2011-5-15

*/

public class NormalMusicService extends Service{

    private String TAG = NormalMusicService.class.getSimpleName();

    private MediaPlayer myMediaPlayer ;

    public static final String INTENT_KEY= "action" ;

    @Override

    public IBinder onBind(Intent arg0) {

        // TODO Auto-generated method stub

        return null;

    }

    @Override

    public void onCreate() {

        // TODO Auto-generated method stub

        Log.v(TAG , TAG+ " onCreate()");

        super.onCreate();

        if(myMediaPlayer==null){

            myMediaPlayer=MediaPlayer.create(this, R.raw.test) ;

            myMediaPlayer.setLooping(false);

        }

    }

    @Override

    public void onStart(Intent intent, int startId) {

        // TODO Auto-generated method stub

        Log.v(TAG , TAG + " onStart()");

        super.onStart(intent, startId);

        if(intent!=null){

            MyMediaController mediaControl =(MyMediaController)intent.getSerializableExtra(NormalMusicService.INTENT_KEY);

            mediaControl.mediaPlayer=myMediaPlayer;

            mediaControl.execute();

        }

    }

    @Override

    public void onDestroy() {

        // TODO Auto-generated method stub

        super.onDestroy();

        Log.v(TAG , " onDestroy");

        if(myMediaPlayer!=null){

            myMediaPlayer.stop();

            myMediaPlayer.release();

        }

    }

}

附件为本实例的代码下载地址:http://down.51cto.com/data/326354

第二种是通过绑定的方式来启动Service。先看流程图。

绑定的方式和第一节的方式最大的不同就是在于,Activity可以和Service实现关联,当被关联的Activity结束后,相应的Service 也会停止,同时在绑定了的Activity中我们还可以回调我们在Service中定义的方法。在这里我们使用了 this.bindService(intent, myServiceConnection, Context.BIND_AUTO_CREATE); 来启动Service,当Service创建了同时绑定了Activity之后,会回调我们定义的ServiceConnection(),从而传回IBinder接口,我们就能够调用Service中的方法了。这时候Activity就和 Service实现了绑定,Activity退出了Service就相应的退出了。Service的申明如下,intent filter 是对接收Service的过滤。

<service android:enabled="true" android:name=".service.mediaplayer.BindMusicService">

<intent-filter>

http://down.51cto.com/data/326354<action android:name="com.androidtest.service.mediaplayer.BindMusicService" />

</intent-filter>

</service>

本节的源代码可以在此下载: http://down.51cto.com/data/326385

前两节中可以看到Activity和Service,context.startService对应着Service中的onStart()方法,context.onBindService对应的是Service中的onBind()方法。当我们继想绑定一个Service又想在 Activity停止时,Service不会停止,我们可以先StartService,然后再BindService()。这时候的流程图如下所示:

此时需要注意一个问题,当Activity退出的时候,Sercvice并不会停止,此时我们可以再进入Activity重新绑定,当这时候 Service就会调用onRebind()方法,但是调用onRebind()方法的前提是先前的onUnbind()方法执行成功,但是使用 super.onUnbind(intent)是执行不成功的,这时候我们要手动的使其返回true,再次绑定时Rebind()就会执行。否则,如果退出时不显示的指定onUnbind()为成功的话(为false),那么重新启动此Activity来绑定服务时,Service的onBind()方法和onReBind都不会执行,但是ServiceConnection方法确一定会回调了。这说明在Service中的onBind()方法不同于 onStart()方法不能被重复调用。

本节代码和上节代码大致相同,只不过是在bind之前先start service ,大家可以在DDMS中看onUnbind() onRebind()的调用情况。本节代码在此下载:http://down.51cto.com/data/326376


相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

 
分享到
 
 
     


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...