Android Api Demos登顶之路(五十三)Service Foreground Service Controller
来源:互联网 发布:java中缺省是什么意思 编辑:程序博客网 时间:2024/05/02 02:14
这个demo演示了如何在前台启动一个服务。由于服务是没有界面的,所以运行在前台的Service必须在屏幕 顶端的Status Bar提供一个Notification以提示用户有Service在运行。
* 前台运行的Service可以通过调用startForeground()使Service在前台运行。stopForeground停止 前台运行,但Service本身不会停止。
* startForeground,stopForeground是从2.0开始支持的,之前的版本采用setForeground。
* 本例为了支持2.0之前和2.0之后的版本,采用了Reflection(反射)的方法来来查找当前版本是否含 有startForeground和stopForeground,如果有则调用,没有则使用setForeground。
* activity_controller.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="5dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_marginBottom="10dp" android:text="@string/text"/> <Button android:id="@+id/start_foreground" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Service Foreground" android:layout_gravity="center_horizontal"/> <Button android:id="@+id/start_background" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start Service Background" android:layout_gravity="center_horizontal"/> <Button android:id="@+id/stop_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Stop Service" android:layout_gravity="center_horizontal"/></LinearLayout>
FregroundService
public class ForegroundService extends Service { private static final String ACTION_FOREGROUND = "com.fishtosky.FOREGROUND"; private static final String ACTION_BACKROUND = "com.fishtosky.BACKROUND"; // 定义class数组用于存放反射调用方法的参数的类型 private static final Class<?>[] mSetForegroundArgTypes = new Class[] { boolean.class }; private static final Class<?>[] mStartForegroundArgTypes = new Class[] { int.class, Notification.class }; private static final Class<?>[] mStopForegroundArgTypes = new Class[] { boolean.class }; private NotificationManager mNm; private Method mStartForeground, mSetForeground, mStopForeground; // 定义object数组,用于存储反射调用方法的参数 private Object[] mSetForegroundArgs = new Object[1]; private Object[] mStartForegroundArgs = new Object[2]; private Object[] mStopForegroundArgs = new Object[1]; @Override public void onCreate() { super.onCreate(); mNm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); // 如果StartForeground、StopForeground两个方法可用,则将这两个方法取出并保存在 // 两个方法类型的变量中,如果这两个方法不存在则将这两个变量置空 try { mStartForeground = getClass().getMethod("startForeground", mStartForegroundArgTypes); mStopForeground = getClass().getMethod("stopForeground", mStopForegroundArgTypes); } catch (NoSuchMethodException e) { mStartForeground = mStopForeground = null; e.printStackTrace(); } // 取出早期版本的SetForeground方法 try { mSetForeground = getClass().getMethod("setForeground", mSetForegroundArgTypes); } catch (NoSuchMethodException e) { throw new IllegalStateException( "OS doesn't have Service.startForeground OR Service.setForeground!"); } } // 定义一个调用方法的方法 private void invokeMethod(Method method, Object[] args) { // 调用的方法都在服务本身上,所以第一个参数设为this try { method.invoke(this, args); } catch (Exception e) { e.printStackTrace(); Log.w("TAG", "Unable to invoke method", e); } } // 定义服务运行在前台的方法 private void startForegroundCompat(int id, Notification notification) { // 如果运行在2.0以上的版本,通过mStartForeground或mStopForeground不为空判定 if (mStartForeground != null) { // 将一个具体的整数值转化为整形的实例(封装) mStartForegroundArgs[0] = Integer.valueOf(id); mStartForegroundArgs[1] = notification; invokeMethod(mStartForeground, mSetForegroundArgs); //return; } else { // 否则调用低版本的setForeground方法 mSetForegroundArgs[0] = Boolean.TRUE; invokeMethod(mSetForeground, mSetForegroundArgs); } // 发送消息通知 mNm.notify(R.string.app_name, notification); } // 停止在前台运行 private void stopForegroundCompat(int id) { mNm.cancel(id); if (mStopForeground != null) { mStopForegroundArgs[0] = Boolean.TRUE; invokeMethod(mStopForeground, mStopForegroundArgs); return; } mSetForegroundArgs[0] = Boolean.FALSE; invokeMethod(mSetForeground, mSetForegroundArgs); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { super.onDestroy(); stopForegroundCompat(R.string.app_name); } // 2.0以下版本当服务启动时调用该方法 @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); handleCommand(intent); } // 2.0以上版本当服务启动时调用该方法 @Override public int onStartCommand(Intent intent, int flags, int startId) { handleCommand(intent); // 返回START_STICKY表示当系统意外杀死服务时,服务会重新创建,并且调用onStartCommand()方法, // 但是它不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand() // 方法.这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。 // 在本例中我们希望服务一直处于运行状态,直到手动去停止它,所以我们返回该值。 return START_STICKY; } private void handleCommand(Intent intent) { if (ACTION_FOREGROUND.equals(intent.getAction())) { PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0); Notification.Builder builder = new Builder(this); builder.setSmallIcon(R.drawable.ic_launcher).setTicker("服务已经启动!") .setContentIntent(contentIntent) .setWhen(System.currentTimeMillis()) .setContentTitle("服务前台启动通知") .setContentText("直到停止前台服务,该通知将一直存在"); Notification noti = builder.build(); startForegroundCompat(R.string.app_name, noti); } if (ACTION_BACKROUND.equals(intent.getAction())) { stopForegroundCompat(R.string.app_name); } } // 主界面 public static class Controller extends Activity implements OnClickListener { private Button bt_start_foreground, bt_start_background, bt_stop_service; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_controller); bt_start_foreground = (Button) findViewById(R.id.start_foreground); bt_start_background = (Button) findViewById(R.id.start_background); bt_stop_service = (Button) findViewById(R.id.stop_service); bt_start_foreground.setOnClickListener(this); bt_start_background.setOnClickListener(this); bt_stop_service.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.start_foreground: Intent foreIntent = new Intent(ACTION_FOREGROUND); foreIntent.setClass(Controller.this, ForegroundService.class); startService(foreIntent); break; case R.id.start_background: Intent backIntent = new Intent(ACTION_BACKROUND); backIntent.setClass(Controller.this, ForegroundService.class); startService(backIntent); break; case R.id.stop_service: stopService(new Intent(Controller.this, ForegroundService.class)); break; default: break; } } }}
配置文件
<service android:name="com.fishtosky.foregroundservice.ForegroundService"></service> <activity android:name="com.fishtosky.foregroundservice.ForegroundService$Controller" android:label="@string/app_name" android:launchMode="singleTop"> <intent-filter > <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
0 0
- Android Api Demos登顶之路(五十三)Service Foreground Service Controller
- Android Api Demos登顶之路(五十)Notification-->Service Controller
- Android Api Demos登顶之路(五十四)Service IsolateService Controller
- Android Api Demos登顶之路(三十二)Alarm Service
- Android Api Demos登顶之路(五十五)Service Messenger Service
- Android Api Demos登顶之路(五十六)Service Remote Service
- Android Api Demos登顶之路(五十七)Service Remote Service Binding options
- Android Api Demos登顶之路(三十一)Alarm Controller
- Android Api Demos登顶之路(五十四)Service LocalService Binding
- Android Api Demos登顶之路(五十八)Service Start Argument Control
- Android Api Demos登顶之路(二)
- Android Api Demos登顶之路(三)
- Android Api Demos登顶之路(四)
- Android Api Demos登顶之路(五)
- Android Api Demos登顶之路(六)
- Android Api Demos登顶之路(七)
- Android Api Demos登顶之路(八)
- Android Api Demos登顶之路(九)
- java线程生命周期图解
- Spring 加载xml配置文件的方式 ApplicationContext
- 成为GEEK是个梦想,从这一刻出发。
- 3.GitHub译文之创建仓库分支
- presenting controller & presented controller 如何区分
- Android Api Demos登顶之路(五十三)Service Foreground Service Controller
- c#格式化数字
- SQL关于IN和EXISTS的用法和区别的比较
- 设计模式在游戏中的应用--观察者模式(十)
- hdoj 2883 kebab 【时间区间离散化 + 最大流】
- c++多态原理
- 内存泄露原因分析
- UINavigationController(loading...)
- java集合