美文网首页Andoid
Service 拾遗

Service 拾遗

作者: Haraway | 来源:发表于2017-04-27 14:32 被阅读0次

    Service的适用场景应该具备以下条件:

    1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);

    2.具有较长时间的运行特性。

    1.Service AndroidManifest.xml 声明
    一般而言,从Service的启动方式上,可以将Service分为Started Service和Bind Service。无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来。在使用Service时,要想系统能够找到此自定义Service,无论哪种类型,都需要在AndroidManifest.xml中声明,语法格式如下:

    <service android:enabled=["true" | "false"]
        android:exported=["true" | "false"]
        android:icon="drawable resource"
        android:isolatedProcess=["true" | "false"]
        android:label="string resource"
        android:name="string"
        android:permission="string"
        android:process="string" >
        . . .
    </service>
    

    2.Started Service

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private final static String TAG = "MainActivity";
    
        //定义一个全局变量用来标记
        private boolean isConnected = false;
    
        private Button startService;
    
        private Button stopService;
    
        @Override  
        public void onCreate() {  
            super.onCreate();  
            Log.d(TAG, "onCreate() executed");  
        }  
      
        @Override  
        public int onStartCommand(Intent intent, int flags, int startId) {  
            Log.d(TAG, "onStartCommand() executed");  
            return super.onStartCommand(intent, flags, startId);  
        }  
          
        @Override  
        public void onDestroy() {  
            super.onDestroy();  
            Log.d(TAG, "onDestroy() executed");  
        }  
      
        @Override  
        public IBinder onBind(Intent intent) {  
            return null;  
        }  
    }  
    

    其中,onBind(...)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。onCreate(...)、onStartCommand(...)和onDestroy()都是Started Service相应生命周期阶段的回调函数。

    当启动一个Service的时候,会调用该Service中的onCreate()和onStartCommand()方法。onCreate()方法只会在Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行。

    package com.demo.xp;
    
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.IBinder;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    import com.demo.xp.service.TestService;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private final static String TAG = "MainActivity";
    
        //定义一个全局变量用来标记
        private boolean isConnected = false;
    
        private Button startService;
    
        private Button stopService;
    
        private Button bindService;
    
        private Button unbindService;
    
        private TestService.TestBinder testBinder;
    
        private ServiceConnection connection = new ServiceConnection() {
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                testBinder = (TestService.TestBinder) service;
                testBinder.startDownload();
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            startService = (Button) findViewById(R.id.start_service);
            stopService = (Button) findViewById(R.id.stop_service);
            bindService = (Button) findViewById(R.id.bind_service);
            unbindService = (Button) findViewById(R.id.unbind_service);
            startService.setOnClickListener(this);
            stopService.setOnClickListener(this);
            bindService.setOnClickListener(this);
            unbindService.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.start_service:
                    Intent startIntent = new Intent(this, TestService.class);
                    startService(startIntent);
                    break;
                case R.id.stop_service:
                    Intent stopIntent = new Intent(this, TestService.class);
                    stopService(stopIntent);
                    break;
                case R.id.bind_service:
                    Intent bindIntent = new Intent(this, TestService.class);
                    //在bindService处添加
                    isConnected=bindService(bindIntent, connection, BIND_AUTO_CREATE);
                    break;
                case R.id.unbind_service:
                    if(isConnected){
                        unbindService(connection);
                        isConnected = false;
                    }
                    break;
                default:
                    break;
            }
        }
    
    }
    

    首先创建了一个ServiceConnection的匿名类,在里面重写了onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在Activity与Service建立关联和解除关联的时候调用。在onServiceConnected()方法中,我们又通过向下转型得到了MyBinder的实例,有了这个实例,Activity和Service之间的关系就变得非常紧密了。现在我们可以在Activity中根据具体的场景来调用MyBinder中的任何public方法,即实现了Activity指挥Service执行指定功能。

    1. Started Service生命周期及进程相关

    1.onCreate(Client首次startService(..)) >> onStartCommand >> onStartCommand - optional ... >> onDestroy(Client调用stopService(..))

    注:onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。

    2.对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。

    3.Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。

    4.Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。

    5.Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。

    6.startService(Intent serviceIntent),其中的intent既可以是显式Intent,也可以是隐式Intent,当Client与Service同处于一个App时,一般推荐使用显示Intent。当处于不同App时,只能使用隐式Intent。

    当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。

    3.Bound Service

    Bound Service的主要特性在于Service的生命周期是依附于Client的生命周期的,当Client不存在时,Bound Service将执行onDestroy,同时通过Service中的Binder对象可以较为方便进行Client-Service通信。Bound Service一般使用过程如下:

    1.自定义Service继承基类Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象;

    2.Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;

    3.自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;

    4.通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;

    5.当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc)。

    在Bound Service具体使用过程中,根据onBind(Intent intent)方法放回的Binder对象的定义方式不同,又可以将其分为以下三种方式,且每种方式具有不同的特点和适用场景:

    1).Extending the Binder class

    这是Bound Service中最常见的一种使用方式,也是Bound Service中最简单的一种。

    局限:Clinet与Service必须同属于同一个进程,不能实现进程间通信(IPC)。否则则会出现类似于“android.os.BinderProxy cannot be cast to xxx”错误。
    参考:
    Android总结篇系列:Android Service
    Android Service完全解析,关于服务你所需知道的一切(上)
    java.lang.IllegalArgumentException: Service not registered
    android service Dialog 弹出框
    在Service中弹出对话框
    Android Service前台服务的使用
    Android Service与Activity之间通信的几种方式

    相关文章

      网友评论

        本文标题:Service 拾遗

        本文链接:https://www.haomeiwen.com/subject/puogzttx.html