-1
public class RSSPullService extends Service {

private ArrayList<String> stringArrayList;
private int i = 0;

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

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    stringArrayList = intent.getStringArrayListExtra("Array");
    final Calendar[] calendars = getCalendars();

    final Handler handler = new Handler();
    Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                while(true) {
                    Calendar calendar = Calendar.getInstance();
                    if ((calendar.get(Calendar.MINUTE) +
                            calendar.get(Calendar.HOUR_OF_DAY) * 60)
                            == (calendars[i].get(Calendar.MINUTE) +
                            calendars[i].get(Calendar.HOUR_OF_DAY) * 60))
                    {
                        setNotification(stringArrayList.get(i));
                        i++;
                    }
                    sleep(60000);
                    handler.post(this);
                }
            }
            catch (InterruptedException e) {e.printStackTrace();}
        }
    };

    thread.start();
    return START_STICKY;
}

private Calendar[] getCalendars() {
    int[] nums = lessonNum(); int len = nums.length;
    Calendar[] calendars = new Calendar[len];
    for (int i = 0; i < len; i++)
        calendars[i] = setCalendar(nums[i]);
    return calendars;
}

private Calendar setCalendar(int i) {
    Calendar calendar = Calendar.getInstance();
    switch (i) {
        case 0:
            calHelper(calendar, 6, 0);
            break;
        case 1:
            calHelper(calendar, 7, 0);
            break;
        case 2:
            calHelper(calendar, 8, 0);
            break;
        case 3:
            calHelper(calendar, 8, 55);
            break;
        case 4:
            calHelper(calendar, 9, 50);
            break;
        case 5:
            calHelper(calendar, 10, 55);
            break;
        case 6:
            calHelper(calendar, 11, 50);
            break;
        case 7:
            calHelper(calendar, 12, 45);
            break;
        case 8:
            calHelper(calendar, 13, 40);
            break;
        case 9:
            calHelper(calendar, 14, 25);
            break;
        case 10:
            calHelper(calendar, 15, 15);
            break;
        default:
            calHelper(calendar, 0, 0);
            break;
    }
    return calendar;
}

private void calHelper(Calendar calendar, int hour, int minute) {
    calendar.set(Calendar.HOUR_OF_DAY, hour);
    calendar.set(Calendar.MINUTE, minute);
}

private int[] lessonNum() {
    int size = stringArrayList.size();
    int[] nums = new int[size];
    for (int i = 0; i < size; i++)
        nums[i] = Integer.parseInt(stringArrayList.get(i).substring(0,1));
    return nums;
}

private void setNotification(String s) {
    Notification.Builder builder = new Notification.Builder(this);
    builder.setContentTitle(getResources().getString(R.string.next));
    builder.setContentText(s);
    builder.setSmallIcon(R.drawable.notify);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(325, builder.build());
    }
}

This is my code, I am trying to make it send a notification at specific times. This code seems to work when my application is running, but once I close the app (click on the little square and swipe the app away) the service force-closes. Any ideas why this happens?

Edit1:

12-24 20:40:04.008 9063-9063/? E/AndroidRuntime: FATAL EXCEPTION: main
                                                 Process: com.example.danny.schoolassist, PID: 9063
                                                 java.lang.RuntimeException: Unable to start service com.example.danny.schoolassist.RSSPullService@8acbb1e with null: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.ArrayList android.content.Intent.getStringArrayListExtra(java.lang.String)' on a null object reference
                                                     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3343)
                                                     at android.app.ActivityThread.-wrap21(ActivityThread.java)
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1582)
                                                     at android.os.Handler.dispatchMessage(Handler.java:102)
                                                     at android.os.Looper.loop(Looper.java:154)
                                                     at android.app.ActivityThread.main(ActivityThread.java:6119)
                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
                                                  Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.ArrayList android.content.Intent.getStringArrayListExtra(java.lang.String)' on a null object reference
                                                     at com.example.danny.schoolassist.RSSPullService.onStartCommand(RSSPullService.java:28)
                                                     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3326)
                                                     at android.app.ActivityThread.-wrap21(ActivityThread.java) 
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1582) 
                                                     at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                     at android.os.Looper.loop(Looper.java:154) 
                                                     at android.app.ActivityThread.main(ActivityThread.java:6119) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

I run the service like so:

protected void onCreate(Bundle savedInstanceState) {
...
Intent mServiceIntent = new Intent(this, RSSPullService.class);
mServiceIntent.putExtra("Array", staticArrayList);
if (!isServiceRunning(RSSPullService.class)) startService(mServiceIntent);
}

private boolean isServiceRunning(Class<?> serviceClass) {
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
            if (serviceClass.getName().equals(service.service.getClassName()))
                return true;
    return false;
}
Blo
  • 11,903
  • 5
  • 45
  • 99
  • [Only have a service running when it is actively delivering value to the user](https://commonsware.com/blog/2014/07/27/role-services.html). Watching the clock tick is not actively delivering value to the user. Use `AlarmManager` or `JobScheduler` to arrange to get control in the background on a periodic basis. Beyond that, [use LogCat to examine the Java stack trace associated with your crash](https://stackoverflow.com/questions/23353173/unfortunately-myapp-has-stopped-how-can-i-solve-this). – CommonsWare Dec 24 '16 at 18:00
  • I don't know about JobScheduler but AlarmManager requires an interval to work with. The times I am using are inconsistent therefore it would be problematic to use them with AlarmManger – Danny Damsky Dec 24 '16 at 18:26
  • "AlarmManager requires an interval to work with" -- no more than your current code does. Call `set()` or `setExact()` for the nearest event (chronologically). When you process that event, in addition to whatever else you are doing, call `set()` or `setExact()` to schedule the next-nearest event. – CommonsWare Dec 24 '16 at 18:38
  • Alright thanks, I shall try to do this with AlarmManager. But first I want to see if I can get this code to work. 12-24 20:40:04.008 9063-9063/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.danny.schoolassist, PID: 9063 java.lang.RuntimeException: Unable to start service com.example.danny.schoolassist.RSSPullService@8acbb1e with null: java.lang.NullPointerException This is the logcat I get, any ideas on what's wrong here? – Danny Damsky Dec 24 '16 at 18:44
  • I suggest that you edit your question, put in the entire Java stack trace, and point out which lines in that stack trace correspond to particular lines in your source code in the question. – CommonsWare Dec 24 '16 at 18:47
  • Okay I edited it. The lines in the code from the other activity are from 72 to 83 – Danny Damsky Dec 24 '16 at 18:56

1 Answers1

0

You are returning START_STICKY from onStartCommand(). This tells Android "hey, if you terminate my process for some reason, please restart it sometime soonish, and call onStartCommand() again".

However, what it will not do is give you your old Intent back. You will get null for that Intent.

Using an Intent to pass data to a service is fine for non-sticky services, or as an optimization for sticky services. However, a sticky service needs to be able to operate independently, as you are asking for it to be re-created independently. The data that you are presently passing via that Intent needs to be persisted (database, SharedPreferences, or other sort of file), so that the sticky service can get that data even if there is no Intent to work with.

But, overall, having an everlasting service like this is generally considered to be an anti-pattern in Android. In your specific case, it will not work well, as when the device falls asleep — and usually a mobile device is asleep the vast majority of the time — you lose the ability to "send a notification at specific times".

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491