service的概念
1、service组件是可执行的程序,也是有自己的生命周期,是四大组件常用组件之一。创建、配置service和Activity的过程相似
service的作用
1、Service非常适用于去执行那些不需要和用户交互而且还要长期运行在后台的任务
service的特点
1、Service默认线程为UI主线程,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作
2、Service的运行不依赖于任何用户界面,即使程序被切换到后台或者用户打开另一个应用程序,Service仍然能够保持正常运行
3、当某个应用程序进程被杀掉时,所有依赖于该进程的Service也会停止运行
service的生命周期
service的使用
1、创建、配置service
1)定义一个继承service的子类
2)在androidManifest.xml文件中配置该service
public class MyService extends Service {
private static final String TAG = "MyService";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
}
/**
* 使用线程暂停的方式来模拟耗时任务暂停20秒导致ANR
*
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
long endTime = System.currentTimeMillis() + 20 * 1000;
Log.i(TAG, "onStartCommand");
// while (System.currentTimeMillis() < endTime) {
// synchronized (this) {
// try {
// wait(endTime - System.currentTimeMillis());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
// }
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
}
}
//activity类
public class MainActivity extends Activity {
ActivityMainBinding binding;
private Boolean isFirst = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
// initView();
initService();
}
private void initService() {
final Intent intent = new Intent();
final Intent intent = new Intent(MainActivity.this,MyService.class);//显式启动
binding.btStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(intent);//启动service
}
});
binding.btStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(intent);/停止service
}
});
//
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
//或者在androidmanifest.xml中注册
private void initService() {
// final Intent intent = new Intent(MainActivity.this,MyService.class);//显式启动
intent.setAction("com.example.broadcastreceiverdemo.FIRST_SERVICE");//隐式启动
binding.btStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(intent);//启动service
}
});
binding.btStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(intent);//停止service
}
});
//
}
//注册
<service android:name=".MyService">
<intent-filter>
<action android:name="com.example.broadcastreceiverdemo.FIRST_SERVICE" />
</intent-filter>
</service>
service绑定本地并与之通信(onBind())
1、如果service和访问者之间需要进行方法调用或数据交换使用bindservice()和unbindservice()方法启动和关闭
2、bindService方法的完整的构造为bindService(Intent service, ServiceConnection conn, int flags)
参数service:该参数通过Intent指定要启动的Service
参数conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况
参数flags:指定绑定时是否自动创建Service(如果Service还未创建),该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)
public class BindService extends Service {
private static final String TAG = "BindService";
private int count;
private boolean quit;
//定义onBinder方法返回的对象
private MyBinder binder = new MyBinder();
/**
* 必须实现该回调方法
*
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
return binder;
}
/**
* 自定义Binder
* 外部调用service中的方法,通过继承IBinder类来实现IBinder
*/
public class MyBinder extends Binder {
// 传递服务中需要的控件
public int getCount() {
return count;
}
}
/**
* 延迟3秒增加一次计数
*/
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
new Thread() {
@Override
public void run() {
while (!quit) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
}.start();
}
//断开时使用该方法
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind");
return true;
}
//被关闭之前调用该方法
@Override
public void onDestroy() {
super.onDestroy();
this.quit = true;
Log.i(TAG, "onDestroy");
}
}
<service android:name=".BindService">
<intent-filter>
<action android:name="com.example.broadcastreceiverdemo.BIND_SERVICE" />
</intent-filter>
</service>
public class SecondActivity extends Activity {
private static final String TAG = "SecondActivity";
ActivitySecondBinding binding;
private BindService.MyBinder binder;
private ServiceConnection conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_second);
initService();
}
private void initService() {
//为Intent设置action属性
final Intent intent = new Intent();
intent.setAction("com.example.broadcastreceiverdemo.BIND_SERVICE");
binding.btStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//定义一个ServiceConnection对象
//当Activity与service连接成功是回调该方法
conn = new ServiceConnection() {
//当Activity与service连接成功是回调该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected");
//获取service的onBind方法所返回的MyBinder对象
binder = (BindService.MyBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected");
}
};
//绑定指定服务
bindService(intent, conn, Service.BIND_AUTO_CREATE);
}
});
binding.btStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//解除绑定
if(conn!=null){
unbindService(conn);
}
}
});
binding.btGetStatus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//获取并显示service的count值
Toast.makeText(SecondActivity.this, "servicede count值为:" + binder.getCount(), Toast.LENGTH_SHORT).show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if(conn!=null){
unbindService(conn);
}
}
}
IntentService的使用
1、IntentService介绍
IntentService是service的子类,因此它不是普通的service比普通service增加了额外的功能
2、service存在的缺点
1)service不会专门启动一条单独的进程,service与它所在应用位于同一个进程中
2)service也不是专门一条新的线程,因此不应该在service中直接处理耗时的任务(容易出现ANR)
public class IntentServiceActivity extends Activity {
ActivityIntentServiceBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_intent_service);
initClick();
}
private void initClick() {
// binding.btService.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Intent intent=new Intent(IntentServiceActivity.this,MyService.class);
// startService(intent);
// }
// });
binding.btIntentService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(IntentServiceActivity.this,MyIntentService.class);
startService(intent);//开启服务
}
});
}
}
静态注册
<service android:name=".MyIntentService" />
在IntentService中操作耗时动作,不会出现ANR
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
/**
*/
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
long endTime = System.currentTimeMillis() + 20 * 1000;
Log.i(TAG, "onStartCommand");
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Log.i(TAG, "-----耗时任务------");
}
}
service保活机制
1、保活的原因
1)、Android系统回收;
2)、手机厂商定制管理系统,如电源管理、内存管理等;
3)、第三方清理软件;
4)、用户手动结束。
2、保活手段
2.1适合Android5.0以下的方法
1)修改Service的onStartCommand 方法返回值
onStartCommand()返回一个整型值,用来描述系统在杀掉服务后是否要继续启动服务,返回值有三种:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象,随后系统会尝试重新创建service。
START_NOT_STICKY:使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统将会把它置为started状态,系统不会自动重启该服务。
START_REDELIVER_INTENT:使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,它将会在隔一段时间后自动重启该服务,并将Intent的值传入。
2)前台服务
前台服务是被认为是用户已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程,前台服务必须有一个 notification 在状态栏中显示。
NotificationCompat.Builder nb = new NotificationCompat.Builder(this);
nb.setOngoing(true);
nb.setContentTitle(getString(R.string.app_name));
nb.setContentText(getString(R.string.app_name));
nb.setSmallIcon(R.drawable.icon);
PendingIntent pendingintent =PendingIntent.getActivity(this, 0, new Intent(this, Main.class), 0);
nb.setContentIntent(pendingIntent);
startForeground(1423, nb.build());
3)监听系统广播
通过监听系统的一些广播,比如:手机开机、解锁屏、网络连接状态变更、应用状态改变等等,然后判断Service是否存活,若否则启动Service。
4)应用之间互拉
利用不同的app进程使用广播来进行相互唤醒,比如支付宝、淘宝、天猫、等阿里系的app,如果打开其中任意一个应用,其它阿里系的app也会唤醒了,其实BAT系都差不多。另外现在很多推送sdk也会唤醒app。
5)利用Android系统提供的帐号和同步机制实现
在应用中建立一个帐号,然后开启自动同步并设置同步间隔时间,利用同步唤醒app。账号建立后在手机设置-账号中能看到应用的账号,用户可能会删除账号或者停止同步,故需要经常检测账号是否能正常同步。
//建立账号
AccountManager accountManager = AccountManager.get(mContext);
Account riderAccount = new Account(mContext.getString(R.string.app_name), Constant.ACCOUNT_TYPE);
accountManager.addAccountExplicitly(riderAccount, mContext.getString(R.string.app_name), null);
ContentResolver.setIsSyncable(riderAccount, Constant.ACCOUNT_AUTHORITY, 1);
ContentResolver.addPeriodicSync(riderAccount, Constant.ACCOUNT_AUTHORITY, new Bundle(), 60);
//开启同步
ContentResolver.setSyncAutomatically(riderAccount, Constant.ACCOUNT_AUTHORITY, true);
2.2我们知道在Android5.0之前,Android源代码还是有不小漏洞的,导致很多不光明的手段来进行++保活++。但是在Android5.0之后,很多都是可以被APP杀死的。Android5.0之后Android提供了JobService和JobScheduler这两的类。我们可以通过这个JobScheduler来进行保活。
1)JobScheduler
JobScheduler是Job的调度类,负责执行,取消任务等逻辑,具体看下JobScheduler的获取和类代码。
JobScheduler jobScheduler = (JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE)
/*
*参数:JobInfo采用Builder的设计模式,对需要执行的Job任务信息进行的封装。
*返回值:RESULT_SUCCESS=1 RESULT_FAILURE=0 表示执行成功或失败
*/
public abstract int schedule(JobInfo job);
/**通过指定的jobId取消Job任务*/
public abstract void cancel(int jobId);
/**取消所有的Job任务*/
public abstract void cancelAll();
/**获取所有的未执行的Job任务*/
public abstract @NonNull List<JobInfo> getAllPendingJobs();
/**获取指定的Job未执行的任务*/
public abstract @Nullable JobInfo getPendingJob(int jobId);
2)JobService
/*
*需要重写,开始jobScheduler的方法
*/
public abstract boolean onStartJob(JobParameters params);
/*
*停止JobScheduler的方法
*/
public abstract boolean onStopJob(JobParameters params);
/*
*完成JobScheduler的方法
*/
public final void jobFinished(JobParameters params, boolean needsReschedule) {
ensureHandler();
Message m = Message.obtain(mHandler, MSG_JOB_FINISHED, params);
m.arg2 = needsReschedule ? 1 : 0;
m.sendToTarget();
}
在JobService中,这几个方法都是通过Handler发送Message,在Handler中调用了IJobCallback的底层的实现
3)JobInfo
// jobId每个Job任务的id
int jobId = 1;
// 指定你需要执行的JobService
ComponentName name = new ComponentName(getPackageName(), MyJobService.class.getName()));
JobInfo.Builder builder = new JobInfo.Bulider(jobId, name);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NONE); //设置需要的网络条件,默认NETWORK_TYPE_NONE
builder.setPeriodic(3000);//设置间隔时间
builder.setMinimumLatency(3000);// 设置任务运行最少延迟时间
builder.setOverrideDeadline(50000);// 设置deadline,若到期还没有达到规定的条件则会开始执行
builder.setRequiresCharging(true);// 设置是否充电的条件,默认false
builder.setRequiresDeviceIdle(false);// 设置手机是否空闲的条件,默认false
builder.setPersisted(true);//设备重启之后你的任务是否还要继续执行
JobInfo info = builder.build();
3、完整代码实例
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.btn);
button.setText(getClass().getSimpleName());
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(getPackageName(), MyJobService.class.getName()))
.setPeriodic(2000)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.build();
jobScheduler.schedule(jobInfo);
}
}
});
}
}
//服务类型
MyService类
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)//API需要在21及以上
public class MyJobService extends JobService {
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Toast.makeText(MyJobService.this, "MyJobService", Toast.LENGTH_SHORT).show();
JobParameters param = (JobParameters) msg.obj;
jobFinished(param, true);
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
return true;
}
});
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public boolean onStartJob(JobParameters params) {
Message m = Message.obtain();
m.obj = params;
handler.sendMessage(m);
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
handler.removeCallbacksAndMessages(null);
return false;
}
}
//静态注册
<service
android:name=".MyJobService"
android:permission="android.permission.BIND_JOB_SERVICE">
</service>