将android中的服务置于前台

发布于 2024-10-27 04:05:27 字数 4012 浏览 0 评论 0原文

我有一个 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);

}

I have an android service where I don't want that the phone disables the services automatically.
I therefore try to put a notification into the notifcation bar.
When I try to do so my HTC Hero reboots.

I use the following code, what's wrong? It's partly copied from the reference.
Is there a good tutorial that explains how this API works?

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

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白芷 2024-11-03 04:05:27

好吧,它不应该重新启动,但示例中的代码至少有 2 个主要错误,并且不会按预期工作。我已经使用 Android 1.6 模拟器对其进行了测试,并且仅在进行以下更改后才对我起作用:

  1. invokeMethod() 显然是错误的,因为它忽略传递的参数并进行固定的方法调用。 IntelliJ IDEA 很容易发现这个问题,修复方法是将 mStartForeground.invoke(this, mStartForegroundArgs); 更改为 method.invoke(this, args);
  2. onCreate( )原始示例不会在1.6上初始化mSetForeground,因为return语句位于第一个catch中,而它必须位于第一个<尝试一下。尝试启动服务时,您将收到 NPE。删除 mStartForeground = mStopForeground = null; 之后的 return 并将其放置在 mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); 之后将解决这个问题。

更新: 看起来 Google 已经修复了 示例 开箱即用,它应该可以正常工作。

Well, it should not reboot, but the code from the sample has at least 2 major bugs and will not work as expected. I've tested it with Android 1.6 emulator and it worked for me only after the following changes:

  1. invokeMethod() is obviously wrong because it ignores the passed arguments and makes a fixed method call instead. IntelliJ IDEA spots this problem easily and the fix would be changing mStartForeground.invoke(this, mStartForegroundArgs); to method.invoke(this, args);
  2. onCreate() in the original sample will not initialize mSetForeground on 1.6 since return statement is in the first catch, while it must be in the first try instead. You'll get an NPE when trying to start the service. Removing return after mStartForeground = mStopForeground = null; and placing it after mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); will fix this problem.

UPDATE: Looks like Google has already fixed the sample and it should work fine out of the box.

半步萧音过轻尘 2024-11-03 04:05:27

谷歌没有解决这个问题。
对我有用的是将其放在开头而不是他们使用的内容:

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

google didn't fix the issue .
what worked for me is putting this in the beginning instead of what they use:

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};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文