intentService和foregroundService的使用

1.intentservice

IntentService具有以下特点:
(1) IntentService自带一个工作线程,当我们的Service需要做一些可能会阻塞主线程的工作的时候可以考虑使用IntentService。

(2) 我们需要将要做的实际工作放入到IntentService的onHandleIntent回到方法中,当我们通过startService(intent)启动了IntentService之后,最终Android Framework会回调其onHandleIntent方法,并将intent传入该方法,这样我们就可以根据intent去做实际工作,并且onHandleIntent运行在IntentService所持有的工作线程中,而非主线程。

(3) 当我们通过startService多次启动了IntentService,这会产生多个job,由于IntentService只持有一个工作线程,所以每次onHandleIntent只能处理一个job。面多多个job,IntentService会如何处理?处理方式是one-by-one,也就是一个一个按照先后顺序处理,先将intent1传入onHandleIntent,让其完成job1,然后将intent2传入onHandleIntent,让其完成job2…这样直至所有job完成,所以我们IntentService不能并行的执行多个job,只能一个一个的按照先后顺序完成,当所有job完成的时候IntentService就销毁了,会执行onDestroy回调方法。

来自:https://blog.csdn.net/wjlsxl_whb/article/details/78036932

2.写法:

写一个类继承自intentservice,无参构造方法里面要调用super(tag),重写onHandleIntent(),在里面做耗时操作即可。

package com.ysl.myandroidbase;

import android.app.IntentService;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.util.Log;

public class MyIntentService extends IntentService {
    public static final String TAG = "MyIntentService";

    public MyIntentService() {
        super(TAG);
        Log.d(TAG, "MyIntentService() is invoke "+Thread.currentThread().getId());
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate is invoke "+Thread.currentThread().getId());
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand is invoke "+Thread.currentThread().getId());
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        //做耗时操作
        Log.d(TAG, "onHandleIntent is invoke "+Thread.currentThread().getId());
        int age = intent.getIntExtra("age",0);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "age = "+age);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy is invoke "+Thread.currentThread().getId());
    }
}

activity启动service,和普通的方式一样:

intent = new Intent(ServiceActivity.this, MyIntentService.class);
                intent.putExtra("age", 15);
                startService(intent);

看一下结果:

onHandleIntent方法在一个子线程中调用,并且执行了耗时任务,在任务结束后,自动调用ondestroy销毁。

service本身是依附在主线程的,假如要在service中执行一些耗时操作。我们就可以使用intentservice来代替service。

3.foregroundService

service默认情况下是后台服务,这意味着service在系统回收内存(比如在浏览器里显示大图片)的时候可以被kill掉。如果你比较在意这个service的挂掉,比如像后台音乐播放器这种突然挂了会影响用户的情况,就可以使用ForegroundService来提示用户。

使用该方法可以让后台服务变成前台服务,使服务的优先级变低,不容易被回收掉。可以用来做进程保活。可以让当前进程持有这样一个服务,当当前进程进入后台之后,由于持有前台服务,会使得当前进程的优先级变低。一般情况下,若当前进程不持有前台进程,当前进程进入后台之后优先级为5,若持有前台进程,优先级变为2。使得不容易被回收。

(1)我的写法:

package com.ysl.myandroidbase;

import android.app.Notification;
import android.app.Notification.Builder;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

public class ForegroundService extends Service {
    public static final String TAG = "ForegroundService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind is invoke");
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate is invoke");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand is invoke");

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, ServiceActivity.class), 0);
        Notification notification = new Notification.Builder(this)
                .setContentIntent(pendingIntent)
                .setContentTitle("设置下拉列表里的标题")
                .setContentText("设置要显示的内容")
                .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher))
                .setSmallIcon(R.mipmap.ic_launcher)
                .setWhen(System.currentTimeMillis() - 24*60*60*1000)//设置通知上的时间,now,1d...
                .setShowWhen(true)//设置是否显示时间
                .build();
        //使用startForeground方法开启前台服务
        startForeground(1, notification);

        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //关闭前台服务
        stopForeground(true);
        Log.d(TAG, "onDestroy is invoke");
    }
}

从代码可以看到,在onStartCommand方法中构建了notification。然后调用startForeground()方法就可以启动前台服务了。并且此时会有一个通知栏消息弹出。

注:startForeground(1, notification);第一个参数不能为0,否则前台服务启动失败。

关于:

setWhen(System.currentTimeMillis())和setWhen(System.currentTimeMillis() - 24*60*60*1000)//设置通知上的时间,now,1d... .

setShowWhen(true)//设置是否显示时间,如上第一张图,就是设置为false,不显示时间的样子。

前台服务的通知栏消息是一直存在的。

在服务的onDestroy()中设置notification.setAutoCancel(true)或者不写这句话。只要是手动停止服务的,通知栏的消息都会消失。但如果是按菜单键直接杀死app,通知栏的消息图标不会消失。

4.虽然前台进程可以避免被杀死,但通知栏的图标对于强迫症来说也是一种折磨。怎么才能去掉它呢?

可以使用2个Service都用startForeground设置为前台进程,但他们使用相同的Notification ID,那么他们只会产生一个通知,然后把其中一个Service取消前台效果,那么就会把通知关闭,剩下的那个Service就是前台Service了,而且通知栏没有通知。

放置前台的service:

package com.ysl.myandroidbase;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.BitmapFactory;
import android.os.Build.VERSION;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

public class ForegroundService extends Service {
    public static final String TAG = "ForegroundService";
    public static final int NOTICE_ID = 100;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind is invoke");
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate is invoke");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand is invoke");
        //使用startForeground方法开启前台服务
        startForeground(NOTICE_ID, getNotification());

        startService(new Intent(this, CancelNoticeService.class));

        return super.onStartCommand(intent, flags, startId);
    }

    private Notification getNotification() {
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, ServiceActivity.class), 0);
        return new Notification.Builder(this)
                .setContentIntent(pendingIntent)
                .setContentTitle("设置下拉列表里的标题")
                .setContentText("设置要显示的内容")
                .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher))
                .setSmallIcon(R.mipmap.ic_launcher)
                .setWhen(System.currentTimeMillis() - 24*60*60*1000)//设置通知上的时间,now,1d...
                .setShowWhen(true)//设置是否显示时间
                .setAutoCancel(true)
                .build();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopForeground(true);
        Log.d(TAG, "onDestroy is invoke");
    }
}

用于取消通知栏图标的service:

package com.ysl.myandroidbase;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.util.Log;

public class CancelNoticeService extends Service {
    public static final String TAG = "CancelNoticeService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate is invoke");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand is invoke");
        startForeground(ForegroundService.NOTICE_ID, new Notification());
        stopForeground(true);
        stopSelf();//停止此服务减少资源消耗
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy is invoke");
    }
}

看上面的代码:在前台service中,startService(new Intent(this, CancelNoticeService.class));启动了取消图标的service。

在取消图标的service中,做了三件事:1.使用和前台service相同ID来使辅助服务变成前台服务,这时会和前台服务公用一个通知栏图标。2.再把此服务停止前台操作,调用stopForeground(true)。3.调用stopSelf();停止服务。减少资源消耗。

这种方式可以取消图标,但图标还是会在通知栏闪一下。使用这种方式是不可避免的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值