Android 四大组件之Service

服务(Service)是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互并且还要求长期运行的任务。Service不依赖于任何界面。它主要用于在后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。


服务的基本用法

1.定义一个服务

创建一个service,我们新建一个MyService集成Service,并重写onCreate()onStartCommand()、和onDestroy()方法。

public class MyService extends Service{

    private static final String TAG = "MyService";

    @Override
    public void onCreate() {
        // 服务创建时调用
        super.onCreate();
        Log.d(TAG, "onCreate: 服务创建");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 服务启动时调用
        Log.d(TAG, "onStartCommand: 服务启动");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        // 服务销毁时调用
        super.onDestroy();
        Log.d(TAG, "onDestroy: 服务销毁");

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

如同四大组件中其他组件,每一个服务都需要在 AndroidManifest.xml 文件中注册才能生效。

  <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

       ...

        <service
            android:name=".service.MyService"/>
    </application>

如此我们便定义好一个服务,接下来需要做的就是启动这个服务

2.启动和停止服务

Service 的启动和停止主要是借助 Intent 来实现的,我们在项目中生成一个界面来控制服务的启动和停止。

图片名称

在Activity中,对两个按钮添加点击事件,以便触发服务的启动和停止。

@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;
        }
    }

点击 START_SERVICE 按钮后,logcat日志如下

这里写图片描述

我们可以看到,第一次启动服务时,onCreate()方法和onStartCommand()方法分别执行一次,如果我们此时再次点击 START_SERVICE 按钮,logcat 日志如下

这里写图片描述

我们可以看到,无论我们点击几次START_SERVICE按钮,onCreatef()只会在服务第一次创建的时候调用,而onStartCommand()方法则在每次启动服务的时候都会调用。

当我们点击 STOP_SERVICE 后,日志打印如下

这里写图片描述

服务调用onDestroy()方法,被销毁了。

除了在活动中调用 stopService()方法停止服务外,在 MyService 中任意一个位置调用stopSelf()方法都可以让服务停下来。


服务和活动之间通信

上面的代码中,我们在 Activity 中启动了 Service,然后服务处于一直运行的状态。可之后,Service 和 Activiy 之间就没有任何联系了。为了Acticity可以对Service进行有效的控制,需要绑定服务

我们修改MyService类中的代码,新建内部类 MyBinder,在 MyBinder 中写一个打印信息的方法 ShowInfo() ,并让MyService中 onBind() 方法返回 MyBinder 的实例。

public class MyService extends Service {

    private MyBinder mBinder = new MyBinder();

    ...

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }


    public class MyBinder extends Binder {

        public void ShowInfo() {
            Log.d(TAG, "ShowInfo: 执行ShowInfo方法");
        }
    }
}

我们在之前的界面上新增两个 Button ,分别用于绑定服务取消服务

图片名称

修改 Activity 代码如下

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private Button start_service;

    private Button stop_service;

    private Button bind_service;

    private Button unbind_service;

    private MyService.MyBinder mBinder;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected: 服务绑定");
            mBinder = (MyService.MyBinder) service;
            mBinder.ShowInfo();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        start_service = (Button) findViewById(R.id.start_service);
        stop_service = (Button) findViewById(R.id.stop_service);
        bind_service = (Button) findViewById(R.id.bind_service);
        unbind_service = (Button) findViewById(R.id.unbind_service);

        start_service.setOnClickListener(this);
        stop_service.setOnClickListener(this);
        bind_service.setOnClickListener(this);
        unbind_service.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);// 绑定服务
                // BIND_AUTO_CREATE 表示服务绑定后自动创建服务。会执行service的onCreate()方法,但onStartCommand()不会执行
                break;
            case R.id.unbind_service:
                unbindService(connection); // 解绑服务
                break;
        }
    }
}

首先,我们创建了一个 ServiceConnection 的内部类,重写它的 onServiceConnected()方法和onServiceDisconnected()方法,这两个方法分别会在服务绑定成功和服务解绑后调用。

onServiceConnected()方法中,通过向下转型获取 MyBinder 实例,然后就可以调用 MyBinder 中任何 Public 方法了。

在 BIND_SERVICE 的点击事件中,通过bindService()实现服务于活动的绑定。点击按钮后logcat如下

这里写图片描述

我们在bindService()中设置了 BIND_AUTO_CREATE 标志位,该标志表示服务绑定后自动创建服务。会执行service的onCreate()方法,但onStartCommand()不会执行

点击 UNBIND_SERVICE 后,打印日志如下

这里写图片描述


服务的生命周期

这里写图片描述

调用 startService()方法后,再次调用stopService()方法,onDestroy()就会执行;

调用bindService()方法后,再次调用unBindService()方法,onDestroy()就会执行;

如果既调用了startService()方法,又调用了bindService()方法,则必须同时调用stopService()unBindService()方法,onDestroy()才会执行;

使用IntentService

服务中的代码默认都是执行在主线程中的。如果在服务中处理耗时操作,很容易出现ANR(Application Not Responding)。

为了防止ANR的发生,我们应该在每个具体的方法里开启一个子线程,然后在这里执行耗时操作。这种服务一旦启动,就会一直处于运行状态,必须调用stopService()stopSelf()方法才能停下来。代码如下

public class MyService extends Service {

    ...

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 服务启动时调用
        Log.d(TAG, "onStartCommand: 服务启动");
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO: 执行耗时操作
                // 在适当的时候结束服务
                stopSelf();
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

}

为了处理这种耗时操作,Android提供了一个 IntentService 类,集开启线程和自动停止于一身。

public class MyIntentService extends IntentService {

    private static final String TAG = "MyIntentService";

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "onHandleIntent: 服务启动");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy: 服务销毁");
    }
}

我们在 Activty 中新建 Button,并设置点击事件启动 IntentService。

case R.id.intent_service:
                Intent intentServiceIntent = new Intent(this, MyIntentService.class);
                startService(intentServiceIntent); // 启动服务
                break;

打印日志如下,服务在执行完毕后自动停止了。

这里写图片描述

写在最后

学疏才浅,写作仓促,如果纰漏之处还望指正,不胜感激。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值