【问题标题】:Bad notification for startForeground error in AndroidAndroid 中 startForeground 错误的错误通知
【发布时间】:2020-09-08 17:17:04
【问题描述】:

使用通知启动前台服务时发生错误。

我正在尝试将 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 中提供了前台服务权限。

【问题讨论】:

  • 您的代码看起来不错...您是否已在清单中将 App 声明为 Application 实例? (或者只是在应用程序设置中验证是否正确创建了频道)也尝试将startForeground 调用移动到onCreate
  • 这能回答你的问题吗? stackoverflow.com/questions/61067561/…
  • 编辑您的问题并将您的清单粘贴到那里。

标签: android android-service android-notifications foreground-service


【解决方案1】:

你不需要这条线

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 不同

【讨论】:

    【解决方案2】:

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

    //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")
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 2020-12-08
      相关资源
      最近更新 更多