Вывод сервиса в Android на первый план - PullRequest
1 голос
/ 28 марта 2011

У меня есть служба Android, где я не хочу, чтобы телефон отключал службы автоматически.Поэтому я пытаюсь поместить уведомление в панель уведомлений.Когда я пытаюсь это сделать, мой HTC Hero перезагружается.

Я использую следующий код, что не так?Он частично скопирован из ссылки .Есть хороший учебник, который объясняет, как работает этот API?

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];

void invokeMethod(Method method, Object[] args) {
    try {
        mStartForeground.invoke(this, mStartForegroundArgs);
    } 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 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);
}

/**
 * This is a wrapper around the new stopForeground method, using the older
 * APIs if it is not available.
 */
void stopForegroundCompat(int id) {
    // If we have the new stopForeground API, then use it.
    if (mStopForeground != null) {
        mStopForegroundArgs[0] = Boolean.TRUE;
        try {
            mStopForeground.invoke(this, mStopForegroundArgs);
        } catch (InvocationTargetException e) {
            // Should not happen.
            Log.w("ApiDemos", "Unable to invoke stopForeground", e);
        } catch (IllegalAccessException e) {
            // Should not happen.
            Log.w("ApiDemos", "Unable to invoke stopForeground", e);
        }
        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);
}

private void setupNotification(){
    mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
    try {
        mStartForeground = getClass().getMethod("startForeground",
                mStartForegroundSignature);
        mStopForeground = getClass().getMethod("stopForeground",
                mStopForegroundSignature);
    } catch (NoSuchMethodException e) {
        // Running on an older platform.
        mStartForeground = mStopForeground = null;
        return;
    }
    try {
        mSetForeground = getClass().getMethod("setForeground",
                mSetForegroundSignature);
    } catch (NoSuchMethodException e) {
        throw new IllegalStateException(
                "OS doesn't have Service.startForeground OR Service.setForeground!");
    }

    CharSequence text = getText(R.string.notification_active_text);
    // Set the icon, scrolling text and timestamp
    Notification notification = new Notification(R.drawable.icon, text,
            System.currentTimeMillis());
    startForegroundCompat(
            R.string.foreground_service_started, 
            notification);

}

Ответы [ 2 ]

3 голосов
/ 03 мая 2011

Ну, это не должно перезагружаться, но код из примера имеет как минимум 2 основные ошибки и не будет работать, как ожидалось. Я тестировал его с эмулятором Android 1.6, и он работал у меня только после следующих изменений:

  1. invokeMethod () явно неверен, поскольку игнорирует переданные аргументы и вместо этого выполняет фиксированный вызов метода. IntelliJ IDEA легко обнаружит эту проблему, и исправление будет изменено с mStartForeground.invoke(this, mStartForegroundArgs); на method.invoke(this, args);
  2. onCreate () в исходном образце не будет инициализировать mSetForeground в 1.6, поскольку return находится в первом поймать , в то время как он должен быть в первой вместо . Вы получите NPE при попытке запустить службу. Удаление return после mStartForeground = mStopForeground = null; и размещение его после mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); исправит эту проблему.

ОБНОВЛЕНИЕ: Похоже, Google уже исправил образец , и он должен нормально работать из коробки.

0 голосов
/ 10 июня 2012

Google не устранил проблему. что сработало для меня - это поставить это в начале вместо того, что они используют:

private static final Class<?>[] mSetForegroundSignature   = new Class[] {Boolean.TYPE};
private static final Class<?>[] mStartForegroundSignature = new Class[] {Integer.TYPE, Notification.class};
private static final Class<?>[] mStopForegroundSignature  = new Class[] {Boolean.TYPE};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...