1

When I want to start a thread, it just crashes on Android Marshmallow and below. I have an autostart script, which calls my check.java script ON_BOOT_COMPLETED. On Android N it works, but it doesn't on Android Marshmallow and lower... It is telling me that a thread has already started, while that thread is the only thread that is called... I tried things like adding sleep(100); and checking if a thread is alive, but nothing worked... How can I fix it?

--------- beginning of crash
E/AndroidRuntime( 2436): FATAL EXCEPTION: main
E/AndroidRuntime( 2436): Process: com.company.app, PID: 2436
E/AndroidRuntime( 2436): java.lang.IllegalThreadStateException: Thread already started
E/AndroidRuntime( 2436):        at java.lang.Thread.checkNotStarted(Thread.java:849)
E/AndroidRuntime( 2436):        at java.lang.Thread.start(Thread.java:1059)
E/AndroidRuntime( 2436):        at com.company.app.CheckRoosterWijziging$SayHello$1.run(CheckRoosterWijziging.java:94)
E/AndroidRuntime( 2436):        at android.os.Handler.handleCallback(Handler.java:739)
E/AndroidRuntime( 2436):        at android.os.Handler.dispatchMessage(Handler.java:95)
E/AndroidRuntime( 2436):        at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime( 2436):        at android.app.ActivityThread.main(ActivityThread.java:5254)
E/AndroidRuntime( 2436):        at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 2436):        at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime( 2436):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
E/AndroidRuntime( 2436):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

My thread:

Thread wijzigingenThread = new Thread() {
    @Override
    public void run() {
        try {
            sleep(100);
            try {
                System.out.println("Hello test");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

Autostart.java

package com.company.app;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class autostart extends BroadcastReceiver {
    public void onReceive(Context arg0, Intent arg1) {
         Intent intent = new Intent(arg0, CheckRoosterWijziging.class);
         arg0.startService(intent);
    }
}

CheckRoosterWijziging.java

package com.company.app;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.support.v4.app.NotificationCompat;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.util.Log;
import android.widget.Toast;

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

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeMap;
import java.util.regex.Pattern;

public class CheckRoosterWijziging extends Service {
    private NotificationManager mNM;
    private int NOTIFICATION = 10;
    Handler handler;
    MainActivity main = MainActivity.getMain();
    final int NOTIFICATION_ID = 10;
    NotificationManager notificationManager;
    static CheckRoosterWijziging checkRoosterWijziging;

    public class LocalBinder extends Binder {CheckRoosterWijziging getService() {return CheckRoosterWijziging.this;}}

    @Override
    public void onCreate() {
        handler = new Handler(Looper.getMainLooper());
        checkRoosterWijziging = this;
        mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        System.out.println("Service");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("CheckRoosterWijziging", "Received start id " + startId + ": " + intent);
        showNotification();
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mNM.cancel(NOTIFICATION);
        Toast.makeText(this, "Stopped", Toast.LENGTH_SHORT).show();
    }

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

    private final IBinder mBinder = new LocalBinder();

    class SayHello extends TimerTask {
       public void run() {
           handler.post(new Runnable() {
               public void run() {
                   wijzigingenThread.start();
               }
           });
       }
   }


    private void showNotification() {
        Timer timer = new Timer();
        timer.schedule(new SayHello(), 15000, 15000);
    }
Jason
  • 1,658
  • 3
  • 20
  • 51
  • please post more code, e.g. CheckRoosterWijziging.java and the BroadcastReceiver – nandsito Sep 30 '16 at 19:11
  • @nandsito added :) – Jason Sep 30 '16 at 19:16
  • On a style note, it's worth reading [this question](http://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread) on `implements Runnable` vs `extends Thread`. – Joe C Sep 30 '16 at 20:16

2 Answers2

1

The timer is calling start() multiple times on the same Thread object, which is causing the IllegalThreadStateException. You could make use of a flag indicating whether the thread has already started, or check Thread.getState(), both before calling start. For example:

if (wijzigingenThread.getState().equals(Thread.State.NEW)) {
    wijzigingenThread.start();
}
nandsito
  • 3,782
  • 2
  • 19
  • 26
  • Isn't there a way to stop a thread and then start it again? I just want to get rid of NetworkOnMainThread exception... so I used an thread. – Jason Sep 30 '16 at 20:15
  • Alternatively, create a new `Thread` every time you want to run this. – Joe C Sep 30 '16 at 20:15
  • @JoeC how can I do so? – Jason Sep 30 '16 at 20:17
  • Step 1: Instead of assigning your new Thread to a variable, create a method that returns a new Thread (ex. `creerenWijzigingenThread()`). Step 2: `creerenWijzigingenThread().start();` – Joe C Sep 30 '16 at 20:19
  • @JoeC how can I exactly do that? I do not quite understand unfortunaly :( – Jason Sep 30 '16 at 20:27
  • Exactly what part do you not understand? I'd rather try to help your understanding than just write the code for you. – Joe C Sep 30 '16 at 20:30
  • do you mean with method that returns thread that I have to move the new thread inside a public void? – Jason Sep 30 '16 at 20:32
  • I mean a method with a signature like `private Thread creerenWijzigingenThread()`. – Joe C Sep 30 '16 at 20:39
  • I tried something other: I copied the whole thread, removed "Thread wijzigingenthread = " and pasted the content at the place where I normally call the thread. It now works :) – Jason Sep 30 '16 at 20:51
  • @JoeC I however now get this error which has nothing to do with the thread but with a notification which I am sending from within the thread: `W/System.err( 2431): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference` – Jason Sep 30 '16 at 20:59
  • I think that merits a new question. – Joe C Sep 30 '16 at 20:59
0

Fixed it by moving the new Thread() to the place where the original wijzigingenThread.start() were called.

So I did the following:

Original:

class SayHello extends TimerTask {
       public void run() {
           handler.post(new Runnable() {
               public void run() {
                   wijzigingenThread.start();
               }
           });
       }
   }

New:

class SayHello extends TimerTask {
       public void run() {
           handler.post(new Runnable() {
               public void run() {
                   new Thread() {
                        @Override
                        public void run() {
                            try {
                                sleep(100);
                                try {
                                    System.out.println("Hello test");
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }.start();
               }
           });
       }
   }

Thanks to @JoeC for helping me and pointing me in the right direction!

Jason
  • 1,658
  • 3
  • 20
  • 51