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
原创粉丝点击