service_service层 - 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、好处就是你的整个项目非常系统化,和数据库的表能一致,而且功能模块化,这样以后维护或者改错比较容易,性能也高一些
    展开全文
  • 相信大多数朋友对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的生命周期...

    简介

    Service是Android的四大组件之一,属于计算型组件,它的作用是提供需在后台长期运行的服务(比如复杂计算、音乐播放、下载等),特点是无用户界面、在后台运行、生命周期长

    生命周期 常用方法

    在这里插入图片描述

    在Service的生命周期里,常用的有:

    • 4个手动调用的方法
    手动调用方法 作用
    startService() 启动服务
    stopService() 关闭服务
    bindService 绑定服务
    unbindService 解绑服务
    • 5个自动调用的方法
    内部自动调用的方法 作用
    onCreate() 创建服务
    onStartCommand() 开始服务
    onDestroy() 销毁服务
    onBind() 绑定服务
    onUnbind() 解绑服务

    类型

    Service可以按照运行地点、运行类型、功能进行分类,具体如下:

    具体分类

    在这里插入图片描述

    详细介绍

    在这里插入图片描述

    使用详解

    本地Service

    这是最普通、最常用的后台服务Service

    使用步骤

    • 步骤1:新建子类继承Service类

      需要重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法

    • 步骤2:构建用于启动Service的Intent对象

    • 步骤3:调用startService()启动Service、调用stopService()停止服务

    • 步骤4:在AndroidManifest.xml里注册Service

    AndroidManifest里Service的常见属性说明:

    属性 说明 备注
    android:name Service的类名
    android:label Service的名字 若不设置,默认为Service类名
    android:icon Service的图标
    android:permission 申明此Service的权限 有提供了该权限的应用才能控制或连接此服务
    android:process 表示该服务是否在另一个进程中运行(远程服务) 不设置默认为本地服务;remote则设置成远程服务
    android:enabled 系统默认启动 true:Service将会默认被系统启动;不设置则默认为false
    android:exported 该服务是否能够被其他应用程序所控制或连接 不设置默认此项为false

    可通信的服务Service

    这种Service增加了与Activity通信的功能,即使用绑定Service服务(Binder类、bindService()、onBind()、unbindService()、onUnbind())

    前台Service

    前台Service和后台Service(普通)最大的区别就在于:

    • 前台Service在下拉通知栏有显示通知,但是后台Service没有
    • 前台Service优先级较高,不会由于系统内存不足而被回收;后台Service优先级较低,当系统出现内存不足情况时,很有可能会被回收

    远程服务Service

    多个应用程序共享同一个后台服务(远程服务)

    即一个远程Service与多个应用程序的组件(四大组件)进行跨进程通信
    在这里插入图片描述

    具体使用

    • 为了让远程Service与多个应用程序的组件(四大组件)进行跨进程通信(IPC),需要使用AIDL

    1.IPC:Intent-Process Communication,即跨进程通信
    2.AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能

    • 在多进程通信中,存在两个进程角色:服务器端、客户端

    • 服务器端:
      步骤1:新建定义AIDL文件,并声明该服务需要向客户端提供的接口
      步骤2:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreate、onBind)
      步骤3:在AndroidManifest.xml中注册服务,声明为远程服务

    • 客户端:
      步骤1:拷贝服务端的AIDL文件到目录下
      步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
      步骤3:通过Intent指定服务端的服务名称和所在包,绑定远程Service

    使用场景

    在这里插入图片描述

    其他思考

    Service与Thread的区别

    • 结论:Service与Thread没有任何关系
    • 之所以有人会将他们联系起来,主要是因为Service的后台概念

    后台:后台任务运行完全不依赖UI,即使Activity被销毁/程序被关闭,只要进程还在,后台任务就可以继续运行

    • 关于二者的异同,具体如下图:
      在这里插入图片描述
    • 注:一般会将Service和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 service_connect_Activity() {  
      //新建工作线程
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    // 执行具体的下载任务  
                }  
            }).start();  
        }  
      
    }  
    

    Service和IntentService的区别

    多线程的应用在Android开发中是非常常见的,常用方法只要有:

    • 继承Thread类
    • 实现Runnable接口
    • AsyncTask
    • Handler
    • HandlerThread
    • IntentService

    定义

    IntentService是Android里的一个封装类,继承自四大组件之一的Service,它的作用是处理异步请求、实现多线程

    使用场景

    线程任务需要按顺序、在后台执行

    1.最常见的场景:离线下载
    2.不符合多个数据同时请求的场景:所有的任务都在同一个Thread looper里执行

    工作原理

    IntentService的工作原理、源码工作流程如下:
    在这里插入图片描述

    特别注意

    若启动IntentService多次,那么每个耗时操作都以队列的方式在IntentService的onHandleIntent回调方法中依次执行,执行完自动结束

    IntentService如何单独开启一个新的工作线程?

    @Override
    public void onCreate() {
        super.onCreate();
        
        // 1. 通过实例化andlerThread新建线程 & 启动;故 使用IntentService时,不需额外新建线程
        // HandlerThread继承自Thread,内部封装了 Looper
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
      
        // 2. 获得工作线程的 Looper & 维护自己的工作队列
        mServiceLooper = thread.getLooper();
    
        // 3. 新建mServiceHandler & 绑定上述获得Looper
        // 新建的Handler 属于工作线程 ->>分析1
        mServiceHandler = new ServiceHandler(mServiceLooper); 
    }
    
    
       /** 
         * 分析1:ServiceHandler源码分析
         **/ 
         private final class ServiceHandler extends Handler {
    
             // 构造函数
             public ServiceHandler(Looper looper) {
             super(looper);
           }
    
            // IntentService的handleMessage()把接收的消息交给onHandleIntent()处理
            @Override
             public void handleMessage(Message msg) {
      
              // onHandleIntent 方法在工作线程中执行
              // onHandleIntent() = 抽象方法,使用时需重写 ->>分析2
              onHandleIntent((Intent)msg.obj);
              // 执行完调用 stopSelf() 结束服务
              stopSelf(msg.arg1);
    
        }
    }
    
       /** 
         * 分析2: onHandleIntent()源码分析
         * onHandleIntent() = 抽象方法,使用时需重写
         **/ 
          @WorkerThread
          protected abstract void onHandleIntent(Intent intent);
    

    IntentService如何通过onStartCommand()将Intent传递给服务并依次插入到工作队列中

    
    /** 
      * onStartCommand()源码分析
      * onHandleIntent() = 抽象方法,使用时需重写
      **/ 
      public int onStartCommand(Intent intent, int flags, int startId) {
    
        // 调用onStart()->>分析1
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
    
    /** 
      * 分析1:onStart(intent, startId)
      **/ 
      public void onStart(Intent intent, int startId) {
    
        // 1. 获得ServiceHandler消息的引用
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
    
        // 2. 把 Intent参数 包装到 message 的 obj 发送消息中,
        //这里的Intent  = 启动服务时startService(Intent) 里传入的 Intent
        msg.obj = intent;
    
        // 3. 发送消息,即 添加到消息队列里
        mServiceHandler.sendMessage(msg);
    }
    
    

    源码总结

    总上面的源码可以看出:IntentService本质上是Handler + HandlerThread

    1. 通过HandlerThread单独开启1个工作线程:IntentService
    2. 创建1个内部Handler:ServiceHandler
    3. 绑定ServiceHandler与IntentService
    4. 通过onStartCommand()传递服务Intent到ServiceHandler,依次插入Intent到工作队列中并逐个发送到onHandlerIntent()
    5. 通过onHandlerIntent()依次处理所有Intent对象所对应的任务

    因此我们通过复写onHandlerIntent()、在里面根据Intent的不同进行不同的线程操作即可

    注意事项

    1.工作任务队列是顺序执行的
    2.不建议通过bindService()启动IntentService

    注意事项1

    即若一个任务正在IntentService中执行,此时你再发送1个新的任务请求,这个新的任务会一直等待直到前面一个任务执行完毕后才开始执行

    原因:

    • 由于onCreate()只会调用一次,也就是说只会创建1个工作线程
    • 当多次调用startService(Intent)时(即onStartCommand(也会调用多次)),其实不会创建新的工作线程,只是把消息加入到消息队列中并等待执行
    • 所以多次启动IntentService会按顺序执行事件
    • 若服务停止,则会清除消息队列汇总的消息,后续的事件不执行

    注意事项2

    原因:

    // 在IntentService中,onBind()`默认返回null
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    

    采用bindService()启动IntentService的生命周期如下:

    onCreate() -> onBind() -> onUnbind() -> onDestory()

    即并不会调用onStart()或onStartCommand(),故不会将消息发送到消息队列,那么onHandlerIntent()将不会回调,即无法实现多线程的操作

    此时,就应该使用Service而不是IntentService

    对比

    与Service的区别

    在这里插入图片描述

    与其他线程的区别

    在这里插入图片描述

    展开全文
  • 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 是有用的相当于 xml配置中得bean id = service 也可以不指定 不指定相当于 bean id = com. service.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类,我们可以实现一个以Service为基类的服务子类,在里面实现自己的计算型逻辑,然后在主进程通过startService函数来启动这个服务。在本文中,将详细分析主进程是如何通过start...
  • Android Service生命周期及用法!

    万次阅读 热门讨论 2010-08-04 23:28:00
    大家好,上一节我讲解了Android Activity的生命周期,这一节我将讲解一下Service,首先我们要知道Service具体是干什么的,什么时候用到?以及它的生命周期等。Service概念及用途:Android中的服务,它与Activity不同...
  • 最近项目要实现这样一个效果:运行后,要有一个service始终保持在后台运行,不管用户作出什么操作,都要保证service不被kill,这可真是一个难题。参考了现今各种定制版的系统和安全厂商牛虻软件,如何能保证自己的...
  • Android Service 服务(一)—— Service

    万次阅读 多人点赞 2014-01-13 13:51:05
    一、 Service简介Service是android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。...
  • 在上一篇文章中,我们学习了Android Service相关的许多重要内容,包括Service的基本用法、Service和Activity进行通信、Service的销毁方式、Service与Thread的关系、以及如何创建前台Service。以上所提到的这些知识点...
  • Android Service与Activity之间通信的几种方式

    万次阅读 多人点赞 2014-01-10 14:41:50
    在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务,所以在我们实际开发中,就会常常遇到Activity与Service之间的通信,我们一般在Activity中启动后台Service,通过Intent来启动,...
  • java中dao层和service层的区别,为什么要用service

    万次阅读 多人点赞 2018-11-12 17:19:33
    读了下面的文章 让我豁然开朗我能不能理解 ssh中service就相当于与jsp+servlet+dao中的servlet???转文: 首先解释面上意思,service是业务层,dao是数据访问层。 呵呵,这个问题我曾经也有过,记得以前刚学...
  • Android之Service学习篇一:Service启动方式之startService

    万次阅读 多人点赞 2013-02-20 23:57:43
    Service概念及用途: A service is an application component that can perform long-running operations in the background and does not provide a user interface。 通常service用来执行一些耗时操作,或者...
  • 最近网站刷新后经常出现503 Service Temporarily Unavailable错误,有时有可以,联想到最近在nginx.conf里做了单ip访问次数限制,(limit_req_zone $binary_remote_addr zone=allips:20m rate=20r/s;) 把这个数量放大...
  • Spring注解@Component、@Repository、@Service、@Controller区别

    万次阅读 多人点赞 2015-06-24 11:12:28
    很长时间没做web项目都把以前学的那点框架知识忘光了,今天把以前做的一个项目翻出来看一下发现用·@Component标记一个组件,而网上有的用@Service标记组件,我晕就查了一下资料: Spring 2.5 中除了提供 @Component...
1 2 3 4 5 ... 20
收藏数 2,138,247
精华内容 855,298
关键字:

service