Android Service介绍

Android Service介绍

一 Service定义

Service是一种可以长期在后台运行而不提供界面的应用组件。服务又可以分为前台服务和后台服务。1.前台服务前台服务是指是能让用户感知到服务正在运行,因此服务必须显示通知。比如QQ音乐的播放,如果打开了播放控制里的状态栏显示,当你播放音乐时,状态栏里会显示你正在播放的音乐,再比如下载软件,也同样会在状态栏里显示下载进度。
2.后台服务后台服务与前台服务相反,用户通常感知不到后台服务正在运行。

:前台服务的优先级很高,因此出现系统内存不足时系统也不会将前台服务回收,而后台服务在系统内存不足时有可能会被系统回收。

二 Service生命周期

1.service的生命周期
启动Service有个方法,startService()和bindService()。startService()对应关闭的服务的方法为stopSelf()和stopService(),bindService()对应关闭服务的方法为unbindService()。两种不同启动服务的方法也对应了两种不同的生命周期。如下图:
在这里插入图片描述
onStartCommand()返回值描述系统在终止服务后又重新启动服务时如何继续运行服务。
(1)START_NOT_STICKY
onstartCommand()中返回START_NOT_STICKY后,服务被终止了,则除非有待传递的挂起intent,否则系统不会重建服务。这样可以避免在不必要时浪费系统资源。
(2)START_STICKY:onstartCommand()中返回START_STICKY后,服务被终止了,系统会重建服务,除非有待传递的挂起intent,否则系统会调用intent为null的onStartCommand()。
(3)START_REDELIVER_INTENT:onstartCommand()中返回START_REDELIVER_INTENT后,服务被终止了,系统会重建服务,且通过传递给服务的最后一个intent,使用该intent调用onStartCommand()。所有挂起的intent均依次传递。

当使用startService()开启服务时,即使开启服务的应用组件已经被销毁,服务也不会被结束。当使用bindService()绑定服务时,绑定的应用组件被销毁时,服务会被结束。

:开启服务并不是只有这两种方式,还可以使用startService()启动服务之后,再使用bindService()绑定上该服务,此时调用stopSelf()或stopService()并不能结束服务,还需要调用unbindService(),服务才会真的被关闭。
2.前台服务的开启
如果android设备9.0及以上,需要在AndroidMAnifest.xml中添加FOREGROUND_SERVICE权限。因为前台服务必须显示通知,因此无论使用startService()还是bindService()开启服务,都需要再调用startForeground(),该服务才会显示通知。

:开启前台服务还可以使用startForegroundService(),startForegroundService()与startService()相似,只不过使用startForegroundService()后,5s内必须调用startForeground(),否则会在logcat中报错。

前台服务显示通知的例子:

public class ForegroundService extends Service {
    private final static String TAG = "ForegroundActivity";
    public ForegroundService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate: ");
        //通知渠道
        String channelId = "ChannelId";
        //Android8.0以上需要通过NotificationManager创建渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            NotificationChannel channel = new NotificationChannel(channelId,"消息推送", NotificationManager.IMPORTANCE_DEFAULT);
            NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
        }

        Notification notification = new NotificationCompat.Builder(this)
                //添加渠道
                .setChannelId(channelId)
                //通知的小图标
                .setSmallIcon(R.drawable.ic_launcher_background)
                //通知的标题
                .setContentTitle("This is title")
                //通知的内容
                .setContentText("This is content")
                //通知的优先级
                .setPriority(Notification.PRIORITY_DEFAULT)
                .build();
        startForeground(1,notification);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return null;
    }
}

三 Service与应用组件通信

1.startService()
应用组件可使用intent与服务进行通信,但如果需要服务返回结果给应用组件,则可以可以使用广播,利用广播中的intent给应用组件返回结果。例子:
在Service中:

	@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        //发送广播
        Intent broadcastIntent = new Intent("com.stu.broastcast");
        broadcastIntent.setPackage("com.homework.stu");
        broadcastIntent.putExtra("current_time",System.currentTimeMillis());
        Log.d(TAG, "onStartCommand: "+broadcastIntent.getLongExtra("current_time",0));
        sendBroadcast(broadcastIntent);
        return super.onStartCommand(intent, flags, startId);
    }

在Activity中:

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_foreground);
        Intent intent = new Intent(this,ForegroundService.class);
        Button button = findViewById(R.id.btn_startService);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //开启服务
                startService(intent);
            }

        });
        //广播注册
        BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d("ForegroundActivity", "onReceive: "+intent.getLongExtra("current_time",0));
            }
        };
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.stu.broastcast");
        //动态注册广播
        registerReceiver(broadcastReceiver,intentFilter);
    }

打印结果如下:1647764154.504 9657-9657/com.homework.stu D/ForegroundActivity: onStartCommand: 1647764154.504 9657-9657/com.homework.stu D/ForegroundActivity: onStartCommand: 16477641545041647764154.514 9657-9657/com.homework.stu D/ForegroundActivity: onReceive: 1647764154504
2.bindService()
使用bindService()绑定服务,主要使用binder进行通信。举个例子。模拟服务下载任务,并将下载进度实时显示在界面上。
界面:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ForegroundActivity"
    android:orientation="vertical">
    <Button
        android:id="@+id/btn_startService"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击下载">
    </Button>
    <Button
        android:id="@+id/btn_stopService"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="取消下载">
    </Button>

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:max="100"
        android:layout_gravity="center"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal">
    </ProgressBar>
