第八章
- Notification通知
书本上介绍的创建方式已经过时了
//第一步:获取状态通知栏管理
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//第二步:实例化通知栏构造器NotificationCompat.Builder:
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
//第三步:对Builder进行配置
// params
int smallIconId = R.mipmap.ic_launcher;
Bitmap largeIcon = ((BitmapDrawable) getResources().getDrawable(R.mipmap.ic_launcher)).getBitmap();
String info = "我是通知内容";
// action when clicked点击事件
Intent intent = new Intent();
intent.setAction("android.intent.action.VIEW");
Uri content_url = Uri.parse("http://www.baidu.com");
intent.setData(content_url);
//设置通知栏自定义的view
RemoteViews view = new RemoteViews(getPackageName(),
R.layout.button_play);
builder.setLargeIcon(largeIcon)// 设置图标
.setSmallIcon(smallIconId)
.setContentTitle("我是通知")// 在下拉通知栏中查看通知时,显示的通知的标题
.setContentText(info)// 在下拉植栏中查看通知时,显示的通知的内容
.setTicker(info)// 消息栏弹出来时显示的内容
.setContent(view)//设置自定义view,前面标题就没效果了
.setAutoCancel(true)// 点击后是否消失
.setWhen(System.currentTimeMillis())
.setPriority(Notification.PRIORITY_DEFAULT) //设置该通知优先级
.setDefaults(Notification.DEFAULT_ALL)
.setContentIntent(PendingIntent.getActivity(this, 0, intent, flag));//点击意图
final Notification n = builder.getNotification();
public final static int NOTIFICATION_ID = "MainActivity".hashCode();
manager.notify(NOTIFICATION_ID, n);
提醒标志符成员:
Notification.FLAG_SHOW_LIGHTS //三色灯提醒,在使用三色灯提醒时候必须加该标志符
Notification.FLAG_ONGOING_EVENT //发起正在运行事件(活动中)
Notification.FLAG_INSISTENT //让声音、振动无限循环,直到用户响应 (取消或者打开)
Notification.FLAG_ONLY_ALERT_ONCE //发起Notification后,铃声和震动均只执行一次
Notification.FLAG_AUTO_CANCEL //用户单击通知后自动消失
Notification.FLAG_NO_CLEAR //只有全部清除时,Notification才会清除 ,不清楚该通知(QQ的通知无法清除,就是用的这个)
Notification.FLAG_FOREGROUND_SERVICE //表示正在运行的服务
.setDefaults(int defaults)
//功能:向通知添加声音、闪灯和振动效果的最简单、使用默认(defaults)属性,可以组合多个属性(和方法1中提示效果一样的)
Notification.DEFAULT_VIBRATE //添加默认震动提醒 需要 VIBRATE permission
Notification.DEFAULT_SOUND // 添加默认声音提醒
Notification.DEFAULT_LIGHTS// 添加默认三色灯提醒
Notification.DEFAULT_ALL// 添加默认以上3种全部提醒
setVibrate(long[] pattern)//设置震动方式
.setVibrate(new long[] {0,300,500,700});
//延迟0ms,然后振动300ms,在延迟500ms,接着在振动700ms
.setLights(intledARGB ,intledOnMS ,intledOffMS )
//android支持三色灯提醒,这个方法就是设置不同场景下的不同颜色的灯
//其中ledARGB 表示灯光颜色、 ledOnMS 亮持续时间、ledOffMS 暗的时间
.setLights(0xff0000ff, 300, 0)
.setSound(Uri sound)//设置默认或则自定义的铃声,来提醒
//获取默认铃声
.setDefaults(Notification.DEFAULT_SOUND)
//获取自定义铃声
.setSound(Uri.parse("file:///sdcard/xx/xx.mp3"))
//获取Android多媒体库内的铃声
.setSound(Uri.withAppendedPath(Audio.Media.INTERNAL_CONTENT_URI, "5"))
.setPriority(int pri)
Notification.PRIORITY_DEFAULT
Notification.PRIORITY_HIGH
Notification.PRIORITY_LOW
Notification.PRIORITY_MAX
Notification.PRIORITY_MIN
setOngoing(boolean ongoing)
//设置为ture,表示它为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)
setProgress(int max, int progress,boolean indeterminate)
//设置带进度条的通知,可以在下载中使用
//此方法在4.0及以后版本才有用,如果为早期版本:需要自定义通知布局,其中包含ProgressBar视图
//如果为确定的进度条:调用setProgress(max, progress, false)来设置通知,在更新进度的时候在此发起通知更新progress,并且在下载完成后要移除进度条,通过调用setProgress(0, 0, false)既可。
PendingIntent
PendingIntent和Intent略有不同,它可以设置执行次数,主要用于远程服务通信、闹铃、通知、启动器、短信中,在一般情况下用的比较少
Notification支持多种Intent来响应单击事件、消除事件、处理紧急状态的全屏事件等。
这里就用到了setContentIntent(PendingIntent intent)来处理以上这么多的事件。
属性:
PendingIntent的位标识符:
FLAG_ONE_SHOT 表示返回的PendingIntent仅能执行一次,执行完后自动取消
FLAG_NO_CREATE 表示如果描述的PendingIntent不存在,并不创建相应的PendingIntent,而是返回NULL
FLAG_CANCEL_CURRENT 表示相应的PendingIntent已经存在,则取消前者,然后创建新的PendingIntent,这个有利于数据保持为最新的,可以用于即时通信的通信场景
FLAG_UPDATE_CURRENT 表示更新的PendingIntent
contentIntent:在通知窗口区域,Notification被单击时的响应事件由该intent触发;
deleteIntent:当用户点击全部清除按钮时,响应该清除事件的Intent;
fullScreenIntent:响应紧急状态的全屏事件(例如来电事件),也就是说通知来的时候,跳过在通知区域点击通知这一步,直接执行fullScreenIntent代表的事件。
//在执行了点击通知之后要跳转到指定的XXX的Activity的时候,可以设置以下方法来相应点击事件:
Intent intent = new Intent(context,XXX.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
mBuilder.setContentIntent(pendingIntent)
//在执行了清空全部的通知操作时候,可以设置以下方法来相应这个事件:
采用setDeleteIntent(PendingIntent intent)方法或按照以下写法
Intent deleteIntent = new Intent();
deleteIntent.setClass(context, XXXReceiver.class);
deleteIntent.setAction(DELETE_ACTION);
notification.deleteIntent = PendingIntent.getBroadcast(context, 0, deleteIntent, 0);
在响应紧急事件(如来电)时候,可以设置以下方法来相应这个事件:
采用setFullScreenIntent(PendingIntent intent, boolean highPriority)
2.接收和发送短信
//调用系统接口发送短信
String content = edtSend.getText().toString();
SmsManager smsManager = SmsManager.getDefault(); List<String> divideContents = smsManager.divideMessage(content);
for (String text : divideContents) { smsManager.sendTextMessage(smsWidget.str_number, null, text, null, null);
}
//调用系统的短信发送器
if(PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber)){
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:"+phoneNumber));
intent.putExtra("sms_body", message);
startActivity(intent);
}
//权限
<uses-permission android:name="android.permission.SEND_SMS" />
//接收短信
class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
String address = messages[0].getOriginatingAddress();
String fullMessage = "";
for (SmsMessage message : messages) {
fullMessage += message.getMessageBody();
}
sender.setText(address);
content.setText(fullMessage);
abortBroadcast();//有序广播进行拦截
}
}
//注册广播
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
receiveFilter.setPriority(100);//设置高的优先级
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
//监听发送短信的状态
class SendStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (getResultCode() == RESULT_OK) {
Toast.makeText(context, "Send succeeded", Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(context, "Send failed", Toast.LENGTH_LONG)
.show();
}
}
}
sendFilter = new IntentFilter();
sendFilter.addAction("SENT_SMS_ACTION");
sendStatusReceiver = new SendStatusReceiver();
registerReceiver(sendStatusReceiver, sendFilter);
send.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SmsManager smsManager = SmsManager.getDefault();
Intent sentIntent = new Intent("SENT_SMS_ACTION");
PendingIntent pi = PendingIntent.getBroadcast(
MainActivity.this, 0, sentIntent, 0); smsManager.sendTextMessage(to.getText().toString(), null,
msgInput.getText().toString(), pi, null);
}
});
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
3.调用摄像头和相册
File outputImage = new File(Environment.getExternalStorageDirectory(),
"output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
//相册的
File outputImage = new File(Environment.getExternalStorageDirectory(),
"output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
intent.putExtra("crop", true);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
}
break;
case CROP_PHOTO://裁剪照片
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
4.播放多媒体
//音频
setDataSource();设置要播放的音频文件的位置
prepare()在播放之前调用这个方法完成准备工作
start()开始或继续播放音乐
pause()暂停播放音乐
reset()重置到开始的状态
seekTo()从指定位置开始播放音乐
stop()停止播放音乐,调用这个方法后MediaPlayer无法再播放音乐
release() 释放掉与MediaPlayer对象相关的资源
isPlaying()判断音乐当前是否在播放
getDuration()获取音频文件的长度。
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");
mediaPlayer.setDataSource(file.getPath());
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
break;
case R.id.pause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
break;
case R.id.stop:
if (mediaPlayer.isPlaying()) {
mediaPlayer.reset();
initMediaPlayer();
}
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
//视频:
setVideoPath():设置要播放视频的位置
start(): 开始或继续播放视频
pause()暂停播放视频
resume()将视频从头开始播放
seekTo()从指定位置播放视频
isPlaying()判断当前是否在播放视频
getDuration()得到整个视频文件的时长
<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.3gp");
videoView.setVideoPath(file.getPath());
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!videoView.isPlaying()) {
videoView.start();
}
break;
case R.id.pause:
if (videoView.isPlaying()) {
videoView.pause();
}
break;
case R.id.replay:
if (videoView.isPlaying()) {
videoView.resume();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();//视频视频资源
}
}
第九章.服务service
1.android多线程
//子线程handler传值
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message);
}
}).start();
//handler接受值
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
text.setText("Nice to meet you");
break;
default:
break;
}
}
};
2.handler异步消息处理机制
- Message:是线程之间传递的消息,可以携带少量信息用于不同线程之间传递数据
- Handler:顾名思义就是处理者的意思,主要用来发送和处理信息,发送用handler的sendmessage()方法,经过一系列处理会传到handler的handleMessage()方法中
- MessageQueue:消息队列的意思,主要用来存放所有通过handler发送的信息,这部分消息会一直存在于消息队列中,等待被处理,每一个线程只会有一个messageQueue对象
Looper:是每个线程中messagequeue的管家,调用Looper.loop()f方法后就会进入一个无限循环中,然后每当发现MessageQueue中有一条消息,就会把它取出,并传递到handler的handlemessage方法中
3.AsyncTask:
创建一个类继承AsyncTask,要指定三个泛型阐述Params:在执行AsyncTask是要传入的参数,可以用于在后台服务中使用
- Progress:后台服务进行时用于显示进度
Result:返回值
重写四个方法:
onPreExecute()在后台服务开始前调用,用于一些界面上的初始化工作,例如显示一个进度条
- doInBackground(Params …)子线程中执行进行耗时操作的
- onProgressUpdate(progress…)显示进度,列如显示进度
- onPostExecute(Result)主线程更新ui
new AsyncTask().execute();
4.服务的使用
service的两种启动模式
onCreate();当服务被创建时调用,只调用一次。
onStartCommand();它与startService()对应,当服务启动后调用。
如果你重写了该方法,你就有责任自己去当任务结束以后,调stopSelf()或者stopService()来停止服务。如果你是绑定的服务,就不需重新该方法了。
onBind();它与bindService()对应,通过返回IBinder,来与service交流
onUnbind();取消绑定
onDestroy();当服务不再被使用时需要销毁时调用,你应该在这里用来停止线程,注销监听器,广播。
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);//启动服务
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);//停止服务
Binder机制
//activity和service通信
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public void startDownload() {
new Thread(new Runnable() {
@Override
public void run() {
// start downloading
}
}).start();
Log.d("MyService", "startDownload executed");
}
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d("MyService", "onBind executed");
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
//创建Notification
用于创建前台服务
// 在API11之后构建Notification的方式
Notification.Builder builder = new Notification.Builder
(this.getApplicationContext()); //获取一个Notification构造器
Intent nfIntent = new Intent(this, MainActivity.class);
builder.setContentIntent(PendingIntent.
getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
R.mipmap.ic_large)) // 设置下拉列表中的图标(大图标)
.setContentTitle("下拉列表中的Title") // 设置下拉列表里的标题
.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
.setContentText("要显示的内容") // 设置上下文内容
.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
Notification notification = builder.build(); // 获取构建好的Notification
notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
startForeground(110, notification);// 开始前台服务
Log.d("MyService", "onCreate executed");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "onStartCommand executed");
new Thread(new Runnable() {
@Override
public void run() {
// do something here
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);// 停止前台服务--参数:表示是否移除之前的通知
Log.d("MyService", "onDestroy executed");
}
}
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
//bind
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
//unbind
unbindService(connection);
5.IntentService:可以简单创建异步的,会自动停止的服务
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService
6.在前台运行的服务(设置版本区别)
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.Build.VERSION;
import android.util.Log;
public class ForegroundService extends Service {
private static final String TAG = "ForegroundService";
private boolean mReflectFlg = false;
private static final int NOTIFICATION_ID = 1; // 如果id设置为0,会导致不能设置为前台service
private static final Class<?>[] mSetForegroundSignature = new Class[] {
boolean.class};
private static final Class<?>[] mStartForegroundSignature = new Class[] {
int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] {
boolean.class};
private NotificationManager mNM;
private Method mSetForeground;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mSetForegroundArgs = new Object[1];
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
mNM = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
try {
mStartForeground = ForegroundService.class.getMethod("startForeground", mStartForegroundSignature);
mStopForeground = ForegroundService.class.getMethod("stopForeground", mStopForegroundSignature);
} catch (NoSuchMethodException e) {
mStartForeground = mStopForeground = null;
}
try {
mSetForeground = getClass().getMethod("setForeground",
mSetForegroundSignature);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"OS doesn't have Service.startForeground OR Service.setForeground!");
}
Notification.Builder builder = new Notification.Builder(this);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
builder.setContentIntent(contentIntent);
builder.setSmallIcon(R.drawable.icon);
builder.setTicker("Foreground Service Start");
builder.setContentTitle("Foreground Service");
builder.setContentText("Make this service run in the foreground.");
Notification notification = builder.build();
startForegroundCompat(NOTIFICATION_ID, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
stopForegroundCompat(NOTIFICATION_ID);
}
void invokeMethod(Method method, Object[] args) {
try {
method.invoke(this, args);
} catch (InvocationTargetException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke method", e);
} catch (IllegalAccessException e) {
// Should not happen.
Log.w("ApiDemos", "Unable to invoke method", e);
}
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
if (mReflectFlg) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
// Fall back on the old API.
mSetForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mSetForeground, mSetForegroundArgs);
mNM.notify(id, notification);
} else {
/* 还可以使用以下方法,当sdk大于等于5时,调用sdk现有的方法startForeground设置前台运行,
* 否则调用反射取得的sdk level 5(对应Android 2.0)以下才有的旧方法setForeground设置前台运行 */
if(VERSION.SDK_INT >= 5) {
startForeground(id, notification);
} else {
// Fall back on the old API.
mSetForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mSetForeground, mSetForegroundArgs);
mNM.notify(id, notification);
}
}
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
if (mReflectFlg) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mStopForeground, mStopForegroundArgs);
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
mSetForegroundArgs[0] = Boolean.FALSE;
invokeMethod(mSetForeground, mSetForegroundArgs);
} else {
/* 还可以使用以下方法,当sdk大于等于5时,调用sdk现有的方法stopForeground停止前台运行,
* 否则调用反射取得的sdk level 5(对应Android 2.0)以下才有的旧方法setForeground停止前台运行 */
if(VERSION.SDK_INT >= 5) {
stopForeground(true);
} else {
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
mSetForegroundArgs[0] = Boolean.FALSE;
invokeMethod(mSetForeground, mSetForegroundArgs);
}
}
}
}
7.IntentService有以下特点:(内部用到了handler)
(1) 它创建了一个独立的工作线程来处理所有的通过onStartCommand()传递给服务的intents。
(2) 创建了一个工作队列,来逐个发送intent给onHandleIntent()。
(3) 不需要主动调用stopSelft()来结束服务。因为,在所有的intent被处理完后,系统会自动关闭服务。
(4) 默认实现的onBind()返回null
(5) 默认实现的onStartCommand()的目的是将intent插入到工作队列中
8.定时后台任务
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d("LongRunningService", "executed at " + new Date().toString());
}
}).start();
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
int anHour = 60 * 60 * 1000;//一个小时
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
//一个小时后触发
return super.onStartCommand(intent, flags, startId);
}
set()的四个参数:
- 第一个是指定AlarmManager的工作类型
AlarmManager.ELAPSED_REALTIME:定时任务的出发时间从系统开机算起,但是不会唤醒CPU
ELAPSED_REALTIME_WAKEUP:触发时间从系统开机开始,会唤醒CPU。
RTC:时间从1970年1月1号0时算起,不唤醒CPU。
RTC_WAKEUP:时间从1970年1月1号0时算起,唤醒CPU。
POWER_OFF_WAKEUP:手机关机情况下也会使用 SystemClock.elapsedRealtime()
获取系统开机到现在时间的毫秒数System.currentTimeMillis()
1970年1月1号到现在的毫秒数第二个参数任务触发的时间,以毫秒为单位
- 第三个参数是PendingIntent
PendingIntent中
getActivity(Context, int, Intent, int) 跳转到一个activity组件
getBroadcast(Context, int, Intent, int) 发送一个广播组件
getService(Context, int, Intent, int) 启动一个服务组件
上面的getActivity()的意思其实是,获取一个PendingIntent对象,而且该对象日后激发时所做的事情是启动一个新activity。也就是说,当它异步激发时,会执行类似Context.startActivity()那样的动作。相应地,getBroadcast()和getService()所获取的PendingIntent对象在激发时,会分别执行类似Context..sendBroadcast()和Context.startService()这样的动作。
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, LongRunningService.class);
context.startService(i);
}
}
Intent intent = new Intent(this, LongRunningService.class);
startService(intent);
定时任务的流程就是,先在activity中启动service, 然后在onStartCommand()方法中执行延迟一个小时的操作,操作为发送一个广播(广播已经静态注册了),然后广播的onReceive()方法中有时去启动服务,只有一来就变成一个没一个小时在后台执行一次的长期存在的服务了。