Chapter 9
AsyncTask<Params, Progress, Result>()
new AsyncTask<Void, Integer, Boolean>() {
@Override
protected Boolean doInBackground(Void... params) {
Log.i("haha","doInBackground");
publishProgress(50);
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
Log.i("haha","onProgressUpdate");
Log.i("haha", ""+values[0]);
super.onProgressUpdate(values);
}
@Override
protected void onPreExecute() {
Log.i("haha","onPreExecute");
super.onPreExecute();
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
Log.i("haha","onPostExecute");
}
}.execute();
当后台任务中调用了 publishProgress 方法,onProgressUpdate 就会很快被调用
服务Service
onCreate onStartCommand
startService 时 服务未从创建过 第一次创建时调用 onCreate onStartCommand , 之后多次调用startService , 只有 onStartCommand 得以执行
context.stopService 或者 在service内部 调用 stopSelf方法
活动和服务的关联
public class LhyService extends Service {
MyBinder mBinder = new MyBinder();
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
class MyBinder extends Binder{
public void startToDo(){
Log.i("haha", "startToDo");
};
public void stopToDo(){
Log.i("haha", "stopToDo");
};
}
}
ServiceConnection conn= new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("haha", "ComponentName : "+name);
Log.i("haha", "onServiceDisconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LhyService.MyBinder myBinder = (MyBinder) service;
myBinder.startToDo();
}
};
bindService(serviceIntent, conn, BIND_AUTO_CREATE);
unbindService(conn);
任何一个服务在应用程序范围内都是通用的 可以和多个活动 activity进行绑定 绑定完成后 都可以获得相同的Binder实例
每个服务只存在于一个实例 所以不管调用了多少次 startService 方法 ,只要调用一次 stopService 或 stopSelf 方法 服务就会停下来
通过调用 bindService 来获取一个服务的持久连接 会调用onBind方法 如果服务还没有被创建 onCreate 方法会先于onBind方法执行 然后再执行 onBind方法
只要调用方和服务之间的连接没有断开 服务就会一直保持运行状态
如果一个活动 既调用 startService 方法 又调用了 bindService 方法 如何destroy掉这个服务呢
根据Android系统的机制 一个服务只要被启动或者被绑定之后,就会一直处于运行状态,必须要让以上两种条件同时不满足 才可以销毁服务 ,也就是说要同时调用 stopService 和 unbindService 方法 ,onDestroy 方法才可以被执行
服务的系统优先级
基本后台运行
内存不足的时候有可能被回收
前台服务和普通服务最大区别在于 会一直有一个正在运行的图标在系统状态栏显示 下拉状态栏会看到更加详细的信息 , 非常类似通知的效果
创建前台服务
public void onCreate() {
super.onCreate();
NotificationCompat.Builder mBuilder = new Builder(this);
mBuilder.setSmallIcon(R.drawable.ic_launcher);
mBuilder.setTicker("foreground service start");
mBuilder.setContentTitle("foreground service title");
mBuilder.setContentText("foreground service content");
Intent intent = new Intent(this,MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pi);
startForeground(1, mBuilder.build());
}
就是把通知的 notify方法 换为 startForeground方法 在onCreate方法里
服务中的代码默认是在主线程中的 ANR 多线程
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
//TODO
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
android 提供了一个 可以创建一个异步的、会自动停止的服务 IntentService 类
onHandleIntent方法是在子线程中的
public class YssService extends IntentService {
public YssService(String name) {
super(name);
}
public YssService() {
super("YssService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i("haha", "ThreadId : "+Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("haha", "onDestroy");
}
}
后台执行的 定时任务
两种方法 一种是 Java 的 Timer 类
一种是 Android 的 Alarm 机制
Timer 有一个明显的短板 不太适用于 那些需要长期在后台运行的定时任务
因为 为了让电池耐用 android 手机的休眠策略是 长时间不操作的情况 自动让 CPU 自动进入睡眠状态 ,这就有可能导致 Timer 中的定时任务无法正常运行。而Alarm机制则不存在这种情况。Alarm具有唤醒CUP的功能
Alarm 机制的用法 :
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
//异步执行的逻辑功能
Log.i("haha", "the service executed at "+new Date().toString());
}
}).start();
AlarmManager manager = (AlarmManager) this.getSystemService(ALARM_SERVICE);
int halfMinute = 30*1000;
// long triggerAtTime = SystemClock.elapsedRealtime()+halfMinute;
long triggerAtTime = System.currentTimeMillis()+halfMinute;
Intent i = new Intent(this,AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
// manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
manager.set(AlarmManager.RTC_WAKEUP, triggerAtTime, pi);
// manager.setExact(type, triggerAtMillis, operation);
return super.onStartCommand(intent, flags, startId);
}
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, LongRunService.class));
}
}
AlarmManager 通过 getSystemService(Context.ALARM_SERVICE)
manager.set(xx,xx,xx);
第一个xx 是 flag 和第二个 xx triggerAtTime是相对应的 trigger(触发)
flag 共有 四个参数可以选择
AlarmManager.ELAPSED_REALTIME_WAKEUP
表示让定时任务的触发时间从系统开机算起,并唤醒CPU
对应获取系统已开机运行的时间的方法 是 SystemClock.elapsedRealtime()
系统开机至今所经历的时间毫秒数
AlarmManager.ELAPSED_REALTIME
定时任务的触发时间从系统开机算起 但不会唤醒CPU
获取时间的方法同上
AlarmManager.RTC_WAKEUP
定时任务的触发时间 从 1970年1月1日0点开始算起 至今的时间加上要延时的时间 并唤醒CPU
获取时间的方法 System.currentTimeMillis()
AlarmManager.RTC
参照以上
第三个xx 是PendingIntent
需要注意的是 从android 4.4 版本开始 Alarm任务触发的时间 会变得不准确 有时候会延迟一段时间后任务才开始得到执行 系统在耗电性方面上进行了优化导致的 大幅度减少 CPU被唤醒的次数 有效延长电池的使用时间
如果要求 Alarm任务执行的时间必须准确无误 使用AlarmManager.setExact() 方法来替代 set