Android Classandroidandroid基础知识点

【Android】Service前台服务的使用

2016-07-28  本文已影响21042人  紫豪

1.什么是前台服务

前台服务是那些被认为用户知道(用户所认可的)且在系统内存不足的时候不允许系统杀死的服务。前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除。
官方描述:
A foreground service(前台服务) is a service that's considered to be(被用户所认可的) something the user is actively aware of and thus not a candidate for(而不是一个候选的,可以在内存不足时,被系统杀死的) the system to kill when low on memory. A foreground service must provide a notification for the status bar(前台服务必须提供一个显示通知), which is placed under the "Ongoing" heading(它是不可以忽略的), which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.(意思是通知信息不能被忽略,除非服务停止或主动移除,否则将一直显示。)


2.为什么要使用前台服务

在一般情况下,Service几乎都是在后台运行,一直默默地做着辛苦的工作。但这种情况下,后台运行的Service系统优先级相对较低,当系统内存不足时,在后台运行的Service就有可能被回收。
  那么,如果我们希望Service可以一直保持运行状态且不会在内存不足的情况下被回收时,可以选择将需要保持运行的Service设置为前台服务

例:
App中的音乐播放服务应被设置在前台运行(前台服务)——在App后台运行时,便于用户明确知道它的当前操作、在状态栏中指明当前歌曲信息、提供对应操作。


3.如何创建一个前台服务

public class MusicPlayerService extends Service {
  
  private static final String TAG = MusicPlayerService.class.getSimpleName();
  
  @Override
  public void onCreate() {
      super.onCreate();
      Log.d(TAG, "onCreate()");
  }
  
  @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()");
       // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
  }
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  Log.d(TAG, "onStartCommand()");
  // 在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; //设置为默认的声音

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

其它Notification构建方式:
Notification(int icon, CharSequence tickerText, long when)
  This constructor was deprecated in API level 11. Use Notification.Builder instead.

// 已过时--在API11之后就被淘汰了,之后需要调用Notification.Builder()来构建Notification.
Notification notification = new Notification(R.mipmap.ic_launcher,
"前台服务测试",System.currentTimeMillis());

getNotification()
  This method was deprecated in API level 16. Use build() instead.

// 在API16之后,可以使用build()来进行Notification的构建 Notification
notification = new Notification.Builder(this.getApplicationContext())
  .setContentText("这是一个前台服务")
  .setSmallIcon(R.mipmap.ic_launcher)
  .setWhen(System.currentTimeMillis())
  .build();
// 参数一:唯一的通知标识;参数二:通知消息。
startForeground(110, notification);// 开始前台服务

注:当使用的通知ID一致时,只会更新当前Notification。

@Override
public void onDestroy() {
  Log.d(TAG, "onDestroy()");
  stopForeground(true);// 停止前台服务--参数:表示是否移除之前的通知
  super.onDestroy();
}

4.自定义Notification布局并设置点击事件

RemoteViews remoteViews = new RemoteViews(this.getPackageName(),
  R.layout.notification_layout);// 获取remoteViews(参数一:包名;参数二:布局资源)
builder = new Notification.Builder(this.getApplicationContext())
      .setContent(remoteViews);// 设置自定义的Notification内容
builder.setWhen(System.currentTimeMillis())
    .setSmallIcon(R.mipmap.ic_launcher);
  
Notification notification = builder.getNotification();// 获取构建好的通知--.build()最低要求在
                  // API16及以上版本上使用,低版本上可以使用.getNotification()。
Notificationnotification.defaults = Notification.DEFAULT_SOUND;//设置为默认的声音
  
startForeground(110, notification);// 开始前台服务
自定义效果.png
private static final int REQUEST_CODE = 100;
private static final String ACTION_PLAY = "play";
  
Intent intentPlay = new Intent(ACTION_PLAY);// 指定操作意图--设置对应的行为ACTION
PendingIntent pIntentPlay = PendingIntent.getBroadcast(this.getApplicationContext(),
REQUEST_CODE, intentPlay, PendingIntent.FLAG_UPDATE_CURRENT);// 取的一个PendingIntent,
                      // 它会发送一个广播,如同Context.sendBroadcast.
remoteViews.setOnClickPendingIntent(R.id.iv_pause, pIntentPlay);// 绑定点击事件(参数一:
  // 控件id;参数二:对应触发的PendingIntent)
// 动态注册广播
@Override
public void onCreate() {
  super.onCreate();
  Log.d(TAG, "onCreate()");
  
  playerReceiver = new PlayerReceiver();
  IntentFilter mFilter = new IntentFilter();
  
  mFilter.addAction(ACTION_PLAY);
  mFilter.addAction(ACTION_PAUSE);
  mFilter.addAction(ACTION_LAST);
  mFilter.addAction(ACTION_NEXT);
  
  registerReceiver(playerReceiver, mFilter);
}
@Override
public void onDestroy() {
  Log.d(TAG, "onDestroy()");
  
  stopForeground(true);// 停止前台服务
  if (playerReceiver != null)
    unregisterReceiver(playerReceiver);// 解除广播注册
  super.onDestroy();
}
<receiver
 android:name=".PlayerReceiver"
 android:exported="true">
 <intent-filter>
  <action android:name="play"/>
  <action android:name="pause"/>
  <action android:name="last"/>
  <action android:name="next"/>
 </intent-filter>
</receiver>
public class PlayerReceiver extends BroadcastReceiver {
  
  private static final String TAG = PlayerReceiver.class.getSimpleName();
  
  public PlayerReceiver() {
  }
  
  @Override
  public void onReceive(Context context, Intent intent) {
    // TODO: This method is called when the BroadcastReceiver is receiving
    String action = intent.getAction();// 获取对应Action
    Log.d(TAG,"action:"+action);
  
    if(action.equals(MusicPlayerService.ACTION_PLAY)){
      // 进行对应操作
    } else if(action.equals(MusicPlayerService.ACTION_PAUSE)){
    } else if(action.equals(MusicPlayerService.ACTION_LAST)){
    } else if(action.equals(MusicPlayerService.ACTION_NEXT)){
    } 
  
  }
}
点击后监听到的动作.png

1.建立对应的Intent(意图)--即指定对应操作的行为Action;
2.PendingIntent来处理意图,(Pending译为“待定的”、“延迟”,PendingIntent类提供了一种创建可由其它应用程序在稍晚时间触发的Intent的机制--推荐阅读
解析Android延迟消息(PendingIntent)处理

3.通过RemoteViews.setOnClickPendingIntent(int viewId,PendingIntent pendingIntent)方法来为指定的控件绑定对应的意图;
4.在Service中注册广播,监听对应操作。


5.修改自定义通知(Notification)上的显示内容

在自定义通知布局后,我们在有些场景下需要修改一些控件的显示内容(如修改TextView显示文字、ImageView图片、ProgressBar进度等),那么我们可以通过如Notification.contentViewsetTextViewText、setImageViewBitmap、setProgressBar等方法打成效果,示例代码如下:

notification.contentView.setTextViewText(R.id.title_tv, "标题");

注:方法的差异不大,都需要传递控件的id,需要设置的内容、属性等参数。


6.前台服务与普通服务的区别

7.Service系列拓展阅读

【Android】Service那点事儿
【Android】远程服务(Remote Service)的使用

用到的图片资源(看不清没关系,右击保存即可...):

last_img.png play_img.png pause_img.png next_img.png
上一篇 下一篇

猜你喜欢

热点阅读