Service的一些知识点

参考资料

Android Service完全解析,关于服务你所需知道的一切(上)
Android中的Service相关全面总结
Android开发实践:使用Service还是Thread

作用

它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。

启动方式
  • startService()

    会依次调用onCreate()onStartCommand()onCreate()只会在第一次启动时被调用,多次启动只会调用onStartCommand()
  • bindSerivce()

    会依次调用onCreate(),onBind()。多次调用,不会回调任何方法。
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    public class MyBinder extends Binder {
    }
销毁
  • stopService()
    多次调用会造成闪退。
  • unBindService()
    多次调用unBindService()会造成闪退。IllegalArgumentException: Service not registered

如果既点击了Start Service按钮,又点击了Bind Service按钮,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。才会调用onDestory()方法

与Acitivty通信

只有bindService()才能与Activity进行通信

private ServiceConnection connection = new ServiceConnection() {  
        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }   
        @Override  
        public void onServiceConnected(ComponentName name, IBinder service){  
            myBinder = (MyService.MyBinder) service;  
            myBinder.startDownload();  
        }  
    };  
更新Activity

使用BroadcastReceiver

与Thread 的关系
  • Service
    • 运行在UI Thread (如果处理耗时操作会造成ANR),应该在Service再创建Thread 。
    • Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
    • 即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例,而线程不行。
  • Thread

    • Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

    既然这样,那么我们为什么要用 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

     @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 开始执行后台任务  
            }  
        }).start();  
        return super.onStartCommand(intent, flags, startId);  
    }  
    class MyBinder extends Binder {  
        public void startDownload() {  
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    // 执行具体的下载任务  
                }  
            }).start();  
        } 
    }
前台Service

Service几乎都是在后台运行的,一直以来它都是默默地做着辛苦的工作。但是Service的系统优先级还是比较低的,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。如果你希望Service可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。前台Service和普通Service最大的区别就在于,它会一直有一个正在运行的图标在系统的状态栏显示

远程Service(Remote)
与本地Service的关系(Local)
类别区别优点缺点应用
本地Service依附在主进程上服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。非常常见的应用如:HTC的音乐播放服务,天天动听音乐播放服务。
远程Service有独立的进程服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。一些提供系统服务的Service,这种Service是常驻的。多个应用可以使用同一个Service
关键代码
在本应用内访问
  • 注册Service的时候将它的android:process属性指定成:remote
  • 使用AIDL(Android Interface Define Language)进行IPC(Inter-Process Communication,进程间通信)
    1.新建MyAIDLService.aidl文件
    interface MyAIDLService {  
    String toUpperCase(String str);  
    }

2.在MyService中,在里面实现我们刚刚定义好的MyAIDLService接口,如下所示

public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    //Stub是Binder的子类,Binder是IBinder的实现
    MyAIDLService.Stub mBinder = new Stub() {
        public String toUpperCase(String str) throws RemoteException {
        return str.toUpperCase();
        }
    };
} 

3.在Activity中实现这样的一个ServiceConnection

  private ServiceConnection connection = new ServiceConnection() {  

        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  

        @Override  
        public void onServiceConnected(ComponentName name, IBinder service){  
            myAIDLService = MyAIDLService.Stub.asInterface(service);  
            try { 
                String upperStr = myAIDLService.toUpperCase("hello world");          
                Log.d("TAG", "upperStr is " + upperStr);  
            } catch (RemoteException e) {  
                e.printStackTrace();  
            }  
        }  
    };
一个应用程序去访问另一个应用程序中的Service

1.注册Service时

 <service
    android:name=".MyService"
    android:exported="true" >//不加的话找到这个acition
        <intent-filter>
            <action android:name="com.example.servicetest.MyAIDLService"/>
        </intent-filter>
</service>

2.另外一个应用程序的Activity如果想要和MyService建立关联,首先需要将MyAIDLService.aidl文件从ServiceTest项目中拷贝过来,注意要将原有的包路径一起拷贝过来
3.另外一个应用程序的Activity实现这样的一个ServiceConnection

private ServiceConnection connection = new ServiceConnection() {  

        @Override  
        public void onServiceDisconnected(ComponentName name) {  
        }  

        @Override  
        public void onServiceConnected(ComponentName name, IBinder service){  
            myAIDLService = MyAIDLService.Stub.asInterface(service);//关键代码  
            try {  
                String upperStr = myAIDLService.toUpperCase("comes from ClientTest");
                Log.d("TAG", "upperStr is " + upperStr);  
            } catch (RemoteException e) {  
                e.printStackTrace();  
            }  
        }  
    };  

4.另外一个应用程序的Activity绑定Service

 Intent intent = new Intent("com.example.servicetest.MyAIDLService");  
 bindService(intent, connection, BIND_AUTO_CREATE);  
IntentService
  • It can’t interact directly with your user interface. To put its results in the UI, you have to send them to an Activity.
  • Work requests run sequentially. If an operation is running in an IntentService, and you send it another request, the request waits until the first operation is finished.
  • An operation running on an IntentService can’t be interrupted.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值