精华内容
下载资源
问答
  • Tomcat内核详解(五):Server组件与Service组件
    千次阅读
    2018-08-01 08:33:16

    1.Server组件

    作为Tomcat最外层的核心组件,Server组件的作用主要有以下几个。

    • 提供了监听器机制,用于在Tomcat整个生命周期中对不同事件进行处理;
    • 提供了Tomcat容器全局的命名资源实现;
    • 监听某个端口以接收SHUTDOWN命令;

    1.生命周期监听器

    为了在Server组件的某阶段执行某些逻辑,于是提供了监听器机制。在Tomcat中实现一个生命周期监听器很简单,只要实现LifecycleListener接口即可,在lifecycleEvent方法中对感兴趣的生命周期事件进行处理。

    1. AprLifecycleListener监听器:

    通过JNI的方式调用本地库能够大幅的提高对静态文件的处理能力。

    该监听器会初始化APR库,假如能初始化成功,则会使用APR接受客户端的请求并处理请求。在Tomcat销毁后,该监听器会做APR的清理工作;

    1. JasperListener监听器:

    在Tomcat初始化前,该监听器会初始化Jasper组件,Jasper是Tomcat的JSP编译器核心引擎,用于在web应用启动之前初始化Jasper;

    1. JreMemoryLeakPreventionListener监听器:

    该监听器主要提供解决JRE内存泄露和锁文件的一种措施,该监听器会在Tomcat初始化的时候使用系统类加载器先加载一些类和设置缓存属性,以避免内存泄露的锁文件。

    内存泄露的根本原因在于当垃圾回收器要回收时候无法回收该被回收的对象。加入一个待回收的对象被另外一个生命周期很长的对象引用,那么这个对象将无法被回收;

    类加载器无法被回收将会导致内存泄露;

    JRE内存泄露与线程上下文类加载器有很大的关系。为了解决JRE内存泄露,尝试让系统类加载器加载这些特殊的JRE库类。

    在Tomcat启动的时候,先将当前线程的上下文类加载器设置为系统类加载器,再执行加载一些特殊类的动作,此时的线程上下文为系统类加载器,加载完这些特殊的类之后再将上下文类加载器还原。

    此时如果Web应用使用到这些类,由于它们已经加载到系统类加载器中,因此重启Web应用的时候不会存在内存泄露。

    JRE中存在内存泄露的类如下:(JRE库中这些类在运行的时候会以单例对象的形式存在,并且它们会存在很长一段时间,基本上是从Java程序启动到关闭,如果JRE库中的这些类使用上下文类加载器进行加载,并且保留了上下文类加载器的引用,所以将导致被应用的类加载器无法被回收,而Tomcat在重加载一个Web应用的时候正是通过实例化一个新的类加载器来实现的,旧的类加载器无法被垃圾回收器回收,导致内存泄露)

    DriverManager、javax.imageio.ImageIo、java.awt.Toolkit、sun.misc.GC、java.security.auth.Policy、java.security.auth.login.Configuration、java.security.Security、javax.xml.parsers.DocumentBuilderFactory、com.sun.jndi.ldapPoolManager

    【锁文件问题】

    锁文件的情景主要是由URLConnection默认的缓存机制导致,在Windows系统下当使用URLConnection的方式读取本地jar包里面的资源的时候,它会将资源内存缓存起来,这就导致了该JAR包被锁,如果重新部署将会失败,因为被锁文件无法删除;

    为了解决锁文件的问题,可以将URLConnection设置成为默认不缓存,而这个工作也交由JREMemoryLeakPreventionListener完成;

    1. GlobalResourcesLifecycleListener监听器:

    该监听器主要负责实例化Server组件里面JNDI资源的Mbean,并提交给JMX管理。此监听器对生命周期内的启动事件和停止事件感兴趣,它会在启动的时候为JNDI创建Mbean,在停止的时候销毁Mbean;

    1. ThreadLocalLeakPreventionListener监听器:

    该监听器主要解决ThreadLocal的使用可能带来的内存泄露问题。当web应用重新加载的时候,该监听器会将所有工作线程销毁并创建,以避免ThreadLocal引起内存泄露;

    ThreadLocal引起的内存泄露根本原因也是因为当垃圾回手器要回收的时候,无法进行回收,因为使用了ThreadLocal的对象被一个运行很长时间的线程引用,导致该对象无法被回收;

    解决ThreadLocal内存泄露的问题最彻底的方法就是当Web应用重新加载的时候,把线程池内的所有线程销毁并重新创建,这样就不会发生线程引用某些对象的问题了。

    Tomcat中处理ThreadLocal内存泄露的工作其实主要就是销毁线程池原来的线程,然后创建新的线程。这分为两个步骤:

    第一步:先将任务队列堵住,不让新的任务进来;

    第二步:将线程池中所有的线程停止;

    ThreadLocalLeakPreventionListener监听器的工作就是实现当Web应用重新加载的时候销毁线程池线程并重新创建新的线程,以此避免ThreadLocal内存泄露;

    1. NamingContextListener监听器:

    该监听器主要负责Server组件内全局命令资源在不同生命周期的不同操作,在Tomcat启动的时候创建命名资源、绑定命名资源,在Tomcat停止前解绑命名资源、反注册Mbean。

    2.全局命名资源

    在Tomcat启动的时候,通过Digester框架将server.xml的描述映射到对象,在Server组件中创建NamingResource和NamingContextListener两个对象。监听器将在启动初始化的时候利用ContextResource里面的属性创建命名上下文,并组织成树状;

    在Web应用中是无法访问全局命名资源的。因为要访问全局命名资源,所以这些资源都必须放置在Server组件中;

    3.监听SHUTDWON命令

    Server会另外开方一个端口用于监听关闭命令,这个端口默认是8005,此端口与接收客户端请求的端口并不是同一个。客户端传输的第一行如果能够匹配关闭命令(默认是SHUTDOWN),则整个Server将关闭;

    实现这个功能:

                       Tomcat中有两类线程,一类是主线程,另外一类是daemon线程。当Tomcat启动的时候,Server将被主线程执行,其实就是完成所有的启动工作,包括启动接收客户端和处理客户端报文的线程,这些线程都是daemon线程;。所有的启动工作完成之后,主线程将进入等待SHUTDOWN命令,它将不断尝试读取客户端发送过来的消息,一旦匹配SHUTDWON命令则跳出循环。主线程继续往下执行Tomcat的关闭工作。最后主线程结束,整个tomcat停止;

    2.Service组件

    Service组件是一个简单地组件,Service组件是若干Connector组件和Executor组件组合而成的概念。

    Connector组件负责监听某个端口的客户端请求,不同的端口对应不同的Connector。

    Executor组件在Service抽象层面提供了线程池,让Service下的组件可以通用线程池;

    使用池的技术:就是为了尽量的减少创建和销毁的连接操作;

    线程池技术:核心思想就是把运行阶段尽量的拉长,对于每个任务的到来,不是重复建立、销毁线程,而是重复利用之前的线程执行任务;

    其中一种解决方案就是在系统建立一定的数量的线程并做好线程维护工作,一旦有任务到来的时候,即从线程池中取出一条空闲的线程执行任务。原理听起来比较简单,但是现实中的对于一条线程,一旦调用start方法后,就将运行任务直到任务完成,随后JVM将对线程对象进行GC回收;

    所以需要换一种思维来解决问题,让这些线程启动之后通过一个无限循环来执行指定的任务。

    一个线程池的属性包含初始化线程数量、线程数组、任务队列。初始化线程数量指线程池初始化的线程数,线程数组保存了线程池中所有的线程,任务队列值添加到线程池中等待处理的所有任务。

    于是:线程池中的所有线程的任务就是不断检测任务队列并不断执行队列中的任务;

    【一个完善的线程池】

    需要提供启动、销毁、增加工作线程的策略,最大工作线程数、各种状态的获取等操作,而且工作线程也不可能始终做无用循环,需要对任务队列使用wait、notify优化,或者将任务队列改用为阻塞队列;

    【JDK的JUC工具包】优秀的并发程序工具包,仅仅线程池就已经提供了好多种类的线程池,实际开发中可以根据需求选择合适的线程池;

    了解了线程池的原理,其实我们并不提倡重复造轮子的行为。

    如果自己实现线程池,很容易产生死锁的问题,同时线程内的同步状态操作不当也可能会导致意想不到的问题;

    更多相关内容
  • service组件跟activity组件及其类似,可以说service是没有界面的activity, 当然service的生命周期和activity还是有一定的差别的。  service组件一般用在什么地方的,上面讲了service组件没有界面,不用跟用户...
  • Service组件代码

    2015-05-11 20:25:43
    android Service组件代码实验
  • Android-Service组件应用-模拟下载
  • Android下Service组件的简单使用,具体可以参见博客:http://www.cnblogs.com/plokmju/p/Android_Service1.html
  • 在进入应用程序时,只要点击登录,service组件启动播放音乐,想退出在登录界面和主界面点击手机返回键就会主动退出播放音乐。进入主界面就是记事本应用。
  • Service组件研究

    千次阅读 2016-11-16 16:04:20
    Android四大组件ServiceService启动过程1. 相关简介ActiveServices: 管理所有services 启动过程通过context->AMS->ActiveServices实现 通过ActivityThread的applicationThread实现 process的回调 ...

    Android四大组件之Service

    Service启动过程

    1. 相关简介

    ActiveServices: 管理所有services
    启动过程通过context->AMS->ActiveServices实现
    通过ActivityThread的applicationThread实现
    process的回调
    activityThread中的token为AMS中ProcessRecord的远端
    activityThread中有mServices存放了该进程下的所有service,以toke binder作为key,该token为AMS对应的ServiceRecord

    2. 流程

    Created with Raphaël 2.1.0 ContextImpl ContextImpl ActivityManagerService ActivityManagerService ActiveServices ActiveServices ActiveService ActiveService ActivityThread ActivityThread startService startService 传入ApplicationThread和userID startServiceLocked retrieveServiceLocked 在ActiveServices mServiceMap中是否存在该service,mServiceMap根据uid保存 startServiceInnerLocked bringUpServiceLocked 如果该进程已经存在,直接调用realStartServiceLocked,否则需要通过AMS启动新的进程 startProcessLocked main attachApplication attachApplicationLocked attachApplicationLocked realStartServiceLocked scheduleCreateService handleCreateService 加载service的class信息 serviceDoneExecuting serviceDoneExecutingLocked

    Service绑定过程

    1. 相关简介

    ServiceRecord: 描述一个正在运行的service,其中bindings描述目前绑在该service的intent集合
    connections存放所有的service connection
    ServiceRecord包含:
    - 一个IntentBindRecord的list,每个IntentBindRecord中存放了一个intent和对应的service的binder,以及以这个intent绑定的AppBindRecord的list
    - 一个ConnectionRecord的hashmap,该hashmap以ServiceConnection的binder对象为key,存放了以改binder绑定的CR对象。一个CR对象内部有一个AppBindRecord,activity以及ConnectionService对象(封装成了ServiceDispatcher)。
    IntentBindRecord: intent和service和app的绑定关系,存放了intent和service的对应关系,以及绑定在该service上的所有app和process
    AppBindRecord: 描述service和client的绑定关系,存放在IntentBindRecord
    ConnectionRecord: 描述一个service的绑定,包含activity信息等等。描述AppBindRecord到ServiceRecord的绑定关系。即使相同的AppBindRecord(app与service的一个绑定),activity不同也算两个ConnectionRecord,考虑到同一个ServiceConnection可能被不同的activity共用

    2. 流程

    Created with Raphaël 2.1.0 ContextImpl ContextImpl ActivityManagerService ActivityManagerService ActiveServices ActiveServices ServiceDispatcher ServiceDispatcher ServiceRecord ServiceRecord ActivityThread ActivityThread ActivityManagerServices ActivityManagerServices (LoadApk)InnerConnection (LoadApk)InnerConnection ServiceConnection ServiceConnection bindService bindServiceCommon bindService bindServiceLocked retrieveServiceLocked new 保存了service与intent,app,Process的对应关系 retrieveAppBindingLocked 保存app信息 bringUpServiceLocked realStartServiceLocked 此时Process已经启动,AMS中能获取到该Process,直接启动Service scheduleCreateService 新启动的Process的ActivityThread handleCreateService requestServiceBindingsLocked requestServiceBindingLocked 遍历绑定每个intent scheduleBindService handleBindService publishService publishServiceLocked 发布service,IntentBindRecord记录绑定成功 connected connected sd中的该handler在bindServiceCommon设过,为ActivityThread中的mH,因此会将RunConnection传递到activityThread中执行 doConnected onServiceConnected
    展开全文
  • Service组件暴露 - exported属性 1. android:exported 该属性用来标示,其他应用的组件是否可以唤醒Service或者和这个Service进行交互 true 表示可以 false 表示不可以,只有同一个应用的组件或者有着...

    Service组件暴露 - exported属性


    一、android:exported


    该属性用来标示,其他应用的组件是否可以唤醒Service或者和这个Service进行交互


    1. true

    表示可以


    2. false


    【1】表示不可以,只有同一个应用的组件或者有着同样user ID的应用可以启动这个Service或者绑定这个Service


    【2】关于user ID的参考链接


    http://yelinsen.iteye.com/blog/977683


    3. 默认值


    【1】 据当前Service是否有intent filter标签来定

    -  没有intent filter - 默认值为false

    没有任何的filter意味着这个Service只有在详细的描述了它的class name后才会被唤起,这表示当前Service只能在应用内部使用,因为其它应用程序并不知道这个class的存在,所以在这种情况下,它的默认值是false


    -  有intent filter - 默认值为true

    如果Service里面至少有一个filter的话,意味着该Service可以被外部应用使用,这个时候它的默认值是true


    4. 权限控制


    【1】不只有exported这个属性可以指定Service是否暴露给其它应用,也可以使用permission来限制外部实体唤醒当前Service


    【2】android:permission

      指定唤醒Service或与Service交互所需要的权限名称


    5. 参考链接


    http://blog.csdn.net/watermusicyes/article/details/46460347


    二、触发条件


    1. 定位AndroidManifest.xml文件中的Service组件


    【1】对应的特征:<service


    2. exported属性的判断


    【1】android:permission 如果设置权限控制,就认为不存在安全风险


    【2】exported属性设置为true

      显示设置 android:exported="true"

      默认值为true,也就是具有intent filter标签,对应的特征:<intent-filter


    三、漏洞原理


    【1】导出的Service组件可以被第三方APP任意调用,导致敏感信息泄露,并可能受到权限提升、拒绝服务等攻击风险


    【2】详细的原理&POC



    http://drops.wooyun.org/tips/4907


    四、修复建议


    【1】如果应用的Service组件不必要导出,或者组件配置了intent filter标签,建议显示设置组件的“android:exported”属性为false


    【2】如果组件必须要提供给外部应用使用,建议对组件进行权限控制


    展开全文
  • 这是自己学习android中service组件的代码,供以后查看用。
  • Android Service组件Demo

    2013-05-17 16:36:08
    Service组件使用的小例子,初学者可以参考下。其中AidlService工程里包含service;AidlServiceCaller是用来调用AidlService中service的客户端。程序比较简单,大家可以参考。
  • android中Service组件总结

    千次阅读 2015-12-15 22:23:14
    Server是android四大组件之一,它与Activity非常类似,最大的区别就是Activity在前台运行,主要作用于界面的交互,而server是在后台运行的一个服务,它没有界面。 Server的创建步骤: (1)定义一个继承Server的子类...

    Service是android四大组件之一,它与Activity非常类似,最大的区别就是Activity在前台运行,主要作用于界面的交互,而Service是在后台运行的一个服务,它没有界面。

    Service的创建步骤:

    (1)定义一个继承Service的子类;

    (2)在AndroidManifest.xml文件中配置该Service。

    与activity类似,Service也有自己的生命周期方法,具体如下:

         abstract IBinder onBind(Intent intent):该方法是重写Service必须实现的一个方法,方法中返回一个Binder对象,我们可以通过该Binder对象与Service进行通信。

         void onCreate ():当Service第一次被创建成功后,将会回调该方法,主要做一些初始化操作。

         void onDestroy():当Service被关闭之前会调用改方法,主要做一些Service的清理与保存工作。

         void onStartCommand():每次客户端调用startService(Intent)后方法启动Service时,Service都会回调改方法进行相关操作。

        boolean onUnbind():当绑定改Service上的所有客户端全都断开连接时,将会调用改回回调方法。

    下面举例子介绍一下Service组件的简单应用

    1、Service的创建、配置、启动与停止

    MyService类:这个类只是重写了一些方法,并打印一些log,为了清楚说明Service启动时的方法回调

    <span style="font-family:FangSong_GB2312;font-size:18px;">import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    
    public class MyService extends Service{
    	private String TAG = "MyService";
    	
    	//必须实现,返回IBinder对象,用于与Service组件进行通信,此处返回null,具体后面详细介绍
    	@Override
    	public IBinder onBind(Intent intent) {
    		return null;
    	}
    	
    	//Service被创建时回调的方法
    	@Override
    	public void onCreate(){
    		Log.i(TAG, "创建Service调用onCreate()");
    	}
    	
    	//Service被启动时回调的方法
    	@Override
    	public int onStartCommand(Intent intent, int flags, int startId){
    		Log.i(TAG, "启动Service调用onStartCommand");
             /*  
             * 这里返回状态有三个值,分别是:  
             * 1、START_STICKY:当服务进程在运行时被杀死,系统将会把它置为started状态,但是不保存其传递的Intent对象,之后,系统会尝试重新创建服务;  
             * 2、START_NOT_STICKY:当服务进程在运行时被杀死,并且没有新的Intent对象传递过来的话,系统将会把它置为started状态,  
             *   但是系统不会重新创建服务,直到startService(Intent intent)方法再次被调用;  
             * 3、START_REDELIVER_INTENT:当服务进程在运行时被杀死,它将会在隔一段时间后自动创建,并且最后一个传递的Intent对象将会再次传递过来。  
             */ 
    		return START_STICKY;
    	}
    
    	//Service销毁时回调的方法
    	@Override
    	public void onDestroy(){
    		super.onDestroy();
    		Log.i(TAG, "销毁Service调用onDestroy()");
    	}
    }</span>

    定义了Service之后需要在AndroidManifest.xml文件中配置该Service,即在AndroidManifest.xml文件中application标签内增加如下的配置片段来配置service:

    <span style="font-family:FangSong_GB2312;font-size:18px;"><!--  配置一个service组件 -->
            <service android:name=".MyService">
                <intent-filter>
                    <!-- 为该组件的intent-filter配置action -->
                    <action android:name="com.example.MY_SERVER"/>
                </intent-filter>
            </service></span>


    当service开发完成之后,接下来就可以在程序中运行service了,android中运行service有如下两种方法:

    1)通过Context的startService()方法来启动service,用该方法启动的service,访问者与改Service没有关联,当访问者退出了,Service仍然运行。

    2)通过Context的bindService()方法启动service,用该方法启动service,访问者与Service绑定在一起,访问者一旦退出,service也就终止。

    下面程序使用activity作为service的访问者,界面中有两个按钮,布局文件很简单,这里就不给出,一个按钮用于启动service,一个按钮用于关闭service

    代码如下MainActivity:

    <span style="font-family:FangSong_GB2312;font-size:18px;">public class MainActivity extends Activity implements OnClickListener{
    
    	private Button start_service;
    	private Button stop_service;
    	private TextView text;
    	private Intent intent;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    	private void initView() {
    		text = (TextView) findViewById(R.id.text);
    		start_service = (Button) findViewById(R.id.start_service);
    		stop_service = (Button) findViewById(R.id.stop_service);
    		start_service.setOnClickListener(this);
    		stop_service.setOnClickListener(this);
    		//创建启动service的Intent
    		intent = new Intent(MainActivity.this, MyService.class);
    	}
    	@Override
    	public void onClick(View v) {
    		switch(v.getId()){
    		case R.id.start_service:
    			//启动service
    			startService(intent);
    			text.setText("start_service");
    			break;
    		case R.id.stop_service:
    			//停止service
    			stopService(intent);
    			text.setText("stop_service");
    			break;
    		}
    	}
    }</span>
    activity的界面展示如下:


    点击“开启SERVER”按钮,控制台输出的log如下:


    再次点击“开启SERVER”按钮,控制台会打印启动"Service调用onStartCommand";

    点击“停止SERVICE”按钮,控制台会打印“销毁Service调用onDestroy()”。

    这里就不截图了,读者可以自己运行上面代码

    2、绑定本地的Service并与之通信

    在现实应用中,我们经常需要在Service执行一些操作,并在activity中获取操作的返回值,也就是要求能与Service进行通信。

    我们前面写的程序通过startService()和stopService()启动、关闭Service时,Service和访问者之间基本不存在太多的关联,因此Service和访问者之间也就无法进行通信和数据交换。

    如果我们需要访问者和Service之间能进行通信,则可以使用bindService()和unbindService()方法启动和关闭服务。

    bindService方法:bindService(Intent service, ServiceConnection conn, int flags),该方法有三个参数,下面对这三个参数逐一介绍:

    1)service:该参数通过Intent指向要启动的Service。

    2)conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当连接成功是会回调该对象的onServiceConnected(ComponentName name, IBinder service)方法,其中service就是Service类OnBind的返回值;当连接断开时将会回调该对象的onServiceDiscinnected(ComponentName name)方法。

    3)flags:指定绑定时是否自创建Service(如果Service还未创建)。0为不创建、BIND_AUTO_CREATE为自创建。

    注意上面第二个参数对象的onServiceConnected方法有个IBinder对象,该对象即可实现与绑定的Server进行通讯。

    在实际开发中,我们通常会继承Binder(IBinder的实现类)来实现自己的IBinder对象,下面我们来看一个实例:

    <span style="font-family:FangSong_GB2312;font-size:18px;">public class BindService extends Service{
    
    	private int count;
    	private boolean quit;
    	private MyBinder binder = new MyBinder();
    	public class MyBinder extends Binder{
    		public int getCount(){
    			//获取Service中的count
    			return count;
    		}
    	}
    	//必须实现的方法,返回IBinder对象
    	@Override
    	public IBinder onBind(Intent intent) {
    		
    		return binder;
    	}
    	@Override
    	public void onCreate() {
    		Log.i("BindService", "onCreate");
    		super.onCreate();
    		count = 0;
    		quit = false;
    		//启动一个线程,动态更新count的值
    		new Thread(){
    			@Override
    			public void run(){
    				while(!quit){
    					try {
    						Thread.sleep(1000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					count++;
    					//Log.i("BindService", count+"-------");
    				}
    			}
    		}.start();
    	}
    	
    	@Override
    	public boolean onUnbind(Intent intent) {
    		
    		return super.onUnbind(intent);
    	}
    	
    	@Override
    	public void onDestroy() {
    		this.quit = true;
    		super.onDestroy();
    	}
    }</span>
    上面的Service类中我们必须实现onBind方法返回一颗可以访问Service的count值得IBinder对象,该对象会被Service返回给调用者。在oncreate方法中,我们创建另一个线程,用时更新count的值。值得注意的事,由于server也是运行在主线程的,所以不能做耗时的操作,如果需要执行耗时的操作,需要创建子线程开完成。

    下面我们来看一下通过Activity绑定Service,具体代码如下:

    <span style="font-family:FangSong_GB2312;font-size:18px;">public class SeconActivity extends Activity implements View.OnClickListener{
    	private TextView text;
    	private Button bind;
    	private Button unbind;
    	private Intent intent;
    	private boolean quit = false;
    	private BindService.MyBinder binder;
    	private Handler hander = new Handler(){
    		@Override
    		public void handleMessage(Message msg) {
    			//收到消息后更新UI(关于Handler,后面的博客会具体讲解)
    			text.setText(msg.arg1+"");
    		}
    		
    	};
    	private ServiceConnection conn = new ServiceConnection() {
    		//访问者与Service连接成功时将回调此方法,得到IBinder对象来与Service进行通信
    		@Override
    		public void onServiceConnected(ComponentName name, IBinder service) {
    			Log.i("Activity", "---onServiceConnected----");
    			quit = true;
    			binder = (MyBinder) service;
    			//拿到binder后,启动一个新线程,来每个一秒从Service取出count的值
    			new Thread(action).start();
    			
    		}
    		//访问者与Service断开连接将回调此方法
    		@Override
    		public void onServiceDisconnected(ComponentName name) {
    			quit = false;
    			Log.i("Activity", "---onServiceDisconnected----");
    		}
    		
    		
    	};
    	private Runnable action = new Runnable() {
    		@Override
    		public void run() {
    			while(quit){
    				try {
    					Thread.sleep(1000);
    					if(binder != null){
    						//取到count值后,向主线程发送一个消息,让主线程来更新UI
    						Message message = new Message();
    						message.arg1 = binder.getCount();
    						hander.sendMessage(message);
    					}
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				
    			}
    		}
    	};
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_two);
            initView();
        }
    	private void initView() {
    		intent = new Intent();
    		intent.setAction("com.example.MY_SERVER");
    		bind = (Button) findViewById(R.id.bind);
    		unbind = (Button) findViewById(R.id.unbind);
    		text = (TextView) findViewById(R.id.text);
    		bind.setOnClickListener(this);
    		unbind.setOnClickListener(this);
    	}
    	@Override
    	public void onClick(View v) {
    		switch (v.getId()) {
    		case R.id.bind:
    			//绑定Service
    			if (!bindService(intent, conn, Service.BIND_AUTO_CREATE)) {
    	               Log.e("bindService", "Could not bind to Bluetooth AVRCP CT Service");
    	            }
    	            else
    	            {
    	                Log.d("bindService","bind successfully"+binder);
    	            }
    			//bindService(intent, conn, Service.BIND_AUTO_CREATE);
    			break;
    			
    		case R.id.unbind:
    			text.setText("取消绑定");
    			unbindService(conn);
    			break;
    
    		default:
    			break;
    		}
    	}
    }</span>

    代码中有详细的解释,大家可以研读一下。代码主要做的事情就是通过Activity绑定一个Service,然后通过得到的Binder来访问Service中的资源。

    对于Service的onBind()方法所返回的IBinder对象来讲,他可以被当成该Service组件遂返回的回调对象,Service允许客户端用户通过IBinder对象来访问内部的数据,这样就可以实现客户端与Service之间通信。

    3.跨进程调用Service

    Android中,各应用程序都运行在自己的进程中,进程之间一般无法直接进行数据交换的,我们上面是现在的代码是指Activity和Service在同一个进程,这样就可以方便的通信,可如果不在一个进程,那么要进行通信就不是那么容易了。

    android跨进程通信的方式很多,比如Bundle、文件共享、AIDL、Messenger、ContentProvider、Socket以及Broadcast方式。其中AIDL和Messenger用的是比较多的,他们都是基于binder实现的,具体细节这里就不多讲了,我以后会专门出类似的博客,请关注。

    由于AIDL比较复杂,这里我选用Messenger来实现跨进程Server通信,Messenger实际是对AIDL的一次封装。

    首先我们看一下服务端,我们创建一个Service来处理客户端请求,并且收到用户请求后向用户返回一条消息,具体代码如下:

    <span style="font-family:FangSong_GB2312;font-size:18px;">public class MessengerService extends Service{
    
    	private Handler MessengerHandler = new Handler(){
    
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case 1:
    				Log.i("MessengerService", msg.getData().getString("msg"));
    				//拿到客户端传过来的Messenger对象
    				Messenger client = msg.replyTo;
    				//封装要反悔给客户端的消息
    				Message replyMessage = Message.obtain(null, 2);
    				Bundle bundle = new Bundle();
    				bundle.putString("reply", "恩,收到您的消息!");
    				replyMessage.setData(bundle);
    				try {
    					//利用客户端的Messenger为客户端发送消息
    					client.send(replyMessage);
    				} catch (RemoteException e) {
    					e.printStackTrace();
    				}
    				break;
    
    			default:
    				super.handleMessage(msg);
    			}
    		}
    	};
    	//创建服务端Messenger
    	private final Messenger mMessenger = new Messenger(MessengerHandler);
    	@Override
    	public IBinder onBind(Intent intent) {
    		Log.i("Service", "onBind");
    		//向客户端返回Ibinder对象,客户端利用该对象访问服务端
    		return mMessenger.getBinder();
    	}
    	@Override
    	public void onCreate() {
    		Log.i("Service", "onCreate");
    		super.onCreate();
    	}
    }</span>
    然后注册Service,让其在单独的进程中运行

    <span style="font-family:FangSong_GB2312;font-size:18px;"><span style="white-space:pre">	</span><service android:name=".Messager.MessengerService"
                 android:process=":remote">  
                <intent-filter>
                    <action android:name="com.example.MESSENGER_SERVER"/>  
                </intent-filter>  
            </service> </span>
    接下来就看客户端了,客户端实现也比较简单,首先绑定远程进程的Service,绑定成功后,根据Service返回的IBinder对象创建Messenger对象,并使用此对象发送消息,为了能收到Service端返回的消息,客户端创建了一个资深的Messenger发送给Service端,Service端就可以通过客户端的Messenger想客户端发送消息了,具体代码如下:

    <span style="font-family:FangSong_GB2312;font-size:18px;">public class MessengerActivity extends Activity{
    
    	private Messenger mService;
    	private Button bind;
    	private TextView text;
    	private Intent intent;
    	private ServiceConnection conn = new ServiceConnection(){
    		@Override
    		public void onServiceConnected(ComponentName name, IBinder service) {
    			//根据得到的IBinder对象创建Messenger
    			mService = new Messenger(service);
    			Message msg = Message.obtain(null, 1);
    			Bundle bundle = new Bundle();
    			bundle.putString("msg", "您好,Service");
    			msg.setData(bundle);
    			msg.replyTo = mGetMessenger;
    			try {
    				mService.send(msg);
    			} catch (RemoteException e) {
    				e.printStackTrace();
    			}
    		}
    		@Override
    		public void onServiceDisconnected(ComponentName name) {
    			
    		}	
    	};
    	
    	//为了收到Service的回复,客户端需要创建一个接收消息的Messenger和Handler
    	private Handler MessengerHander = new Handler(){
    		@Override
    		public void handleMessage(Message msg) {
    			switch (msg.what) {
    			case 2:
    				Log.i("MessengerActivity", msg.getData().getString("reply"));
    				text.setText(msg.getData().getString("reply"));
    				break;
    			default:
    				super.handleMessage(msg);
    			}
    		}
    	};
    	private Messenger mGetMessenger = new Messenger(MessengerHander);
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_messenger);
    		init();
    	}
    	private void init() {
    		intent = new Intent(MessengerActivity.this, MessengerService.class);
    		bind = (Button) findViewById(R.id.bind);
    		text = (TextView) findViewById(R.id.text);
    		bind.setOnClickListener(new View.OnClickListener() {
    			@Override
    			public void onClick(View v) {
    				
    				//bindService(intent, conn, Context.BIND_AUTO_CREATE);
    				if (!bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
    		               Log.e("bindService", "Could not bind to Bluetooth AVRCP CT Service");
    		            }
    		            else
    		            {
    		                Log.d("bindService","bind successfully");
    		            }
    			}
    		});
    	}
    	@Override
    	protected void onDestroy(){
    		unbindService(conn);
    		super.onDestroy();
    	}
    }
    </span>
    代码看起来比较长,可是很简单,相信读者都能读懂。我们运行程序后,看一下log,很闲人客户端向Service发送了一条消息,也收到了Service返回的消息,这说明我们跨进程和Service通信实现成功。



    到这里,android的四大组件之一Service就介绍完毕,谢谢大家的阅读!









    展开全文
  • Service组件(本地、远程调用)详解

    千次阅读 2015-12-14 17:22:33
    一、Service组件使用介绍 service组件的使用分为两种,一种是远程调用(夸进程);另一种本地调用(同进程)。 Android系统中,各应用程序都运行在自己的进程中,进程之间一般无法进行数据交换。 Android远程调用...
  • Android_Service组件

    2014-06-27 17:29:43
    Android_Service组件测试。一般用法,IntentService用法。很好的资源哦!
  • 摘要:C#源码,菜单窗体,IIS C#使用ServiceController组件计算机的服务,示例使用 ServiceController 类检查警报器服务是否已停止。如果该服务已停止,此示例将启动该服务并等待服务状态设置为 Running。  使用 ...
  • Android 四大组件Service的详解

    千次阅读 2021-04-11 20:07:04
    Service是android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。 作用:提供 需在后台...
  • service的启动,停止,绑定,取消绑定,以及IntentService的生命周期走向测试和IntentService与访问者信息通信过程,不清楚之处请参阅我的博客《Android开发四大组件Service总结》
  • 默认情况下,无论是通过startService还是bindService启动同一Application的Service组件,都是运行在该Application的同一进程中。然而,很多时候我们希望该Service组件可以运行在不同的进程中,这样的目的往往是为了...
  • 主要介绍了Angular5.0 子组件通过service传递值给父组件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 【安卓笔记】全面解析Service组件

    千次阅读 2014-02-17 14:38:38
    service,android四大组件之一,是一个长期运行在应用后台的android组件,它没有与用户交互的界面。 service的特点是: 1.长期运行在后台; 2.其他组件可以通过绑定操作与service进行交互; 3.默认运行在UI线程上;...
  • Android四大组件ServiceService的生命周期被启动(startService)的服务的生命周期:被绑定(bindService)的服务的生命周期:被启动又被绑定的服务的生命周期:实例布局创建Service类启动ServiceDemo下载 android开发...
  • android service 四大组件 完整代码 非常好用 非常经典 完整的代码.
  • Service的线程和工作线程是一回事吗?使用Service需要权限吗?安卓系统提供了哪些可以使用的系统级的Service呢?本文将为你回答这些看上去简单但是确很实用的问题。
  • 主要介绍了Android实现Activity、Service与Broadcaster三大组件之间互相调用的方法,结合实例形式详细分析了Activity、Service与Broadcaster三大组件相互调用的原理,实现方法与相关注意事项,需要的朋友可以参考下
  • 今天小编就为大家分享一篇关于Android四大组件Service详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • springboot扫描引入jar包的service组件

    千次阅读 2019-12-02 17:21:30
    像上面这种包组织的话,是不需要额外加入任何配置的(前提是依赖jar包相应组件一定要有@Component等注解修饰),因为springboot项目默认扫描目录就是Application所在目录及子目录,但是这种情况仅限于单个项目安排,...
  • Android开发四大组件Service(实例篇)

    千次阅读 多人点赞 2014-07-21 17:10:27
    关于Service的开发详解已经在上一篇:Android开发四大组件Service(详解篇)讲的很清楚了,本篇主要对Service的开发实例做下讲解。
  • 在这些组件之间的通讯中,主要是由Intent协助完成的。 Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成...
  •  Service为Android四大组件之一,Service与Activity组件相似,都代表可执行的程序且有自己的生命周期,唯一的区别是Activity组件提供界面方便人机交互而Service只在后台运行且没有交互界面。Service

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 483,277
精华内容 193,310
关键字:

service组件

友情链接: cclog.rar