service_services - CSDN
精华内容
参与话题
  • service层的作用

    千次阅读 2014-10-12 13:04:34
    1,dao和service对应 一般情况下,Hibernate DAO只操作一个POJO对象,因此一个DAO对应一个POJO对象。 Service层是为了处理包含多个POJO对象(即对多个表的数据操作)时,进行事务管理(声明式事务管理)。Service...
    1,dao和service对应

    一般情况下,Hibernate DAO只操作一个POJO对象,因此一个DAO对应一个POJO对象。 Service层是为了处理包含多个POJO对象(即对多个表的数据操作)时,进行事务管理(声明式事务管理)。Service层(其接口的实现类)被注入多个DAO对象,以完成其数据操作。

    2, Service之有无

    这一点我的看法未必正确,我的脑海现在有两种构建业务层的模式:

    模式1是Service + DAO,即DAO中只做CRUD及类似的简单操作(称之为功能点,不包含业务逻辑),Service中通过调用一个或多个DAO中的功能点来组合成为业务逻辑.Service的数量应该由功能模块来决定。

    在这种模型中业务逻辑是放在Service中的,事务的边界也应该在Service中控制. 当然,直接在Service中控制事务会引入非业务逻辑的代码,幸好Spring的AOP可以解决这个问题,这也是引入Spring的原因之一.

    如果说到缺点,就在于对某些对象的操作就是简单的CRUD,Service层显得累赘.


    2:
    从字面的意思上来看,service是业务层,dao是数据访问层。
    记得刚学编程的时候,都是在service里直接调用dao,service里面就new一个dao类对象,调用,其他有意义的事没做,因为也不知道应该在里面写些什么有意义的代码,也不明白有这个有什么用,甚至还觉得不要serivce层不更好,省点功夫,反正它不也就是copy了一次dao层然后改个名字而已么……
    我们都知道,标准主流现在的编程方式都是采用MVC综合设计模式,MVC本身不属于设计模式的一种,它描述的是一种结构,最终目的达到解耦,解耦说的意思是你更改某一层代码,不会影响我其他层代码,如果你会像spring这样的框架,你会了解面向接口编程,表示层调用控制层,控制层调用业务层,业务层调用数据访问层。初期也许都是new对象去调用下一层,比如你在业务层new一个DAO类的对象,调用DAO类方法访问数据库,这样写是不对的,因为在业务层中是不应该含有具体对象,最多只能有引用,如果有具体对象存在,就耦合了。当那个对象不存在,我还要修改业务的代码,这不符合逻辑。好比主板上内存坏了,我换内存,没必要连主板一起换。我不用知道内存是哪家生产,不用知道多大容量,只要是内存都可以插上这个接口使用。这就是MVC的意义。
    接下来说如果现在感觉不到service的存在意义,其实因为现在做东西分层次不是那么严格,在一个你们做东西业务本身也少,举个最简单的例子,你做一个分页的功能,数据1000条,你20条在一个页,你可以把这个功能写成工具类封装起来,然后在业务层里调用这个封装的方法,这才是业务里真正干得事,只要没访问数据库的,都要在业务里写。
    比说你现在用的是SSH框架,做一个用户模块:
    1、假设现在你做这个功能会用到user表和权限表,那么你前台的页面访问action,action再去调用用户模块service,用户模块service判断你是操作user表还是权限表,如果你操作的是user表则service的实现类就去调用userDAO。如果是操作的是权限表则调用权限的DAO
    2、也就是说DAO一定是和数据库的每张表一一对应,而service则不是。明白的没?其实你一个项目一个service和一个DAO其实也一样可以操作数据库,只不过那要是表非常多,出问题了,那找起来多麻烦,而且太乱了
    3、好处就是你的整个项目非常系统化,和数据库的表能一致,而且功能模块化,这样以后维护或者改错比较容易,性能也高一些
    展开全文
  • spring注解@service("service")括号中的service有什么用

    万次阅读 多人点赞 2019-01-09 11:08:53
    service 是有用的相当于 xml配置中得bean id = service 也可以不指定 不指定相当于 bean id = com. service.service 就是这个类的全限定名,表示给当前类命名一个别名,方便注入到其他需要用到的类中;不加的话,默认...

    service  是有用的相当于 xml配置中得bean  id = service  也可以不指定 不指定相当于 bean id =  com. service.service 就是这个类的全限定名,表示给当前类命名一个别名,方便注入到其他需要用到的类中;不加的话,默认别名就是当前类名,但是首字母小写 

     

     

    Spring注解@Component、@Repository、@Service、@Controller区别

    所以,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释,而用 @Component 对那些比较中立的类进行注释。 

    在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。 Spring2.5为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件时一样的。要使用自动扫描机制,我们需要打开以下配置信息: 
    Java代码 
     

    <?xml version="1.0" encoding="UTF-8" ?> 
    <beansxmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans2.5.xsd  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context-2.5.xsd"  > 
      
     <context:component-scan base-package=”com.eric.spring”>   
     </beans>   


    6. 其中base-package为需要扫描的包(含所有子包) @Service用于标注业务层组件,@Controller用于标注控制层组件(如struts中的action),@Repository用于标注数据访问组件,即DAO组件,而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。  

    @Service  
    public class VentorServiceImpl implements iVentorService{     
    }   
      
    Repository  
    public class VentorDaoImpl implements iVentorDao {   
    }   
    1. getBean的默认名称是类名(头字母小写),如果想自定义,可以@Service(“aaaaa”)这样来指定,这种bean默认是单例的,  
    2. 如果想改变,可以使用  
    3. @Service(“beanName”)  
    4. @Scope(“prototype”)来改变。可以使用以下方式指定初始化方法和销毁方法(方法名任意):  
    @PostConstruct  
    public void init() {   
     }   
      
     @PreDestroy  
     public void destory() {   
     }   
    


    注入方式: 

    把DAO实现类注入到service实现类中,把service的接口(注意不要是service的实现类)注入到action中,注 

    入时不要new 这个注入的类,因为spring会自动注入,如果手动再new的话会出现错误,然后属性加上 

    @Autowired后不需要getter()和setter()方法,Spring也会自动注入。至于更具体的内容,等对注入的方式更 

    加熟练后会做个完整的例子上来。 

    注解: 

    在 spring的配置文件里面只需要加上<context:annotation-config/>和<context:component-scanbase-package="需要实现注入的类所在包"/>,

    可以使用base-package="*"表示全部的类。   

    < context:component-scan base-package=”com.eric.spring”> 

    其中base-package为需要扫描的包(含所有子包) 

    在接口前面标上@Autowired和@Qualifier注释使得接口可以被容器注入,当接口存在两个实现类的时候必须指定其中一个来注入,

    使用实现类首字母小写的字符串来注入,如: 

        @Autowired      
       
        @Qualifier("chinese")       
       
         private Man man;    
    否则可以省略,只写@Autowired  。 

    @Service服务层组件,用于标注业务层组件,表示定义一个bean,自动根据bean的类名实例化一个首写字母为小写的bean,

    例如Chinese实例化为chinese,如果需要自己改名字则:@Service("你自己改的bean名")。   

    @Controller用于标注控制层组件(如struts中的action) 

    @Repository持久层组件,用于标注数据访问组件,即DAO组件 

    @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。 


    @Service 
    public class VentorServiceImpl implements iVentorService { 


    @Repository 
    public class VentorDaoImpl implements iVentorDao { 


    getBean 的默认名称是类名(头字母小写),如果想自定义,可以@Service(“aaaaa”) 这样来指定,这种 

    bean默认是单例的,如果想改变,可以使用@Service(“beanName”)@Scope(“prototype”)来改变。 

    可以使用以下方式指定初始化方法和销毁方法(方法名任意): 

    @PostConstruct 

    public void init() { 



    @PreDestroy 

    public void destory() { 

     

     

     

     

    Spring中@Autowired注解、@Resource注解的区别

    BY ETHAN ON 2011年 06 月 02 日 IN JAVA

    Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
    @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
    @Resource装配顺序
    1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
    2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
    3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
    4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

    @Autowired 与@Resource的区别:

     

    1、 @Autowired与@Resource都可以用来装配bean.都可以写在字段上,或写在setter方法上。

    2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:

    1

    @Autowired() @Qualifier("baseDao")

    2

    private BaseDao baseDao;

    3、@Resource(这个注解属于J2EE的),默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    1

    @Resource(name="baseDao")

    2

    private BaseDao baseDao;

    推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。

    展开全文
  • Service的概念与使用

    千次阅读 2017-11-06 18:04:41
    Service即服务,与Activity,ContentProvider,BroadcastReceiver并称Android程序的四大组件。 在程序后台运行,不可见,难以被Android系统自动杀死。 服务分为本地服务和远程服务,本地服务即为在程序内部...

    概述:

    Service即服务,与Activity,ContentProvider,BroadcastReceiver并称Android程序的四大组件。

    在程序后台运行,不可见,难以被Android系统自动杀死。

    服务分为本地服务和远程服务,本地服务即为在程序内部使用的服务,而远程服务是在Android系统内的程序与程序之间使用。


    用途举例:
    后台保持播放音乐、记录地理位置变动、监听部分动作等等。

    注意事项:

    运行在主线程,所以不能用来做耗时操作,可以在服务中开子线程来做耗时操作。


    本地服务的启动与停止:
    有两种启动方式,分别是start和bind。
    start方式是由startService方法启动,stopService方法,stopSelf方法,stopSelfResult方法停止。
    bind方式则是bindService方法,要停止则要先unbindService。


    远程服务:
    远程服务用于系统内的程序和程序之间,需要定义IBinder接口


    生命周期:
    根据服务的启动方式,服务的生命周期由两部分组成。
    start方式启动的服务的生命周期:onCreate()->onStartCommand()->running->onDestroy()->结束。

    bind方式启动的服务的生命周期:onCreate()->onBind()->服务和启动源绑定->onUnbind()->onDestroy()->结束。

    running时,可以自行停止或通过启动源停止,当执行了stopService方法,会调用onDestroy()。
    当执行了unbindService(),会调用onUnbind()。


    特点:
    Start方式特点:
    服务跟启动源无联系,也无法得到服务对象。
    Bind方式特点:
    通过Ibinder接口实例,返回ServiceConnection对象给启动源,通过ServiceConnection对象的相关方法能得到Service对象。


    Start方式启动(例):

    //先要在记录文件中进行记录:
    <service android:name="所写的Service类">
     </service>
    服务类:
    public class Startservice extends Service
    {
       @Override
       public IBinder onBind(Intent intent)  //这里要重写onBind方法
      {
        
        return null;
       }
    }
    Activity中:
    Intent intent=new Intent(当前Activity对象,服务类的class);
      startService(intent);
      ...
      stopService(intent);
    

    Bind方式启动(例):

    依旧是先在Android程序的记录文件中进行记录。

    服务类:

      public class MyBind extends Service
     {
        public class MyBinder extends Binder    //定义MyBinder内部类。
      {
          public MyBind getit()
         {
           return MyBind.this;
         }
       }
         public IBinder onBind(Intent intent)
        {
          return new MyBinder();
        }
        public void unbindService(ServiceConnection conn)
      {
        super.unbindService(conn);
      }
    }
    
    

    Activity中:

         MyBind mb;
         ......
       ServiceConnection con=new ServiceConnection()
       {
        public void onServiceDisconnected(ComponentName name) //Service的启动源与Service的连接丢失时,该方法会被调用。
       {                                                         
    
        }
         public void onServiceConnected(ComponentName name,IBinder service) //Service的启动源与Service连接成功后,该方法会被调用。
       {                                                                     
                                                                              
          mb=((MyBinder)service).getit();   //然后后面就可以用这个mb来调用这个服务类里定义的部分方法。
        }
       };
       ......
       Intent intent2=new Intent(当前Activity对象,MyBind.class);
       bindService(intent2,con,Service.BIND_AUTO_CREATE);
       ......
       unbindService(con);



    注:如果start和bind方式一起使用,要注意先stopService,再unbindService。



    展开全文
  • 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的Android程序员如果连Service都没听说过的话,那确实也太逊了。Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色。它主要...

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11952435


    相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的Android程序员如果连Service都没听说过的话,那确实也太逊了。Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。


    不过,虽然Service几乎被每一个Android程序员所熟知,但并不是每个人都已经将Service的各个知识点都掌握得非常透彻。那么今天我就将带着大家对Service进行一次全面、深入的探究,希望每个人在读完本篇文章后都能对Service有更深一层的理解。


    Service的基本用法


    关于Service最基本的用法自然就是如何启动一个Service了,启动Service的方法和启动Activity很类似,都需要借助Intent来实现,下面我们就通过一个具体的例子来看一下。

    新建一个Android项目,项目名就叫ServiceTest,这里我选择使用4.0的API。


    然后新建一个MyService继承自Service,并重写父类的onCreate()、onStartCommand()和onDestroy()方法,如下所示:

    public class MyService extends Service {
    
    	public static final String TAG = "MyService";
    
    	@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;
    	}
    
    }

    可以看到,我们只是在onCreate()、onStartCommand()和onDestroy()方法中分别打印了一句话,并没有进行其它任何的操作。


    然后打开或新建activity_main.xml作为程序的主布局文件,代码如下所示:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/start_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Start Service" />
    
        <Button
            android:id="@+id/stop_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Stop Service" />
    
    </LinearLayout>

    我们在布局文件中加入了两个按钮,一个用于启动Service,一个用于停止Service。


    然后打开或新建MainActivity作为程序的主Activity,在里面加入启动Service和停止Service的逻辑,代码如下所示:

    public class MainActivity extends Activity implements OnClickListener {
    
    	private Button startService;
    
    	private Button stopService;
    
    	@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);
    		startService.setOnClickListener(this);
    		stopService.setOnClickListener(this);
    	}
    
    	@Override
    	public void onClick(View v) {
    		switch (v.getId()) {
    		case R.id.start_service:
    			Intent startIntent = new Intent(this, MyService.class);
    			startService(startIntent);
    			break;
    		case R.id.stop_service:
    			Intent stopIntent = new Intent(this, MyService.class);
    			stopService(stopIntent);
    			break;
    		default:
    			break;
    		}
    	}
    
    }
    可以看到,在Start Service按钮的点击事件里,我们构建出了一个Intent对象,并调用startService()方法来启动MyService。然后在Stop Serivce按钮的点击事件里,我们同样构建出了一个Intent对象,并调用stopService()方法来停止MyService。代码的逻辑非常简单,相信不需要我再多做解释了吧。


    另外需要注意,项目中的每一个Service都必须在AndroidManifest.xml中注册才行,所以还需要编辑AndroidManifest.xml文件,代码如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.servicetest"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="14"
            android:targetSdkVersion="17" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            
    	……
    
            <service android:name="com.example.servicetest.MyService" >
            </service>
        </application>
    
    </manifest>

    这样的话,一个简单的带有Service功能的程序就写好了,现在我们将程序运行起来,并点击一下Start Service按钮,可以看到LogCat的打印日志如下:



    也就是说,当启动一个Service的时候,会调用该Service中的onCreate()和onStartCommand()方法。


    那么如果我再点击一次Start Service按钮呢?这个时候的打印日志如下:




    可以看到,这次只有onStartCommand()方法执行了,onCreate()方法并没有执行,为什么会这样呢?这是由于onCreate()方法只会在Service第一次被创建的时候调用,如果当前Service已经被创建过了,不管怎样调用startService()方法,onCreate()方法都不会再执行。因此你可以再多点击几次Start Service按钮试一次,每次都只会有onStartCommand()方法中的打印日志。


    我们还可以到手机的应用程序管理界面来检查一下MyService是不是正在运行,如下图所示:



    恩,MyService确实是正在运行的,即使它的内部并没有执行任何的逻辑。


    回到ServiceTest程序,然后点击一下Stop Service按钮就可以将MyService停止掉了。


    Service和Activity通信


    上面我们学习了Service的基本用法,启动Service之后,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑了。不过这样的话Service和Activity的关系并不大,只是Activity通知了Service一下:“你可以启动了。”然后Service就去忙自己的事情了。那么有没有什么办法能让它们俩的关联更多一些呢?比如说在Activity中可以指定让Service去执行什么任务。当然可以,只需要让Activity和Service建立关联就好了。


    观察MyService中的代码,你会发现一直有一个onBind()方法我们都没有使用到,这个方法其实就是用于和Activity建立关联的,修改MyService中的代码,如下所示:

    public class MyService extends Service {
    
    	public static final String TAG = "MyService";
    
    	private MyBinder mBinder = new MyBinder();
    
    	@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 mBinder;
    	}
    
    	class MyBinder extends Binder {
    
    		public void startDownload() {
    			Log.d("TAG", "startDownload() executed");
    			// 执行具体的下载任务
    		}
    
    	}
    
    }

    这里我们新增了一个MyBinder类继承自Binder类,然后在MyBinder中添加了一个startDownload()方法用于在后台执行下载任务,当然这里并不是真正地去下载某个东西,只是做个测试,所以startDownload()方法只是打印了一行日志。


    然后修改activity_main.xml中的代码,在布局文件中添加用于绑定Service和取消绑定Service的按钮:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/start_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Start Service" />
    
        <Button
            android:id="@+id/stop_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Stop Service" />
    
        <Button
            android:id="@+id/bind_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Bind Service" />
        
        <Button 
            android:id="@+id/unbind_service"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Unbind Service"
            />
        
    </LinearLayout>
    接下来再修改MainActivity中的代码,让MainActivity和MyService之间建立关联,代码如下所示:
    public class MainActivity extends Activity implements OnClickListener {
    
    	private Button startService;
    
    	private Button stopService;
    
    	private Button bindService;
    
    	private Button unbindService;
    
    	private MyService.MyBinder myBinder;
    
    	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();
    		}
    	};
    
    	@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, MyService.class);
    			startService(startIntent);
    			break;
    		case R.id.stop_service:
    			Intent stopIntent = new Intent(this, MyService.class);
    			stopService(stopIntent);
    			break;
    		case R.id.bind_service:
    			Intent bindIntent = new Intent(this, MyService.class);
    			bindService(bindIntent, connection, BIND_AUTO_CREATE);
    			break;
    		case R.id.unbind_service:
    			unbindService(connection);
    			break;
    		default:
    			break;
    		}
    	}
    
    }

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


    当然,现在Activity和Service其实还没关联起来了呢,这个功能是在Bind Service按钮的点击事件里完成的。可以看到,这里我们仍然是构建出了一个Intent对象,然后调用bindService()方法将Activity和Service进行绑定。bindService()方法接收三个参数,第一个参数就是刚刚构建出的Intent对象,第二个参数是前面创建出的ServiceConnection的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service,这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行。


    然后如何我们想解除Activity和Service之间的关联怎么办呢?调用一下unbindService()方法就可以了,这也是Unbind Service按钮的点击事件里实现的逻辑。


    现在让我们重新运行一下程序吧,在MainActivity中点击一下Bind Service按钮,LogCat里的打印日志如下图所示:




    另外需要注意,任何一个Service在整个应用程序范围内都是通用的,即MyService不仅可以和MainActivity建立关联,还可以和任何一个Activity建立关联,而且在建立关联时它们都可以获取到相同的MyBinder实例。


    如何销毁Service


    在Service的基本用法这一部分,我们介绍了销毁Service最简单的一种情况,点击Start Service按钮启动Service,再点击Stop Service按钮停止Service,这样MyService就被销毁了,可以看到打印日志如下所示:



    那么如果我们是点击的Bind Service按钮呢?由于在绑定Service的时候指定的标志位是BIND_AUTO_CREATE,说明点击Bind Service按钮的时候Service也会被创建,这时应该怎么销毁Service呢?其实也很简单,点击一下Unbind Service按钮,将Activity和Service的关联解除就可以了。


    先点击一下Bind Service按钮,再点击一下Unbind Service按钮,打印日志如下所示:



    以上这两种销毁的方式都很好理解。那么如果我们既点击了Start Service按钮,又点击了Bind Service按钮会怎么样呢?这个时候你会发现,不管你是单独点击Stop Service按钮还是Unbind Service按钮,Service都不会被销毁,必要将两个按钮都点击一下,Service才会被销毁。也就是说,点击Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让Service和Activity解除关联,一个Service必须要在既没有和任何Activity关联又处理停止状态的时候才会被销毁。


    为了证实一下,我们在Stop Service和Unbind Service按钮的点击事件里面加入一行打印日志:

    public void onClick(View v) {
    	switch (v.getId()) {
    	case R.id.start_service:
    		Intent startIntent = new Intent(this, MyService.class);
    		startService(startIntent);
    		break;
    	case R.id.stop_service:
    		Log.d("MyService", "click Stop Service button");
    		Intent stopIntent = new Intent(this, MyService.class);
    		stopService(stopIntent);
    		break;
    	case R.id.bind_service:
    		Intent bindIntent = new Intent(this, MyService.class);
    		bindService(bindIntent, connection, BIND_AUTO_CREATE);
    		break;
    	case R.id.unbind_service:
    		Log.d("MyService", "click Unbind Service button");
    		unbindService(connection);
    		break;
    	default:
    		break;
    	}
    }

    然后重新运行程序,先点击一下Start Service按钮,再点击一下Bind Service按钮,这样就将Service启动起来,并和Activity建立了关联。然后点击Stop Service按钮后Service并不会销毁,再点击一下Unbind Service按钮,Service就会销毁了,打印日志如下所示:



    我们应该始终记得在Service的onDestroy()方法里去清理掉那些不再使用的资源,防止在Service被销毁后还会有一些不再使用的对象仍占用着内存。


    Service和Thread的关系


    不少Android初学者都可能会有这样的疑惑,Service和Thread到底有什么关系呢?什么时候应该用Service,什么时候又应该用Thread?答案可能会有点让你吃惊,因为Service和Thread之间没有任何关系!


    之所以有不少人会把它们联系起来,主要就是因为Service的后台概念。Thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。而Service我们最初理解的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行,这就会让人产生混淆了。但是,如果我告诉你Service其实是运行在主线程里的,你还会觉得它和Thread有什么关系吗?让我们看一下这个残酷的事实吧。


    在MainActivity的onCreate()方法里加入一行打印当前线程id的语句:

    Log.d("MyService", "MainActivity thread id is " + Thread.currentThread().getId());
    然后在MyService的onCreate()方法里也加入一行打印当前线程id的语句:
    Log.d("MyService", "MyService thread id is " + Thread.currentThread().getId());

    现在重新运行一下程序,并点击Start Service按钮,会看到如下打印日志:



    可以看到,它们的线程id完全是一样的,由此证实了Service确实是运行在主线程里的,也就是说如果你在Service里编写了非常耗时的代码,程序必定会出现ANR的。


    你可能会惊呼,这不是坑爹么!?那我要Service又有何用呢?其实大家不要把后台和子线程联系在一起就行了,这是两个完全不同的概念。Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。你可能又会问,前面不是刚刚验证过Service是运行在主线程里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。


    额,既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。


    一个比较标准的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被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service,比如说墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息,如下图所示:



    那么我们就来看一下如何才能创建一个前台Service吧,其实并不复杂,修改MyService中的代码,如下所示:

    public class MyService extends Service {
    
    	public static final String TAG = "MyService";
    
    	private MyBinder mBinder = new MyBinder();
    
    	@Override
    	public void onCreate() {
    		super.onCreate();
    		Notification notification = new Notification(R.drawable.ic_launcher,
    				"有通知到来", System.currentTimeMillis());
    		Intent notificationIntent = new Intent(this, MainActivity.class);
    		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
    				notificationIntent, 0);
    		notification.setLatestEventInfo(this, "这是通知的标题", "这是通知的内容",
    				pendingIntent);
    		startForeground(1, notification);
    		Log.d(TAG, "onCreate() executed");
    	}
    
    	.........
    
    }

    这里只是修改了MyService中onCreate()方法的代码。可以看到,我们首先创建了一个Notification对象,然后调用了它的setLatestEventInfo()方法来为通知初始化布局和数据,并在这里设置了点击通知后就打开MainActivity。然后调用startForeground()方法就可以让MyService变成一个前台Service,并会将通知的图片显示出来。


    现在重新运行一下程序,并点击Start Service或Bind Service按钮,MyService就会以前台Service的模式启动了,并且在系统状态栏会弹出一个通栏图标,下拉状态栏后可以看到通知的详细内容,如下图所示。



    好了,由于篇幅的原因,本篇文章就先写到这里。目前我们已经把关于Service的很多重要知识点都梳理完了,下一篇文章会承接这篇文章,介绍Android Service中剩下的一个非常重要且复杂的知识点 —— 远程Service的使用,感兴趣的朋友请继续阅读 Android Service完全解析,关于服务你所需知道的一切(下) 。


    关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

    微信扫一扫下方二维码即可关注:

            

    展开全文
  • Service

    2020-06-26 12:17:51
    Service是Android的四大组件之一,属于计算型组件,它的作用是提供需在后台长期运行的服务(比如复杂计算、音乐播放、下载等),特点是无用户界面、在后台运行、生命周期长 生命周期 常用方法 在Service的生命周期...
  • Android中Service的三种使用方式

    万次阅读 2020-08-26 10:50:09
    第一种,直接在客户端,一般是activity中调用startService()方法,传递一个Intent参数,将要传递的数据储存在intent中传递给Service即可,启动服务后会依次调用服务的一些生命周期的回调方法,其中在onStartCommand...
  • 相信大多数朋友对Service这个名词都不会陌生,没错,一个老练的Android程序员如果连Service都没听说过的话,那确实也太逊了。Service作为Android四大组件之一,在每一个应用程序中都扮演着非常重要的角色。它主要...
  • 安卓Service 详解

    万次阅读 多人点赞 2018-06-07 17:40:49
    Service全部内容基本会在本篇涉及到,我们将围绕以下主要知识点进行分析:Service简单概述Service在清单文件中的声明Service启动服务实现方式及其详解Service绑定服务的三种实现方式关于启动服务与绑定服务间的...
  • @service 注解

    千次阅读 2019-01-19 10:00:27
    service 是有用的相当于 xml配置中得bean id = service 也可以不指定 不指定相当于 bean id = com. service.service 就是这个类的全限定名,表示给当前类命名一个别名,方便注入到其他需要用到的类中; 加的话 可...
  • Service 1.Service基础知识概述   Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务...
  • Android Service两种启动方式详解(总结版)

    万次阅读 多人点赞 2017-07-25 06:25:13
    Service生命周期.png 第一种方式:通过StartService启动Service 通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。 要创建一...
  • Ubutntu安装完docker后,执行sudo service docker start提示 Failed to start docker.service: Unit docker.service is masked. 解决方案:执行如下三条指令systemctl unmask docker.service systemctl unmask ...
  • centos7查看服务开机启用和禁用的方法 ...systemctl enable firewalld.service ; systemctl enable httpd.service; 先关闭,停止运行服务 systemctl stop firewalld.service ; 加入开机禁用 systemctl di...
  • XXXXX: unrecognized service 错误解决办法

    万次阅读 2019-10-12 15:51:57
    service httpd status 查看服务状态 service httpd start service httpd stop service httpd restart 报错:httpd: unrecognized service 不能识别的服务将httpd service注册为系统服务即可,类比于其它服务都是...
  • 不用service network restart 用service network-manager restart
  • Android提供的dumpsys工具可以用于查看感兴趣的系统服务信息与状态,手机连接电脑后可以直接命令行执行adb shell dumpsys 查看所有支持的Service但是这样输出的太多,可以通过dumpsys | grep "DUMP OF SERVICE" 仅...
  • 比如maven项目,如果A层Service调用了B层Service的方法,那么就一定要先启动B工程,否则A层启动的时候就会报错,虽然可以不介意这种Exception,但是如果真的是B层的service出了问题那也会被误以为没错。如果这个时候...
  • Android Service 详解四:开始停止service

    万次阅读 多人点赞 2013-03-25 14:12:44
    开始一个Service 你可以从一个activity或从其它应用的组件通过传递一个Intent(指定了要启动的服务)给startService()启动一个服务.Android系统然后调用service的onStartCommand()方法并且把Intent传递给它.(你永远...
  • Failed to stop iptables.service: Unit iptables.service not loaded.

    万次阅读 多人点赞 2019-03-03 21:43:42
    在关闭防火墙到时候,出现: Redirecting to /bin/...Failed to stop iptables.service: Unit iptables.service not loaded. 解决方法: yum install iptables-services 实际上,centos7后是使用的基于iptabl...
  • Ubuntu下"sshd:unrecognized service

    万次阅读 2017-04-11 09:34:55
    windows下的VMware Station安装了ubuntu(版本不限)。想通过远程工具WinSCP上传文件,因为U盘挂载的办法太麻烦了。...开启远程服务器在终端界面输入:service sshd start。 结果显示:ssh:unrecognized service
1 2 3 4 5 ... 20
收藏数 2,166,028
精华内容 866,411
关键字:

service