Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/232.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何创建持久的Android服务_Java_Android_Service_Android Notifications - Fatal编程技术网

Java 如何创建持久的Android服务

Java 如何创建持久的Android服务,java,android,service,android-notifications,Java,Android,Service,Android Notifications,在用于在上述回合中运行服务的中,提供了以下示例代码: Notification Notification=新通知(R.drawable.icon,getText(R.string.ticker\u text), System.currentTimeMillis()); Intent notificationIntent=新的意图(例如,activity.class); PendingEvent PendingEvent=PendingEvent.getActivity(this,0,notifi

在用于在上述回合中运行服务的中,提供了以下示例代码:

Notification Notification=新通知(R.drawable.icon,getText(R.string.ticker\u text),
System.currentTimeMillis());
Intent notificationIntent=新的意图(例如,activity.class);
PendingEvent PendingEvent=PendingEvent.getActivity(this,0,notificationIntent,0);
setLatestEventInfo(this,getText(R.string.notification_title),
getText(R.string.notification_message),pendingent);
startForeground(正在进行的通知,通知ID);

但是,此代码不起作用。首先,不推荐使用用于通知的。其次,该方法不再包含在类中。当我消除这些并以正确的方式创建通知时,会出现如下错误:

Caused by: java.lang.NullPointerException: class name is null
  at android.content.ComponentName.<init>(ComponentName.java:114)
  at android.app.Service.startForeground(Service.java:654)
  at com.vcapra1.motionsensors.MainActivity.startService(MainActivity.java:53)
当我使用notificationManager.notify时(1,notification)行,创建了一个通知,但它不是持久的,不会启动服务(当然,这是不应该发生的)。但是,当我使用
startForeground(1,通知)时行,应用程序会因上面的堆栈跟踪而崩溃


因此,我的最后一个问题是:启动一个即使应用程序关闭也能继续运行的服务的正确方法是什么?我检查了几个来源,它们都包括我在Android文档中找到的方法。

您必须使用Notification.Builder,而不是通知的类构造函数

以下是使用操作启动前台服务的示例:

private Notification getForegroundNotification() {      
    Intent showTaskIntent = MyActivity.createStartIntent(this, mContext);

    PendingIntent contentIntent = PendingIntent.getActivity(
            getApplicationContext(),
            0,
            showTaskIntent,
            PendingIntent.FLAG_UPDATE_CURRENT);


    Notification.Builder builder = new Notification.Builder(this);

    builder.setContentTitle(getString(R.string.title))
        //.setContentText(getString(R.string.notification_text))
        .setSmallIcon(R.drawable.notification_white)
        .setContentIntent(contentIntent);



    Intent shutdownActionIntent = new Intent(this, MyService.class);
    shutdownActionIntent.setAction(SHUTDOWN_NOTIFICATION_ACTION);

    PendingIntent shutdownPendingIntent = PendingIntent.getService(
            getApplicationContext(),
            1,
            shutdownActionIntent,
            PendingIntent.FLAG_UPDATE_CURRENT);

    builder.addAction(android.R.drawable.ic_lock_power_off, getString(R.string.shutdown_action), shutdownPendingIntent);

    if(isRunningJellybeanOrLater()) {
        builder.setPriority(Notification.PRIORITY_MAX);
        return builder.build();
    } else {
        return builder.getNotification();
    }
} 
这是您如何开始的:

void handleStartAction() {      
        Notification notification = getForegroundNotification();
        startForeground(FOREGROUND_NOTIFICATION_ID, notification);
    }
从服务生命周期方法(例如,
onCreate()
onStartCommand()
)或由这些生命周期方法之一调用的方法(例如,
IntentService的
onHandleIntent()
)调用
startForeground()

例如,当在
OnHandleContent()中进行下载时,此服务使用前台
通知

(来自)


堆栈跟踪表明您正试图从
MainActivity
调用
startForeground()
,这应该是不可能的,而且肯定不是一种合适的模式。

以下是示例。应该行得通。“当我删除这些,并创建一个正确的通知”——而不是张贴你不使用的代码时,你可能会考虑张贴你正在使用的代码,并生成这个堆栈跟踪。@公共SWARES-我用我在添加代码中使用的代码更新了我的帖子,CTX是主要活动的上下文,代码在我的服务类“ctx是主活动的上下文”中——您的服务无权访问该活动。“代码在我的服务类中”--堆栈跟踪声称不是这样。是的,这修复了通知的创建,但我在调用
startForeground
时仍然得到NPE。(对不起,我想我是在你发布这个答案的同时更新了我的问题)这会创建一个服务,但没有通知,并且当应用程序运行时,服务会停止closed@vcapra1:如回答中所述,此特定示例仅在下载过程中处于前台状态。这与应用程序是否“关闭”(不管是什么意思)无关。我选择这个特定的代码列表是因为它很短,显示了调用的时间,并显示了如何构造
通知
@vcapra1:和中演示了更持久的服务,但这些示例要复杂得多。@commonware“组件中的每个方法要么是构造函数/初始值设定项,要么是生命周期方法,要么是从生命周期方法调用的东西”,或者(在服务的情况下)由绑定到它的其他东西调用的东西,例如,这对于音频播放控件来说很常见。我并不是说从生命周期调用它
是错误的,但这并不是唯一的方法。@MarkCarter:“由其他绑定到它的东西调用的东西,例如音频播放控件中常见的东西”--非常正确,我错过了。使用
startForeground()
活页夹上的某个方法中执行
也应该是安全的。同样,关键是在创建服务后,服务需要在其自身上调用
startForeground()
/***
  Copyright (c) 2008-2012 CommonsWare, LLC
  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain   a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  From _The Busy Coder's Guide to Android Development_
    https://commonsware.com/Android
 */

package com.commonsware.android.foredown;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.support.v4.app.NotificationCompat;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class Downloader extends IntentService {
  public static final String ACTION_COMPLETE=
      "com.commonsware.android.downloader.action.COMPLETE";
  private static int NOTIFY_ID=1337;
  private static int FOREGROUND_ID=1338;

  public Downloader() {
    super("Downloader");
  }

  @Override
  public void onHandleIntent(Intent i) {
    try {
      String filename=i.getData().getLastPathSegment();

      startForeground(FOREGROUND_ID,
                      buildForegroundNotification(filename));

      File root=
          Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);

      root.mkdirs();

      File output=new File(root, filename);

      if (output.exists()) {
        output.delete();
      }

      URL url=new URL(i.getData().toString());
      HttpURLConnection c=(HttpURLConnection)url.openConnection();
      FileOutputStream fos=new FileOutputStream(output.getPath());
      BufferedOutputStream out=new BufferedOutputStream(fos);

      try {
        InputStream in=c.getInputStream();
        byte[] buffer=new byte[8192];
        int len=0;

        while ((len=in.read(buffer)) >= 0) {
          out.write(buffer, 0, len);
        }

        out.flush();
      }
      finally {
        fos.getFD().sync();
        out.close();
        c.disconnect();
      }

      stopForeground(true);
      raiseNotification(i, output, null);
    }
    catch (IOException e2) {
      stopForeground(true);
      raiseNotification(i, null, e2);
    }
  }

  private void raiseNotification(Intent inbound, File output,
                                 Exception e) {
    NotificationCompat.Builder b=new NotificationCompat.Builder(this);

    b.setAutoCancel(true).setDefaults(Notification.DEFAULT_ALL)
     .setWhen(System.currentTimeMillis());

    if (e == null) {
      b.setContentTitle(getString(R.string.download_complete))
       .setContentText(getString(R.string.fun))
       .setSmallIcon(android.R.drawable.stat_sys_download_done)
       .setTicker(getString(R.string.download_complete));

      Intent outbound=new Intent(Intent.ACTION_VIEW);

      outbound.setDataAndType(Uri.fromFile(output), inbound.getType());

      b.setContentIntent(PendingIntent.getActivity(this, 0, outbound, 0));
    }
    else {
      b.setContentTitle(getString(R.string.exception))
       .setContentText(e.getMessage())
       .setSmallIcon(android.R.drawable.stat_notify_error)
       .setTicker(getString(R.string.exception));
    }

    NotificationManager mgr=
        (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

    mgr.notify(NOTIFY_ID, b.build());
  }

  private Notification buildForegroundNotification(String filename) {
    NotificationCompat.Builder b=new NotificationCompat.Builder(this);

    b.setOngoing(true);

    b.setContentTitle(getString(R.string.downloading))
     .setContentText(filename)
     .setSmallIcon(android.R.drawable.stat_sys_download)
     .setTicker(getString(R.string.downloading));

    return(b.build());
  }
}