Search code examples
androidnotificationsandroid-sqliteandroid-workmanager

Unable to send periodic local notifications with WorkManager after app is killed


I'm facing an issue that is wasting my time.
I'm building an app with a local SQLite database. I want this app to send a notification with some data from the SQLite database to the user every 15 minutes for example. I have successfully achieved this AS LONG AS THE APP IS RUNNING OR NOT KILLED But, when the app gets killed the notifications no longer appear to the user. I'm testing the app on two real devices Samsung & Huawei.
Here is the code for the notifier class that extends Worker :-

public Result doWork() {
    try {

      SqliteAssetHelper dbHelper = new SqliteAssetHelper(MainActivity.mcontext);
        mdatabase = dbHelper.getWritableDatabase();


        Cursor mCursor = mdatabase.query(BDH.BDHEntry.TABLE_NAME,
                new String[]{BDH.BDHEntry.COLUMN_HADITH_ID,BDH.BDHEntry.COLUMN_BOOK_NAME,
                        BDH.BDHEntry.COLUMN_DOOR_NAME, BDH.BDHEntry.COLUMN_NARRATORS, BDH.BDHEntry.COLUMN_CONTEXT},
                BDH.BDHEntry.COLUMN_BOOK_ID+"=?",new String[]{"1"},null,null, "RANDOM() LIMIT 1");

        if (mCursor != null) {
            mCursor.moveToFirst();
            if (mCursor.getCount() > 0) {
                while (mCursor.isAfterLast() == false) { //You need to check if cursor doesnot contain last row
                    hadithID = mCursor.getString(mCursor.getColumnIndex("HadithID"));
                    book = mCursor.getString(mCursor.getColumnIndex("BookName"));
                    door = mCursor.getString(mCursor.getColumnIndex("DoorName"));
                    mCursor.moveToNext();
                }
            }
        }

        Intent intentActivity = new Intent(MainActivity.mcontext, HadithActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intentActivity.putExtra("id", hadithID );
        PendingIntent contentIntent = PendingIntent.getActivity(MainActivity.mcontext, 0, intentActivity, PendingIntent.FLAG_UPDATE_CURRENT);

        notificationManager = NotificationManagerCompat.from(MainActivity.mcontext);
        Notification notification = new NotificationCompat.Builder(MainActivity.mcontext,CHANNEL_ID)
                .setSmallIcon(R.drawable.book)
                .setContentTitle(book)
                .setContentText(door)
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setAutoCancel(true)
                .setCategory(NotificationCompat.CATEGORY_CALL)
                .setContentIntent(contentIntent)
                .build();

        notificationManager.notify(notificationID, notification);
        return Result.success();

    }
    catch (Throwable throwable)
    {
        return Result.retry();
    }
}


In the Main Activity I'm using the previous notifier to appear every 15 Minutes:-

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mcontext = this;


    //creating constraints
    Constraints constraints = new Constraints.Builder()
            .setTriggerContentMaxDelay(1, TimeUnit.MINUTES)
            .build();


    PeriodicWorkRequest showHadithEveryHour = new PeriodicWorkRequest.Builder(HadithNotifier.class, 15, TimeUnit.MINUTES)
            .setConstraints(constraints)
            .build();
    WorkManager.getInstance(this).enqueue(showHadithEveryHour);
    }


When I change the notifier class code to show a log message without any values the Result for worker in the logcat is Success

Log.d(TAG,"Work Manager is working");

enter image description here If I change the notifier class code to show a log Message with a value from the Cursor or to show a hard coded notification it doesn't work and the Result for worker is Retry. enter image description here


Solution

  • At minimum, remove all references to MainActivity.mcontext from this class. Even better would be to remove mcontext entirely from the app, as it is a memory leak.

    Your Worker constructor is passed a Context. Hold onto it in a field, and use that Context from your doWork() method.