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。需要三个参数         //参数1intent对象         //参数2ServiceConnection对象         //参数3Context.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) {
   //Service绑定成功,并且方法参数中的“IBinder service”对象非空时调用,   //该参数的值是通过Service里面的onBind()方法返回   Log.e("SecondActivity", "onServiceConnected:============= ");   //调用MyService里面的test()方法   MyService.MyBinder myBinder = (MyService.MyBinder) service;   myBinder.test();
} @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。需要三个参数 //参数1intent对象 //参数2ServiceConnection对象 //参数3Context.BIND_AUTO_CREATE表示如果系统中不存在服务,则自动创建一个。 bindService(intent, conn, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); //在界面销毁的时候,需要调用unbindService()方法解绑 unbindService(conn); }}

    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()方法自我销毁,它适用于一些短期的耗时任务。   

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果手机淘宝占内存太大怎么办 苹果手机淘宝图标找不到了怎么办 苹果手机看淘宝很卡怎么办 苹果手机淘宝忘了密码怎么办 苹果手机更新后淘宝打不开怎么办 淘宝买到苹果翻新机怎么办 淘宝网密码忘了怎么办 淘宝改密码要拍摄脸部怎么办 苹果一体机键盘没反应怎么办 淘宝买东西退货卖家拒绝怎么办? 淘宝被限制下单怎么办 淘宝扫码登录后怎么办 花呗选项被隐藏怎么办 新换手机支付宝怎么办 ih5点击按钮跳转页面怎么办 sap点安装程序没反应怎么办 淘宝店账号忘了怎么办 点击电脑桌面图标没反应怎么办 为什么淘宝打不开已停止运行怎么办 移动宽带打不开淘宝网怎么办 淘宝发布宝贝没有品牌怎么办 烫了卷发显老怎么办 唯品会商品不支持退换货怎么办 京东没有自提怎么办 不支持七天无理由的商品怎么办 淘宝评价忘记点亮星星怎么办 淘宝宝贝权重降低了该怎么办 换卡支付宝账号怎么办 支付宝免密支付无法关闭怎么办 手机换了支付宝怎么办 支付宝版本过低怎么办 支付宝无故扣钱怎么办 支付宝里面的钱不见了怎么办 支付宝还不起钱怎么办 支付宝借不到钱怎么办 买家淘宝号被监控了怎么办 卖微信号被骗了怎么办 淘宝原密码忘了怎么办 淘宝号忘记密码了怎么办啊 淘宝忘了原密码怎么办 电脑账户密码忘了怎么办