The error occurs when starting a foreground service with notification.
I am trying to load the data from the JSON file to my database. Since the file is large, I am using foreground service to show the loading progress in notification.
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);
}
}
}
Error
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)
I don't know what is causing this error. I also provided Foreground service permission in AndroidManifest.xml.
You do not need this line
notificationManager.notify(1,notification.build());
Try to remove it and place startForeground
into onCreate
method
@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
}
Notice that onStartCommand
method will be called multiple times unlike the onCreate