Android App开发从零开始之基础篇—四大组件(二)—使程序后台运行的Service
来源:互联网 发布:猫群算法 编辑:程序博客网 时间:2024/05/17 22:56
Android四大组件(二)—使程序后台运行的Service
前言:应用开发中经常会遇到要求长期持续运行的任务,这些任务即使在程序被切换到后台,或者用户打开另一个应用,也能够保持正常运行。Android开发中通过Service提供了这类解决方案。
一、概念
Service是Android中用于实现程序后台运行,以便执行一些无需用户界面且要求长期运行的任务的解决方案。Service无需用户界面,即使程序被切换到后台,或者用户打开另一个应用,程序仍可正常运行。注意,“后台运行”并非运行于子线程或独立进程,Service默认运行于UI线程(主线程)中,除非在Service中创建子线程,否则不要在Service中执行耗时操作。
二、Service的使用
Android中有两种Service,一种是普通Service,一种叫做IntentService。下面分别进行介绍。
2.1 普通Service
(1)生命周期:与Activity一样,Service也具有生命周期。如下图:
图1 Service的生命周期
如上图所示,Service的生命周期被分为了两种。这是因为Service具有两种启动方式:通过startService()方法启动,以及通过bindService()方法启动。下面来分别介绍:
● 通过startService()方法启动Service
以startService()方法启动的Service,程序将能够在系统中保持长存。意思就是说,除非在代码中调用了stopService()或stopSelf()方法,或者Service所在进程被杀死,否则以startService()方法启动的Service,在启动后会一直保持运行状态,即使用户将程序切换到后台,或者用户打开另一个应用,程序也会持续运行。下面来看一下使用:
首先,需要先创建一个Service,在项目中“File”—>"New",找到Service,创建即可(Eclipse中可能需要“File”—>"New"—>"Other"—>"Android"—>"Android Object")。创建好后,默认会有一个构造函数和一个onBind(Intent intent)方法,这里我们把onCreate()和onStartCommand()方法也加上,然后简单的打个日志测试一下生命周期的执行。代码如下所示:
package com.test.myapplication;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. return null; } @Override public void onCreate() { Log.e("MyService", "onCreate: ====================" ); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e("MyService", "onStartCommand: ====================" ); return super.onStartCommand(intent, flags, startId); }}
接下来在Activity里面使用Service,同界面跳转一样,需要使用Intent来指定要使用的Service。这里在MainActivity里面添加两个按钮,分别测试启动Service和停止Service。代码如下:
activity_main.xml代码:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.test.myapplication.MainActivity"> <Button android:id="@+id/main_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开启Service"/> <Button android:id="@+id/main_button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="停止Service" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/main_button" android:layout_toEndOf="@+id/main_button" android:layout_marginLeft="18dp" android:layout_marginStart="18dp" /> </RelativeLayout>
MainActivity代码:
package com.test.myapplication;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //为了在Activity中对布局文件中的UI元素(控件、布局等)进行操作,需要 //使用findViewById()方法从布局文件中找到对应的UI元素,并将其关联到 //Activity中的一个对象。代码书写格式如下: Button button = (Button) findViewById(R.id.main_button); //布局中的Button按钮设置点击事件监听 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //实例化Intent对象 Intent intent = new Intent(); //通过Intent对象指定要启动的Service intent.setClass(MainActivity.this, MyService.class); //通过startService()启动Service startService(intent); } }); findViewById(R.id.main_button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setClass(MainActivity.this, MyService.class); stopService(intent); } }); }}
MainActivity代码:
package com.test.myapplication;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //为了在Activity中对布局文件中的UI元素(控件、布局等)进行操作,需要 //使用findViewById()方法从布局文件中找到对应的UI元素,并将其关联到 //Activity中的一个对象。代码书写格式如下: Button button = (Button) findViewById(R.id.main_button); //布局中的Button按钮设置点击事件监听 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //实例化Intent对象 Intent intent = new Intent(); //通过Intent对象指定要启动的Service intent.setClass(MainActivity.this, MyService.class); //通过startService()启动Service startService(intent); } }); findViewById(R.id.main_button1).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //实例化Intent对象。 Intent intent = new Intent(); //指定要停止的Service intent.setClass(MainActivity.this, MyService.class); //停止Service stopService(intent); } }); }}
接下来,就可以分别点击两个按钮进行测试。当我们连续点击“开启Service”时,会发现onCreate()方法只调用了一次,而onStartCommand()方法每次点击的时候都会调用。如果我们点击了“停止Service”,然后再点击“开启Service”,会发现onCreate()会再次被调用。这就说明,以startService()方法启动Service的时候,onCreate()方法只会在Service第一次被创建的时候调用,其他时候只要Service没有因调用stopService()或stopSelf(),或者进程被杀死而停止,再次启动Service只会调用onStartCommand()方法。
● 通过bindService()方法启动Service
bindService()方法会将Activity与Service绑定,被绑定 的Service会随着Activity的启动而启动,通过bindService()方法绑定Service后,可以在Activity里面调用Service里面的方法。下面来看使用步骤:
首先,在项目里再添加一个SecondActivity,同时在MainActivity里面添加一个按钮跳转到SecondActivity。然后在SecondActivity的onCreate()的时候绑定Service,在onDestory()方法(即Activity关闭的时候)调用unbindService()方法解绑服务(必需)。SecondActivity代码如下:
SecondActivity代码:
package com.test.myapplication;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.support.v7.app.AppCompatActivity;import android.util.Log;public class SecondActivity extends AppCompatActivity { ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //当Service绑定成功,并且方法参数中的“IBinder service”对象非空时调用, //该参数的值是通过Service里面的onBind()方法返回 Log.e("SecondActivity", "onServiceConnected:============= "); } @Override public void onServiceDisconnected(ComponentName name) { //当Service所在进程被杀死,Service连接断开时调用此方法。 } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); //实例化Intent对象 Intent intent = new Intent(); //设置要绑定的Service intent.setClass(this, MyService.class); //绑定Service。需要三个参数 //参数1:intent对象 //参数2:ServiceConnection对象 //参数3:Context.BIND_AUTO_CREATE表示如果绑定的Service还未创建,则自动创建一个。 bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); //在界面销毁的时候,需要调用unbindService()方法解绑 unbindService(conn); }}
要在Activity里面调用Service里面的方法,则需继续以下步骤:
● 创建一个类MyBinder,继承Binder类
● 在MyBinder类中添加需要调用的方法
● 在Service的onBind()方法中返回一个MyBinder类的对象
● 在Activity的onServiceConnected(ComponentName name,IBinder service)方法中,将参数中的service强转为MyBinder类型
● 通过强转后的MyBinder对象调用Service中的方法
具体代码如下:
添加了MyBinder类的MyService代码:
package com.test.myapplication;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;public class MyService extends Service { public MyService() { } @Override public IBinder onBind(Intent intent) { return new MyBinder(); } @Override public void onCreate() { Log.e("MyService", "onCreate: ===================="); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.e("MyService", "onStartCommand: ===================="); return super.onStartCommand(intent, flags, startId); } public class MyBinder extends Binder { public void test() { Log.e("MyBinder", "test: ============="); } }}
调用MyService中的方法的SecondActivity代码:
package com.test.myapplication;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.support.v7.app.AppCompatActivity;import android.util.Log;public class SecondActivity extends AppCompatActivity { ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) {} @Override public void onServiceDisconnected(ComponentName name) { //当Service所在进程被杀死,Service连接断开时调用此方法。 } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); //实例化Intent对象 Intent intent = new Intent(); //设置要绑定的Service intent.setClass(this, MyService.class); //绑定Service。需要三个参数 //参数1:intent对象 //参数2:ServiceConnection对象 //参数3:Context.BIND_AUTO_CREATE表示如果系统中不存在服务,则自动创建一个。 bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); //在界面销毁的时候,需要调用unbindService()方法解绑 unbindService(conn); }}//当Service绑定成功,并且方法参数中的“IBinder service”对象非空时调用, //该参数的值是通过Service里面的onBind()方法返回 Log.e("SecondActivity", "onServiceConnected:============= "); //调用MyService里面的test()方法 MyService.MyBinder myBinder = (MyService.MyBinder) service; myBinder.test();
2.2 IntentService
Android中还有一种IntentService,与普通Service默认在UI线程运行不同,IntentService会将用户请求执行在一个子线程中,用户只需覆写onHandleIntent()方法,并在其中完成自己的耗时操作即可。需要注意的是,IntentService只能通过startService()来启动,且在任务执行完毕后会调用stopSelf自我销毁。因此,它适用于一些短期的耗时任务。IntentService代码如下:
package com.test.myapplication;import android.app.IntentService;import android.content.Intent;import android.util.Log;/** * An {@link IntentService} subclass for handling asynchronous task requests in * a service on a separate handler thread. * <p> * TODO: Customize class - update intent actions, extra parameters and static * helper methods. */public class MyIntentService extends IntentService { public MyIntentService() { super("MyIntentService"); } //新建IntentService的时候会默认覆写几个方法, //我们只需在这个方法里面执行自己的操作即可 @Override protected void onHandleIntent(Intent intent) { int i = 0; while (i < 100) { i++; Log.e("MyIntentService", "onHandleIntent: ==============="+i); } }}
后记:“后台运行”不等于“运行在子线程中”。普通Service默认运行在U线程中,不能在其中直接执行耗时操作。它的主要功能是用来执行一些可以在后台执行,无需用户交互界面的功能,比如后台下载,后台更新等。它有两种启动方式:startService和bindService。Android中另外提供了IntentService使程序能够默认将用户的请求执行在子线程中。IntentService只能通过startService进行启动,并且当任务执行完毕时,IntentService会调用stopSelf()方法自我销毁,它适用于一些短期的耗时任务。
- Android App开发从零开始之基础篇—四大组件(二)—使程序后台运行的Service
- Android App开发从零开始之基础篇—四大组件(一)—Activity初体验
- Android App开发从零开始之基础篇—四大组件(一)—Activity再探
- Android App开发从零开始之基础—四大组件(四)—内容提供者ContentProvider
- Android App开发从零开始之基础篇—四大组件(三)—组件间的通信方式Broadcast(广播)
- android上app后台运行的相关知识(一)————android的四大组件:Activity、Service、BroadCast Recevicer、Content provider
- Android四大组件之service(二)——用service、scheduleAtFixedRate写一个后台定时执行任务
- Android 学习之四大组件(二)——service
- Android开发——四大组件之Service的探索
- Android App开发从零开始之基础篇—布局和控件(二)— 控件
- Android 四大组件之一:Service 后台运行
- Android App开发基础篇—四大组件之Broadcast-01
- Android四大组件之Service(二)
- Android四大组件之Service(二)
- Android App开发从零开始之入门篇(二)—Android Studio的基本使用
- Android——Service 四大组件之二
- Android基础——四大组件Service
- Android开发之四大组件——Service
- 多级评论数据表设计
- Android开发消除横向排列的多个Button之间的空隙
- Popupwindow挡住键盘的问题
- [Leetcode] #203 Remove Linked List Elements
- 分布式一致性算法--Basic Paxos
- Android App开发从零开始之基础篇—四大组件(二)—使程序后台运行的Service
- Tyvj 1038-1039 忠诚1-2 【线段树】
- 操作与运筹(第一遍学习)
- TestNG入门——@DataProvider
- Python之日期与时间处理模块(date和datetime)
- codeforces-50A-A. Domino piling ( C && greedy && math )
- 关于volatile的用法
- ARM+LINUX路线
- HDU - 4324 拓扑排序