稳扎稳打_Android开发课[5]_Service学习

步步为营_Android开发课[5]_Service学习

Focus on technology, enjoy life!—— QQ:804212028
浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305


  • 主题:Service服务相关内容
    -Android开发中Service服务是非常重要滴,也是有一定难度滴,不怕,我们一起一步一步来看:

一、 Service简介

Service是android系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。
Service的启动有两种方式:context.startService() 和 context.bindService()

二、如何开发一个Service组件?

第一步:继承Service类 public class SMSService extends Service {}
第二步:在AndroidManifest.xml文件中的节点里对服务进行配置:
第三步:启动服务

启动服务方法一:context.startService():调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
步骤:

context.startService() 启动流程: context.startService() -> onCreate()
-> onStart() -> Service running -> context.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():调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点

context.bindService()启动流程: context.bindService() -> onCreate() ->
onBind() -> Service running -> onUnbind() -> 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生命周期

Service生命周期很简单,它只继承了onCreate()、onStart()、onDestroy()三个方法
当我们第一次启动Service时,先后调用了onCreate()、onStart()这两个方法;当停止Service时,则执行onDestroy()方法。
这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。
它可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己,无论调用了多少次的启动服务方法,只要调用一次stopService()方法便可以停止服务。

onCreate():
该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。
onDestroy():
该方法在服务被终止时调用。与采用Context.startService()方法启动服务有关的生命周期方法
onStart():
只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
onBind():
只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
onUnbind():
只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用

生命周期图:
稳扎稳打_Android开发课[5]_Service学习

四:Service和Thread的区别?

答:servie是系统的组件,它由系统进程托管(service manager);它们之间的通信类似于client和server,是一种轻量级的ipc通信,这种通信的载体是binder,它是在linux层交换信息的一种ipc。而thread是由本应用程序托管。

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使用实例(用Service后台播放音乐)

main.xml文件的源码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView  
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:text="Welcome to Andy's blog!"
       android:textSize="16sp"/>   
    <TextView  
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:text="音乐播放服务"/>
    <Button
       android:id="@+id/startMusic" 
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="开启音乐播放服务"/>
    <Button
       android:id="@+id/stopMusic" 
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="停止音乐播放服务"/>
   <Button
      android:id="@+id/bindMusic" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="绑定音乐播放服务"/>
   <Button
      android:id="@+id/unbindMusic" 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="解除 ——绑定音乐播放服务"/>
</LinearLayout>

MusicServiceActivity源码:

package com.example.service;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MusicServiceActivity extends Activity {

    //为日志工具设置标签
    private static String TAG = "--------------";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //输出Toast消息和日志记录
        Toast.makeText(this, "MusicServiceActivity",
                Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicServiceActivity");

        initlizeViews();
    }

    private void initlizeViews(){
        Button btnStart = (Button)findViewById(R.id.startMusic);
        Button btnStop = (Button)findViewById(R.id.stopMusic);
        Button btnBind = (Button)findViewById(R.id.bindMusic);
        Button btnUnbind = (Button)findViewById(R.id.unbindMusic);

        //定义点击监听器
        OnClickListener ocl = new OnClickListener() {

            @Override
            public void onClick(View v) {
                //显示指定  intent所指的对象是个   service
                Intent intent = new Intent(MusicServiceActivity.this,MusicService.class);
                switch(v.getId()){
                case R.id.startMusic:
                    //开始服务
                    startService(intent);
                    break;
                case R.id.stopMusic:
                    //停止服务
                    stopService(intent);
                    break;
                case R.id.bindMusic:
                    //绑定服务
                    bindService(intent, conn, Context.BIND_AUTO_CREATE);
                    break;
                case R.id.unbindMusic:
                    //解绑服务
                    unbindService(conn);
                    break;
                }
            }
        };

         //绑定点击监听
        btnStart.setOnClickListener(ocl);
        btnStop.setOnClickListener(ocl);
        btnBind.setOnClickListener(ocl);
        btnUnbind.setOnClickListener(ocl);
    }

    //定义服务链接对象
    final ServiceConnection conn = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Toast.makeText(MusicServiceActivity.this, "MusicServiceActivity onSeviceDisconnected"
                    , Toast.LENGTH_SHORT).show();
            Log.e(TAG, "MusicServiceActivity onSeviceDisconnected");
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Toast.makeText(MusicServiceActivity.this, "MusicServiceActivity onServiceConnected"
                    ,Toast.LENGTH_SHORT).show();
            Log.e(TAG, "MusicServiceActivity onServiceConnected");
        }
    };
}

MusicService.java源码:

package com.example.service;
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 {
    //为日志工具设置标签
    private static String TAG = "--------------";
    //定义音乐播放器变量
    private MediaPlayer mPlayer;

    //该服务不存在需要被创建时被调用,不管startService()还是bindService()都会启动时调用该方法
    @Override
    public void onCreate() {
        Toast.makeText(this, "MusicSevice onCreate()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onCreate()");

        mPlayer = MediaPlayer.create(getApplicationContext(), R.raw.music);
        //设置可以重复播放
        mPlayer.setLooping(true);
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Toast.makeText(this, "MusicSevice onStart()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onStart()");

        mPlayer.start();

        super.onStart(intent, startId);
    }
    @Override
    public void onDestroy() {
        Toast.makeText(this, "MusicSevice onDestroy()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onDestroy()");

        mPlayer.stop();

        super.onDestroy();
    }
    //其他对象通过bindService 方法通知该Service时该方法被调用
    @Override
    public IBinder onBind(Intent intent) {
        Toast.makeText(this, "MusicSevice onBind()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onBind()");

        mPlayer.start();

        return null;
    }
    //其它对象通过unbindService方法通知该Service时该方法被调用
    @Override
    public boolean onUnbind(Intent intent) {
        Toast.makeText(this, "MusicSevice onUnbind()"
                , Toast.LENGTH_SHORT).show();
        Log.e(TAG, "MusicSerice onUnbind()");

        mPlayer.stop();

        return super.onUnbind(intent);
    }

}

最后在AndroidManifest.xml配置文件中添加对Service的注册

    <service android:name=".MusicService"/> 

就算我们退出程序回到手机主界面,由于该服务还在后台运行着,音乐还是不会停止播放,这样我们就可以边听歌曲,边聊QQ了。

Focus on technology, enjoy life!—— QQ:804212028
浏览链接:http://blog.csdn.net/y18334702058/article/details/44624305