服务(Service)-《Android第一行代码》笔记

服务(Service)

标签(空格分隔): Android


服务的基本用法

注意:每一个服务都需要在AndroidManifest.xml文件中进行注册才能生效。这也是Android四大组件(服务、活动、内容提供器、广播接收器)的特点。

定义一个服务

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.servicetest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!--定义的服务-->
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true" />
        <service android:name=".MyIntentService" />
    </application>

</manifest>

MyService类:

package com.example.servicetest;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

/**
 * 新建的服务需要继承Service类
 */
public class MyService extends Service {

    public MyService() {
    }

    private DownloadBinder mBinder = new DownloadBinder();

    /**
     * 模拟一个下载功能
     */
    class DownloadBinder extends Binder {

        public void startDownload() {
            Log.d("MyService", "startDownload executed");
        }

        /**
         * 模拟返回下载进度
         * @return
         */
        public int getProgress() {
            Log.d("MyService", "getProgress executed");
            return 0;
        }

    }

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

    /**
     * 在服务创建时调用,这里创建的是前台服务,与创建通知的方法类似,都是构建Notification对象,只不过没有使用NotificationManager使通知显示出来,
     * 而是调用了startForeground()方法让MyService变成一个前台服务,该方法有两个参数:
     *      第一个参数:通知的id,类似于notify()的第一个参数。
     *      第二个参数:构建出的Notification对象。
     */
    @RequiresApi(api = Build.VERSION_CODES.ECLAIR)
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService", "onCreate executed");
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("This is content title")
                .setContentText("This is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .build();
        startForeground(1, notification);
    }

    /**
     * 每次服务启动时调用
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "onStartCommand executed");
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 服务销毁时调用
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService", "onDestroy executed");
    }

}

控制服务的活动类:

package com.example.servicetest;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private MyService.DownloadBinder downloadBinder;

    /**
     * 创建ServiceConnection匿名类,通过这个类来让活动控制服务的运行状态
     */
    private ServiceConnection connection = new ServiceConnection() {

        /**
         * 活动与服务成功断开时调用
         * @param name
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        /**
         * 活动与服务成功绑定时调用
         * 这里把service向下转型为我们创建的下载服务,然后调用下载服务的方法
         * @param name
         * @param service
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
    };

    /**
     * 在布局里定义了四个按钮:开始服务、停止服务、绑定服务、解绑服务
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService = (Button) findViewById(R.id.start_service);
        Button stopService = (Button) findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        Button bindService = (Button) findViewById(R.id.bind_service);
        Button unbindService = (Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
        Button startIntentService = (Button) findViewById(R.id.start_intent_service);
        startIntentService.setOnClickListener(this);
    }

    /**
     * startService()和stopService()方法定义在Context类中,这里可以直接调用。
     * 在活动中任意位置调用stopSelf()方法也能停止服务
     * bingService()方法用于绑定服务,有三个参数
     *      第一个:Intent对象
     *      第二个:ServiceConnection实例
     *      第三个:是一个标志位,这里传入BIND_AUTO_CREATE表示在活动和服务进行绑定后自动创建服务
     *          这会让MyService的onCreate()方法得到执行,但onStartCommand()方法不会执行
     * unbindService()用于解绑
     *
     * 要注意的是,任何一个服务在整个应用程序范围内都是通用的,即MyService不仅可以和MainActivity绑定,还可以和任何
     * 一个其他活动进行绑定,而且在绑定完成后她们都可以获取到相同的DownloadBinder实例。
     * @param v
     */
    @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;
            case R.id.start_intent_service:
                // 打印主线程的id
                Log.d("MainActivity", "Thread id is " + Thread.currentThread(). getId());
                Intent intentService = new Intent(this, MyIntentService.class);
                startService(intentService);
                break;
            default:
                break;
        }
    }

}

服务的生命周期

一旦在项目的任何位置调用了Context的startService()方法,相应的服务就会启动起来,并回调onStartCommand()方法。
如果这个服务之前还没有创建过,onCreate()方法会先于onStartCommand()方法执行。
服务启动之后会一直保持运行状态,直到stopService()或stopSelf()方法被调用。
注意:虽然每调用一次startService()方法,onStartCommand()就会执行一次,但实际上每个服务都只会存在一个实例。所以不管你调用多少次的startService()方法,只需调用一次stopService()或stopSelf()方法,服务就会停止下来。

可以调用Context的bindService()方法来获取一个服务的持久连接,这时就会回调服务中的onBind()方法。
类似地,如果这个服务之前还没有创建过,onCreate()方法会先于onBind()方法执行。
之后,调用方可以获取到onBind()方法里返回的IBinder对象的实例,这样就能自由地和服务进行通信了。
只要调用方和服务之间的连接没有断开,服务就会一直保持运行状态。

当调用了startService()方法后,又调用stopService()方法,这时服务中的onDestroy()方法就会执行,表示服务已经销毁。
类似地,调用bindService()方法后,又去调用unbindService()方法,onDestroy()方法也会执行。
当对一个服务既调用了startService()方法,又调用了bindService(),需要同时调用stopService()和unbindService()方法,onDestroy()方法才会执行。

服务的更多技巧

使用前台服务

服务的系统优先级较低,如果系统内存吃紧,会回收一部分服务。如果希望服务一直运行,需要使用前台服务。
前台服务会有一个正在运行的图标在系统的通知栏,例如天气预报应该的服务。
具体用法看上面的例子。

使用IntentService

IntentService创建的是一个异步的,会自动停止的服务。创建时,需要继承IntentService类。下面是个例子:

package com.example.servicetest;

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

/**
 * 继承IntentService类
 *
 * 另,不要忘记向AndroidManifest.xml中注册服务
 */
public class MyIntentService extends IntentService {

    /**
     * 必须调用父类的有参构造函数
     */
    public MyIntentService() {
        super("MyIntentService"); // 调用父类的有参构造函数
    }

    /**
     * 该方法会创建一个子线程,并在运行结束后自动停止服务,并调用onDestroy()
     * 服务的具体业务在此方法中实现。
     * @param intent
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印当前线程的id
        Log.d("MyIntentService", "Thread id is " + Thread.currentThread(). getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestroy executed");
    }

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值