Android 中 startForeground 错误的错误通知

问题描述 投票:0回答:3

启动带通知的前台服务时出现错误。

我正在尝试将 JSON 文件中的数据加载到我的数据库中。由于文件很大,我使用前台服务在通知中显示加载进度。

LoadIntentService.java

import android.app.NotificationManager;
import android.app.Service;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.android.word.database.DbHelper;
import com.android.word.database.WordDictionaryContract;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;

import static com.android.word.App.CHANNEL_ID;

public class LoadIntentService  extends Service {

    private static final String LOG_TAG = "LoadIntentService";


    private DbHelper dbHelper;
    private SQLiteDatabase mDatabase;


    private Context mContext;


    public LoadIntentService() {
        super();
        Log.d(LOG_TAG,"LoadIntentService");
    }

    @Override
    public void onCreate() {
        super.onCreate();

        mContext = getApplicationContext();

        dbHelper = new DbHelper(this);
        mDatabase = dbHelper.getWritableDatabase();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        final int countMax = intent.getIntExtra("size",0);

        Log.d(LOG_TAG," onStartCommand");


        final NotificationCompat.Builder notification = new NotificationCompat.Builder(this,CHANNEL_ID)
                .setContentTitle("Loading Dictionary")
                .setSmallIcon(R.drawable.ic_file_download_black_24dp)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .setProgress(countMax,0,false);

        final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(1,notification.build());

        startForeground(1,notification.build());


        new Thread(new Runnable() {
            @Override
            public void run() {

                Log.d(LOG_TAG," start thread");

                String json;

                String word,definition,audiourl,synonym,antonym;




                try {
                    Log.d(LOG_TAG,"parsing json");
                    InputStream inputStream = mContext.getAssets().open("worddictionary.json");
                    int size = inputStream.available();
                    Log.d(LOG_TAG,"parsing json size: "+size);
                    byte[] buffer = new byte[size];
                    inputStream.read(buffer);
                    inputStream.close();
                    json = new String(buffer, "UTF-8");
                    // Log.d(LOG_TAG,"parsing json data: "+json);
                    JSONArray jsonArray = new JSONArray(json);

                    for (int i=0;i<jsonArray.length();i++){

                        notification.setProgress(countMax,i,false);
                        notificationManager.notify(1,notification.build());

                        JSONObject obj = jsonArray.getJSONObject(i);
                        word = obj.getString("word");
                        definition = obj.getString("definition");
                        audiourl = obj.getString("audiourl");
                        synonym = obj.getString("synonym");
                        antonym = obj.getString("antonym");

                        ContentValues values = new ContentValues();
                        values.put("word",word);
                        values.put("definition",definition);
                        values.put("audiourl",audiourl);
                        values.put("synonyms",synonym);
                        values.put("antonyms",antonym);

                        long id = mDatabase.insert(WordDictionaryContract.WordDictionaryEntry.TABLE_NAME,null,values);

                        if (id==-1){
                            Log.d(LOG_TAG,"insert failed: "+word);
                        } else{
                            Log.d(LOG_TAG,"insert success id: "+id);
                        }

                    }

                    Log.d(LOG_TAG,"Dictionary Loaded");

                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(LOG_TAG,"Read json error: "+e);
                } catch (JSONException e) {
                    Log.d(LOG_TAG,"Parse json error: "+e.getStackTrace());
                    e.printStackTrace();
                }


                stopSelf();
                notification.setContentText("Dictionary Loaded").setProgress(0,0,false).setOngoing(false);
                notificationManager.notify(1,notification.build());

            }
        }).start();

        return START_NOT_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

App.java

import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;

public class App extends Application {

    public static final String CHANNEL_ID = "loadDataServiceChannel";


    @Override
    public void onCreate() {
        super.onCreate();

        createNotificationChannel();

    }

    private void createNotificationChannel(){
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,"Loading Dictionary",
                    NotificationManager.IMPORTANCE_HIGH
            );

            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }

}

错误

2020-09-08 22:42:06.863 5076-5076/com.android.word E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.android.word, PID: 5076
    android.app.RemoteServiceException: Bad notification for startForeground
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1738)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6692)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

我不知道是什么导致了这个错误。我还在AndroidManifest.xml中提供了前台服务权限。

android android-service android-notifications foreground-service
3个回答
0
投票

您不需要这条线

notificationManager.notify(1,notification.build());

尝试将其移除并将

startForeground
放入
onCreate
方法

@Override
public void onCreate() {
    super.onCreate();

    final NotificationCompat.Builder notification = new NotificationCompat.Builder(this,CHANNEL_ID)
                .setContentTitle("Loading Dictionary")
                .setSmallIcon(R.drawable.ic_file_download_black_24dp)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .setProgress(countMax,0,false);

    final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    // notificationManager.notify(1,notification.build()); <-- remove this

    startForeground(1,notification.build());

    //... other stuff
}

请注意,与

onStartCommand
 不同,
onCreate

方法将被多次调用

0
投票
    Create a Notification channel whereever you are calling the startforeground service , it fixed my problem  

   

  val channelId = "Channel Id "
        val channelName = "Channel Name"
        val notificationManager = NotificationManagerCompat.from(context)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val importance = NotificationManager.IMPORTANCE_MAX
            val channel = NotificationChannel(channelId, channelName, importance)
            notificationManager.createNotificationChannel(channel)
        }

-1
投票

这就是我构建通知的方式:

//Helpers

fun updateKibiNotification(context: Context, channelID: String, icon : Int, message : String = this.message): Notification? {

    notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        Notification.Builder(context,channelID)
            .setContentTitle(title)
            .setContentText(message)
            .setSmallIcon(icon)
            .build()
    } else {
        Notification.Builder(context)
            .setContentTitle(title)
            .setContentText(message)
            .setSmallIcon(icon)
            .build()
    }
    return notification
}

fun createNotificationChannel(
    channelName: String,
    channelDescription: String = "",
    channelID: String,
    context: Context
){

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // Create the NotificationChannel
        val importance = NotificationManager.IMPORTANCE_HIGH
        val mChannel = NotificationChannel(channelID, channelName, importance)
        mChannel.description = channelDescription
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        val notificationManager = 
         context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(mChannel)
    }
}

这就是我启动前台服务的方式:

 private fun setupForeground(){
    KibiNotificationBuilder.createNotificationChannel(kibiChannelID,channelID = kibiChannelID, context = this)
    val initialMessage = getString(R.string.setup_foreground_text)
    startForeground(KibiNotificationBuilder.notificationId,
        KibiNotificationBuilder.updateKibiNotification(this, kibiChannelID,R.drawable.notification_icon_background,initialMessage))
    Log.d(DEBUG_TAG, "setupForeground: started")
}
© www.soinside.com 2019 - 2024. All rights reserved.