</LinearLayout>

Service:

public class ForegroundService extends Service {
    private final static String TAG = "ForegroundActivity";
    /*
     *下载进度
     */
    private static int progress = 0;
    /*
    * 单线程池执行下载任务
    */
    private ExecutorService mSingleThreadExecutor = Executors.newSingleThreadExecutor();
    public ForegroundService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //通知渠道
        String channelId = "ChannelId";
        //Android8.0以上需要通过NotificationManager添加渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            NotificationChannel channel = new NotificationChannel(channelId,"消息推送", NotificationManager.IMPORTANCE_DEFAULT);
            NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
            manager.createNotificationChannel(channel);
        }

        Notification notification = new NotificationCompat.Builder(this)
                //添加渠道
                .setChannelId(channelId)
                //通知的小图标
                .setSmallIcon(R.drawable.ic_launcher_background)
                //通知的标题
                .setContentTitle("This is title")
                //通知的内容
                .setContentText("正在模拟下载...")
                //通知的优先级
                .setPriority(Notification.PRIORITY_DEFAULT)
                .build();
        startForeground(1,notification);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return new DownLoadBinder();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //移除状态栏的通知
        stopForeground(true);
    }

    public class DownLoadBinder extends Binder{
        /*
         *是否停止下载
         */
        private boolean isStop = false;
        public OnProgressListener onProgressListener;
        /*
        *开始下载
        */
        public void startLoad() {
            //模拟下载任务
            mSingleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    while (progress<100 && (!isStop)){
                        //下载进度
                        progress++;
                        //监听下载进度
                        onProgressListener.progress(progress);
                        Log.d(TAG, "run: "+progress);
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            });

        }

        /*
         *停止下载
         */
        public void stopLoad(){
            //取消下载
            isStop = true;
            mSingleThreadExecutor.shutdownNow();
        }

        public void setOnProgressListener(OnProgressListener onProgressListener){
            this.onProgressListener = onProgressListener;
        }

    }

    /*
     *下载进度接口
     */
    public interface OnProgressListener{
        void progress(int progress);
    }
}

Activity:
public class ForegroundActivity extends AppCompatActivity {
private ForegroundService.DownLoadBinder mDownLoadBinder;

private ServiceConnection mServiceConnection ;
/*
* 进度条
*/
private  ProgressBar progressBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_foreground);
    Intent intent = new Intent(this,ForegroundService.class);

// startService(intent);
Button button = findViewById(R.id.btn_startService);
progressBar = findViewById(R.id.progressBar);
mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mDownLoadBinder = (ForegroundService.DownLoadBinder) iBinder;
mDownLoadBinder.startLoad();
mDownLoadBinder.setOnProgressListener(new ForegroundService.OnProgressListener() {
@Override
public void progress(int progress) {
Log.d(“ForegroundActivity”, "progress: "+progress);
progressBar.setProgress(progress);
}
});

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mDownLoadBinder = null;
        }
    };
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //开启服务
            bindService(intent,mServiceConnection,BIND_AUTO_CREATE);
        }

    });
    Button cancel = findViewById(R.id.btn_stopService);
    cancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mDownLoadBinder.stopLoad();
            unbindService(mServiceConnection);
        }
    });
}

}

四 扩展IntentService

因为service是长期运行在后台的,如果多次调用startService(),让service处理多个请求,很有可能出现ANR的情况,比如service中使用Thread.sleep()线程睡眠十几秒,点击按钮调用startService(),再次按钮时就会出现ANR,这是因为按钮超过时间没有响应。面对处理多个请求的问题,因此扩展出了IntentService。使用intentService的优点:
(1)创建工作队列,将所有的intent逐个传递给onHandleIntent()实现。
(2)处理完所有的intent后会自动停止服务,而不需要再去调用stopSelf()。
举个栗子:
点击一个按钮,在点击事件中调用startService(intent1),startService(intent2)
Activity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_intent);
        Button btn_intent1 = findViewById(R.id.btn_start_intent);
        btn_intent1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent1 = new Intent(getBaseContext(),TestIntentService.class);
                intent1.setAction(ACTION_TEST1);

                Intent intent2 = new Intent(getBaseContext(),TestIntentService.class);
                intent2.setAction(ACTION_TEST2);
                startService(intent1);
                startService(intent2);
            }
        });

    }

IntentService:

public class TestIntentService extends IntentService {

    private final static String TAG = "TestIntentService";
    private static final String ACTION_TEST1= "com.homework.stu.action1";
    private static final String ACTION_TEST2 = "com.homework.stu.action2";

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

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_TEST1.equals(action)) {
                handleAction1();
            } else if (ACTION_TEST2.equals(action)) {
                handleAction2();
            }
        }
    }

    private void handleAction1() {
        Log.d(TAG, "handleAction1: "+System.currentTimeMillis());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    private void handleAction2() {
        Log.d(TAG, "handleAction2: "+System.currentTimeMillis());
    }
}

打印结果,先执行完intent1,再去执行intent2:
1647784083.991 20363-20420/com.homework.stu D/TestIntentService: handleAction1: 1647784083991
1647784088.992 20363-20420/com.homework.stu D/TestIntentService: handleAction2: 1647784088992

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值