zoukankan      html  css  js  c++  java
  • Android 四大组件之Service

    什么是Service?

    Service是能够在后台执行长时间运行操作并且不提供用户界面的应用程序组件。(简单来说,Service就是提供服务的代码,这些代码最终体现为一个个的接口函数。所以,Service就是实现一组函数的对象,通常也称为组件。)它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() Context.bindService()

    为什么要用Service?

    Service不是进程,也不是线程。
    处理耗时操作,需开启子线程。
    Service一般是运行在主线程的,可以通过在主线程和Service都打印Thread.currentThread().getId()验证。
    具体使用在:比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等。
     
    Service的分类:
    Service按启动方法分类分为两种,它们的区别如下:
    启动方法 Activity与Service 是否返回值 何时被动终止 手动关闭
    startService 没有关系 Activity退出,仍运行 stopService或stopSelf(只有intent执行完才行停止掉)
    bindService 可以有多个Acyivity绑定 是,可以IPC通信 所有绑定Activity退出,才退出??? 同上

    要想正确使用Service,必须熟知Service的启动流程,具体如下:

    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()  -> 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在一个生命周期中只能被调用一次。

    PS: onStart()  虽仍能使用,但它已被抛弃,被onStartCommand所取代。

    下面我们用图的形式来了解Service的生命周期:

    这里要说明一下的是如果你在ServiceonCreate或者onStart做一些很耗时间的事情,最好在Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。

    下面,我们分别用不同方式启动的Service举一个例子:

    先用context.startService() 这种方式做一个背景音乐,在界面上有两个button,控制背景音乐的开关:

    创建一个MusicService.java继承Service。

    public class MusicService extends Service {
        private static MediaPlayer mediaPlayer;
    
        @Override
        public void onStart(Intent intent, int startId) {
            // TODO Auto-generated method stub
            super.onStart(intent, startId);
            System.out.println("onStart");
            // 设置音乐循环
            mediaPlayer.setLooping(true);
            if (!mediaPlayer.isPlaying())
                mediaPlayer.start();
        }
    
        @Override
        public void onCreate() {
            System.out.println("onCreate");
            mediaPlayer = MediaPlayer.create(this, R.raw.begin_music);
            super.onCreate();
        }
    
        @Override
        public void onDestroy() {
            System.out.println("onDestroy");
            super.onDestroy();
            mediaPlayer.stop();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            System.out.println("onBind");
            return null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            System.out.println("onStartCommand");
            return super.onStartCommand(intent, flags, startId);
        }
    
    }

    在MainActivity中的代码为:

    public class MainActivity extends Activity {
        final int RIGHT = 0;
        final int LEFT = 1;
        private GestureDetector gestureDetector;
        private Intent intent;
    
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            intent = new Intent("com.topcsa.test.music");
            startService(intent);
            Button btn_close=(Button) findViewById(R.id.btn_close);
            Button btn_start=(Button) findViewById(R.id.btn_start);
            btn_close.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    
                    stopService(new Intent(MainActivity.this,MusicService.class));
                    
                }
            });
            btn_start.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    startService(new Intent(MainActivity.this,MusicService.class));
                    
                }
            });
    
            
        }
    
        @Override
        protected void onDestroy() {
            stopService(new Intent(MainActivity.this,MusicService.class));
            super.onDestroy();
        }
        
    
    }

    记住在Activity的onDestroy中停止服务,否则即使退出当前应用,Service依然在后台执行并播放音乐。(这种方式中,Activity启动服务后就与Service几乎没有关系了,所以必须要手动关闭Service)

    注意:一定不要忘记注册Service

    <service android:name="com.example.test_android.MusicService">
                <intent-filter >
                    <action android:name="com.topcsa.test.music"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
            </service>

     该程序的运行结果为:

    刚打开应用时的结果为(此时,音乐已开始播放):

     第一次点击打开背景音乐的button时,结果为(音乐正常播放,无停顿、异常):

    此时未运行onCreate方法,但执行了onStartCommand()、onStart()方法。

    接下来,第一次点击关闭背景音乐的button,结果为(音乐被关闭):

    此时执行了onDestroy()方法。

    接下来,我们再点击打开背景音乐的button,结果为(音乐再次打开):

    此时,执行了onCreate()方法。

    下面我们通过一个例子来了解了解context.bindService()的使用:

    main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    
        <Button 
            android:id="@+id/start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="启动服务"/>
        <Button 
            android:id="@+id/stop"
            android:layout_width="wrap_content"
            android:layout_below="@id/start"
            android:layout_height="wrap_content"
            android:text="停止服务"/>
        <Button 
            android:id="@+id/bind"
            android:layout_below="@id/stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="绑定服务"/>
         <Button 
            android:id="@+id/unbind"
            android:layout_below="@id/bind"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="解除绑定服务"/>
    
    </RelativeLayout>
    MusicService.java
    public class MusicService extends Service {
        private static MediaPlayer mediaPlayer, mediaPlayer2;
        Intent intent;
        private IBinder myBinder = new IBinder() {
    
            @Override
            public String getInterfaceDescriptor() throws RemoteException {
    
                return "My Service class";
            }
    
            @Override
            public boolean pingBinder() {
                // TODO Auto-generated method stub
                return false;
            }
    
            @Override
            public boolean isBinderAlive() {
                // TODO Auto-generated method stub
                return false;
            }
    
            @Override
            public IInterface queryLocalInterface(String descriptor) {
                // TODO Auto-generated method stub
                return null;
            }
    
            @Override
            public void dump(FileDescriptor fd, String[] args)
                    throws RemoteException {
                // TODO Auto-generated method stub
    
            }
    
            @Override
            public void dumpAsync(FileDescriptor fd, String[] args)
                    throws RemoteException {
                // TODO Auto-generated method stub
    
            }
    
            @Override
            public boolean transact(int code, Parcel data, Parcel reply, int flags)
                    throws RemoteException {
                // TODO Auto-generated method stub
                return false;
            }
    
            @Override
            public void linkToDeath(DeathRecipient recipient, int flags)
                    throws RemoteException {
                // TODO Auto-generated method stub
    
            }
    
            @Override
            public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
                // TODO Auto-generated method stub
                return false;
            }
    
        };
    
        @Override
        public void onStart(Intent intent, int startId) {
            // TODO Auto-generated method stub
            super.onStart(intent, startId);
            System.out.println("onStart");
    
        }
    
        @Override
        public void onCreate() {
            System.out.println("onCreate");
            mediaPlayer = MediaPlayer.create(this, R.raw.begin_music);
            super.onCreate();
        }
    
        @Override
        public void onDestroy() {
            System.out.println("onDestroy");
            super.onDestroy();
            mediaPlayer.stop();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            System.out.println("onBind");
            return null;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            System.out.println("onUnbind");
            return super.onUnbind(intent);
        }
    
        @Override
        public void onRebind(Intent intent) {
            System.out.println("onRebind");
            super.onRebind(intent);
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            System.out.println("onStartCommand");
            if (!mediaPlayer.isPlaying())
                mediaPlayer.start();
            mediaPlayer.setLooping(true);// 设置音乐循环
            return Service.START_CONTINUATION_MASK;
        }
    
    }

    MainActivity.java:

    public class MainActivity extends Activity {
        final int RIGHT = 0;
        final int LEFT = 1;
        private GestureDetector gestureDetector;
        private Intent intent;
        boolean tag=false;
    
        private ServiceConnection sercon = new ServiceConnection() {
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                System.out.println("onServiceDisconnected");
    
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                try {
                    System.out.println("onServiceConnected service="
                            + service.getInterfaceDescriptor());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
    
            }
        };
    
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            startService(new Intent(MainActivity.this, MusicService.class));
            Button btn_close = (Button) findViewById(R.id.stop);
            Button btn_start = (Button) findViewById(R.id.start);
            Button btn_bind = (Button) findViewById(R.id.bind);
            Button btn_unbind = (Button) findViewById(R.id.unbind);
            btn_close.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
    
                    stopService(new Intent(MainActivity.this, MusicService.class));
    
                }
            });
            btn_start.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    startService(new Intent(MainActivity.this, MusicService.class));
    
                }
            });
            btn_bind.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    tag=true;
                    bindService(new Intent(MainActivity.this, MusicService.class),
                            MainActivity.this.sercon, Context.BIND_AUTO_CREATE);
    
                }
            });
            btn_unbind.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    if(tag)
                    unbindService(MainActivity.this.sercon);
                    tag=false;
                }
            });
    
        }
    
    }

    运行程序可知:

    程序启动时:onCreate、onStartCommand

    点击第一个启动服务按钮:onStartCommand

    点击第二个停止服务按钮:onDestroy

    点击第三个绑定服务按钮:onCreate、onBind

    点击第三个解除绑定服务时:onUnbind、onDestroy

    推荐文献:http://blog.csdn.net/androiddevelop/article/details/14498193         http://www.cnblogs.com/allin/archive/2010/05/15/1736458.html

          http://blog.csdn.net/ithomer/article/details/7364024

  • 相关阅读:
    Minimum Sum of Array(map迭代器)
    stl库中的map (反向迭代器)以及例题
    stl库中反转的函数
    如何使用java中的对象
    java中的成员变量和局部变量
    java中的构造方法
    static使用之静态变量
    什么是类和对象
    如何定义java中的类
    css让图片作为按钮的背景并且大小合适
  • 原文地址:https://www.cnblogs.com/scetopcsa/p/af74776.html
Copyright © 2011-2022 走看看