After calling the notify method the thread is still waiting - java

I have several classes:
WorkerQueue - queue.
WorkerRunnable - runnable which contain worker thread method with loop and its stop flag.
SomeClass - just class for initalize and management thread stuff.
I need to stop thread in destroy method. For it I create endTask method but it doesn't work thread still waiting.
If I replace called endTask method to mWorkerQueue.add(...), it's working fine and thread stop waiting.
class WorkerQueue {
private Queue<BasePrintTask> mTaskQueue = new ArrayDeque<>();
private Object obj = new Object();
public BasePrintTask get() {
while (mTaskQueue.isEmpty())
{
try {
synchronized (obj) {
obj.wait();
}
}
catch (InterruptedException ie)
{
ie.printStackTrace();
}
}
return mTaskQueue.remove();
}
public void add(BasePrintTask task) {
mTaskQueue.add(task);
synchronized (obj) {
obj.notify();
}
}
public void endTask() {
synchronized (obj) {
obj.notify();
}
}
}
public class WorkerRunnable implements Runnable
{
private boolean mFlag = false;
private WorkerQueue mWorkerQueue = null;
public WorkerRunnable(WorkerQueue workerQueue)
{
this.mPrinterManager = printerManager;
this.mWorkerQueue = workerQueue;
}
public void endThread() { mFlag = false; }
public void startThread() { mFlag = true; }
#Override
public void run() {
while(mFlag)
{
try
{
BasePrintTask task = mWorkerQueue.get();
}
catch (NoSuchElementException el)
{
}
}
}
}
public class SomeClass
{
private final Context mContext;
private WorkerQueue mWorkerQueue = new WorkerQueue();
private Thread mWorkerThread = null;
private WorkerRunnable mWorkerRunnable = null;
public SomeClass(final Context context)
{
this.mContext = context;
}
public void init()
{
mWorkerRunnable = new WorkerRunnable(mWorkerQueue);
}
public int prepare() {
mWorkerRunnable.startThread();
mWorkerThread = new Thread(mWorkerRunnable);
mWorkerThread.start();
return 0;
}
public int destroy() {
mWorkerRunnable.endThread();
mWorkerQueue.endTask();
try {
if(mWorkerThread.isAlive()) {
mWorkerThread.join();
}
}
catch (InterruptedException e) {
}
return 0;
}

Related

How to use Saved State module for ViewModel in Background Thread

How to use Saved State module for ViewModel in Background Thread
For MutableLiveData we have the option to use setvalue and postvalue , where Postvalue can be used in background thread.
How ever How can we use BACKGROUND THREAD FOR Saved State module for ViewModel
here Is the code I am trying
public class CommonViewModel extends ViewModel {
private SavedStateHandle mState;
public CommonViewModel(SavedStateHandle savedStateHandle) {
mState = savedStateHandle;
}
private static final String NAME_KEY = "name";
private Executor mExecutor = Executors.newSingleThreadExecutor();
public LiveData<ArrayList<CommonOwn>> getCart() {
if (mState.getLiveData(NAME_KEY) == null) {
initCart();
}
return mState.getLiveData(NAME_KEY);
}
public void initCart() {
mState.set(NAME_KEY, new ArrayList<CommonOwn>());
}
public void addItemToCart(CommonOwn commonOwn) {
if (getCart().getValue() == null) {
initCart();
}
ArrayList<CommonOwn> cartItemList = new ArrayList<CommonOwn>(getCart().getValue());
if (cartItemList.contains(commonOwn)) {
int a = cartItemList.indexOf(commonOwn);
cartItemList.remove(a);
} else {
cartItemList.add(commonOwn);
}
// mState.set(NAME_KEY, cartItemList);
mExecutor.execute(new Runnable() {
#Override
public void run() {
mState.set(NAME_KEY, cartItemList);
}
});
}
}
when using background thread The following error occurs
java.lang.IllegalStateException: Cannot invoke setValue on a background thread
at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:487)
at androidx.lifecycle.LiveData.setValue(LiveData.java:306)
at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
at androidx.lifecycle.SavedStateHandle$SavingStateLiveData.setValue(SavedStateHandle.java:367)
at androidx.lifecycle.SavedStateHandle.set(SavedStateHandle.java:256)
at com.example.CommonViewModel$1.run(CommonViewModel.java:63)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
how can we solve this issue.
The following line can never be null:
mState.getLiveData(NAME_KEY) == null
Hope this illustrates the solution. You just rely on the MutableLiveData from SavedStateHandle:
public class CommonViewModel extends ViewModel {
private MutableLiveData<ArrayList<CommonOwn>> cart;
public CommonViewModel(SavedStateHandle savedStateHandle) {
cart = savedStateHandle.getLiveData(NAME_KEY);
}
private static final String NAME_KEY = "name";
private Executor mExecutor = Executors.newSingleThreadExecutor();
public MutableLiveData<ArrayList<CommonOwn>> getCart() {
return cart;
}
public void addItemToCart(CommonOwn commonOwn) {
ArrayList<CommonOwn> cartItemList;
if(cart.getValue() == null) {
cartItemList = new ArrayList<CommonOwn>();
} else {
cartItemList = cart.getValue();
}
if (cartItemList.contains(commonOwn)) {
int a = cartItemList.indexOf(commonOwn);
cartItemList.remove(a);
} else {
cartItemList.add(commonOwn);
}
// mState.set(NAME_KEY, cartItemList);
mExecutor.execute(new Runnable() {
#Override
public void run() {
cart.postValue(cartItemList);
}
});
}
}

How to replace AsyncTask onProgressUpdate() using Runnable callbacks

I'm trying to replace deprecated AsyncTask without using Kotlin Coroutines or others libraries, so I have
MyTask objects with following structure
public abstract class MyTask<R> implements MyCallable<R> {
#Override
public void setUiForLoading() {
//runs on ui
}
#Override
public void setDataAfterLoading(R result) {
//runs on ui
}
#Override
public R call() throws Exception {
//runs in background
return null;
}
}
MyCallable is just a simple interface
public interface MyCallable<R> extends Callable<R>{
void setDataAfterLoading(R result);
void setUiForLoading();
}
And use this MyTaskRunner to execute them
public class MyTaskRunner {
private final Handler handler = new Handler(Looper.getMainLooper());
private final Executor executor = Executors.newCachedThreadPool();
public <R> void executeAsync(MyCallable<R> callable) {
try {
callable.setUiForLoading();
executor.execute(new RunnableTask<R>(handler, callable));
} catch (Exception e) {
}
}
public static class RunnableTask<R> implements Runnable{
private final Handler handler;
private final MyCallable<R> callable;
public RunnableTask(Handler handler, MyCallable<R> callable) {
this.handler = handler;
this.callable = callable;
}
#Override
public void run() {
try {
final R result = callable.call();
handler.post(new RunnableTaskForHandler(callable, result));
} catch (Exception e) {
}
}
}
public static class RunnableTaskForHandler<R> implements Runnable{
private MyCallable<R> callable;
private R result;
public RunnableTaskForHandler(MyCallable<R> callable, R result) {
this.callable = callable;
this.result = result;
}
#Override
public void run() {
callable.setDataAfterLoading(result);
}
}
}
it works, but I cannot figure how I could replicate correctly the behaviour of publishProgress() and onProgressUpdate() of AsyncTask useful to show actual progress rather that just indeterminate
I cannot give the same code as yours but hopefully you get the idea.
Everything is self explain in code itself.
import android.app.*;
import android.graphics.*;
import android.os.*;
import android.widget.*;
import java.lang.ref.*;
public class MainActivity extends Activity
{
private static final class HeavyJob implements Runnable
{
private final WeakReference<Handler> handler;
private final Thread thread;
private boolean isAlive;
private boolean state;
private int progress;
public final HeavyJob(final Handler handler)
{
this.handler = new WeakReference<Handler>(handler);
thread = new Thread(this);
isAlive = true;
thread.setPriority(Thread.NORM_PRIORITY);
thread.start();
}
#Override
public final void run()
{
while(isAlive) {
try {
synchronized(this) {
while(!state) this.wait();
}
Thread.sleep(200L); //Let say this a heavy job which takes 200 m/s each round.
progress += 10;
final Handler hanRef = handler.get();
if(hanRef == null) {
isAlive = false;
handler.clear();
break;
}
final Message msg = Message.obtain();
msg.what = 0;
msg.arg1 = progress;
hanRef.sendMessageAtTime(msg, SystemClock.uptimeMillis()); //Update its progress each round.
} catch(final InterruptedException e) {}
}
//Finished ???
final Handler hanRef = handler.get();
if(hanRef != null) {
final Message msg = Message.obtain();
msg.what = 1;
msg.arg1 = progress; //Make your progress is 100% completed and updated.
//msg.obj = bitmap;
hanRef.sendMessageAtTime(msg, SystemClock.uptimeMillis());
}
}
public final synchronized void resume()
{
if(isAlive) {
state = true;
this.notify();
}
}
public final void suspend()
{
state = false;
thread.interrupt();
}
public final void stop()
{
isAlive = false; // In case interrupt() does nothing (Thread was not in sleep nor wait mode).
thread.interrupt();
handler.clear();
}
}
private static final class UIHandler extends Handler
{
private final WeakReference<MainActivity> activity;
public final UIHandler(final MainActivity activity)
{
super(Looper.getMainLooper());
this.activity = new WeakReference<MainActivity>(activity);
}
#Override
public final void handleMessage(final Message msg)
{
final MainActivity referent = activity.get();
if(referent != null) {
switch(msg.what) {
case 0: referent.onProgress(msg.arg1); break;
case 1: referent.onPostExecute(msg.arg1, (Bitmap)msg.obj); break;
}
}
}
}
private ProgressBar pb;
private ImageView iv;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pb = findViewById(R.id.pb);
iv = findViewById(R.id.next);
UIHandler handler = new UIHandler(this);
//Initilize the object but will not run yet.
HeavyJob hj = new HeavyJob(handler);
//Run the job
hj.resume();
//Pause the job
hj.suspend();
//Resume the job
hj.resume();
//Stop the job
hj.stop();
//Multiple jobs
for(int i=0; i<10; i++) {
new HeavyJob(handler);
}
}
public final void onProgress(final int progress) {
pb.setProgress(progress);
}
public final void onPostExecute(final int progress, Bitmap bitmap)
{
pb.setProgress(progress);
if(bitmap != null) iv.setImageBitmap(bitmap);
}
}
The best I founded to do it is:
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
Button btn_start;
TextView text;
ProgressBar progressBar1, progressBar2;
int num = 0;
ExecutorService service;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = findViewById(R.id.textHello);
btn_start = findViewById(R.id.btn_start);
progressBar1 = findViewById(R.id.progressbar1);
progressBar2 = findViewById(R.id.progressBar2);
btn_start.setOnClickListener(v -> toDo());
}
private void toDo() {
service = Executors.newSingleThreadExecutor();
service.execute(() -> {
runOnUiThread(() -> {
// onPreExecute method of AsyncTask
progressBar1.setVisibility(View.VISIBLE);
progressBar2.setVisibility(View.VISIBLE);
});
// doInBackground of AsyncTask
for (int i = 1; i <= 10000; i++) {
num = i;
runOnUiThread(() -> {
// onProgressUpdate method of AsyncTask
progressUpdate(num);
});
}
runOnUiThread(() -> {
// onPostExecute method of AsyncTask
progressBar1.setVisibility(View.GONE);
progressBar2.setVisibility(View.GONE);
});
});
}
public void progressUpdate(Integer i) {
text.setText(String.valueOf(i));
progressBar2.setProgress(i);
}
}

Singleton with Android

I'm having a bit of trouble using the singleton pattern correctly in my android studio project. I created a textView in my mainActivity class in which I want to set the text of that textView the string value of the variable "a" in the GrouseSingleton class. However, the textView always displays as "hello" (the way it was initialized) and not the actual string it should be (it should be "mainly cloudy skies", parsed from the website). I'm assuming that I'm not set the variable "a" correctly in the singleton class. Any help would be appreciated, thanks!
SINGLETON CLASS CODE:
public class GrouseSingleton extends AppCompatActivity {
private static GrouseSingleton instance = null;
public Document grouseWeather;
public String a = "hello";
private GrouseSingleton() throws IOException {
startThread();
}
public static GrouseSingleton getInstance() throws IOException {
if (instance == null) {
instance = new GrouseSingleton();
}
return instance;
}
public void startThread() throws IOException {
new Thread() {
public void run() {
try {
grouseWeather = Jsoup.connect("https://www.grousemountain.com/current_conditions#weather").get();
runOnUiThread( new Runnable()
{
public void run()
{
a = grouseWeather.select("h3.metric").first().text();
setA(a);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
public void setA(String a) {
this.a = a;
}
}
MAIN ACITVITY CODE:
try {
grouseSingleton = GrouseSingleton.getInstance();
} catch (IOException e) {
e.printStackTrace();
}
TextView tv45 = findViewById(R.id.textView45);
tv45.setText(grouseSingleton.a);
Your singleton is fine. The issue is that you create the instance of class GrouseSingleton and then right after that you get the value of a which is the default value "hello" . So you need to use an interface like below to inform your activity when the value of a is fetched from server:
public interface ResultListener {
void onResultFetched(int textViewId, String txt);
}
In your Activity:
try {
grouseSingleton = GrouseSingleton.getInstance(new ResultListener () {
#Override
public void onResultFetched(int textViewId, String txt) {
TextView tv45 = findViewById(id);
tv45.setText(txt);
});
grouseSingleton.startThread();
} catch (IOException e) {
e.printStackTrace();
}
set the listener in your GrouseSingleton class:
private static ResultListener listener;
public static GrouseSingleton getInstance(ResultListener listener) throws IOException {
if (instance == null) {
instance = new GrouseSingleton();
GrouseSingleton.listener = listener;
}
return instance;
}
public void startThread() throws IOException {
new Thread() {
public void run() {
try {
grouseWeather = Jsoup.connect("https://www.grousemountain.com/current_conditions#weather").get();
runOnUiThread( new Runnable()
{
public void run()
{
a = grouseWeather.select("h3.metric").first().text();
listener.onResultFetched(txtViewId, a);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
All code is fine. But the problem is before load data textview set default value hello. Afterload data it's cannot update the value. To simply achieve this just sent your textView as a parameter when calling your singleton. like:
SingletonClass:
public class GrouseSingleton extends AppCompatActivity {
private static GrouseSingleton instance = null;
public Document grouseWeather;
public String a = "hello";
TextView textView;
private GrouseSingleton(TextView textView) throws IOException {
this.textView = textView;
startThread();
}
public static GrouseSingleton getInstance(TextView textView) throws IOException {
if (instance == null) {
instance = new GrouseSingleton(textView);
}
return instance;
}
public void startThread() throws IOException {
new Thread() {
public void run() {
try {
grouseWeather = Jsoup.connect("https://www.grousemountain.com/current_conditions#weather").get();
runOnUiThread( new Runnable()
{
public void run()
{
a = grouseWeather.select("h3.metric").first().text();
textView.setText(a);
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
And from MAinActivity:
TextView tv45 = findViewById(R.id.textView45);
try {
grouseSingleton = GrouseSingleton.getInstance(tv45);
} catch (IOException e) {
e.printStackTrace();
}
tv45.setText(grouseSingleton.a);

Android ChangeOverTime method freezing at runtime (but not consistently)

So I am running into a problem with a function I made to slowly change the value of a monitored variable over time that is causing all the java logic to lock up. It doesn't seem to be producing an error or make the application crash so it must be getting stuck in the while loop or something but the logging isn't firing while it is locked so I am just very confused. If anyone can help me figure out how to diagnose what is causing the freezing that would be very much appreciated
EDIT: Turns out the problem was updating the UI from another thread, I manged to get it to crash and got the error and used a CountDownTimer instead of the background thread and now it is working fine. For those curious checkout my GitHub for this project.
Function in question:
public static void changeOverTime(final MonitoredVariable<Integer> tVar, final int tTo, final long tTime, final long tUpdateFreq) {
if (tTime < tUpdateFreq) { Log.e(TAG, "Time must be greater then update freq."); }
if (tVar == null) { Log.e(TAG, "Container cannot be null."); }
else {
final Thread tBackgroundThread = new Thread(new Runnable() {
#Override
public void run() {
float tSteps = tTime / tUpdateFreq; // 2000/100 = 20
float tInterval = (tTo - tVar.get()) / tSteps; // 67-175 = -108/20 = -5.4
float tVal = tVar.get(); //175
while (Math.round(tVal) != tTo) { //67(After 20 Times) != 67 -> FALSE
Debug.Log(TAG, "EQ: " + Math.round(tVal) + "?=" + tTo);
tVal += tInterval; // -5.4 * 20(Times) = -108+175 = 67
tryToSleep(tUpdateFreq); // 100ms * 20(Times) = 2000ms total
tVar.set(Math.round(tVal));
}
}
});
tBackgroundThread.start();
}
}
Supporting Function:
private static void tryToSleep(long tTime) {
try { sleep(tTime); }
catch (InterruptedException e) { e.printStackTrace(); }
}
Monitored Variable Class:
public class MonitoredVariable<Prototype> {
protected Prototype mData;
protected ChangeListener mListener;
public MonitoredVariable(Prototype tData) {
this(tData, null);
}
public MonitoredVariable(Prototype tData, ChangeListener tListener) {
if (tListener != null) setListener(tListener);
mData = tData;
}
public Prototype get() {
return mData;
}
public void set(Prototype tData) {
if (mData != tData) {
mData = tData;
notifyChange();
}
}
public void setListener(ChangeListener tListener) {
mListener = tListener;
}
public ChangeListener getListener() {
return mListener;
}
public void notifyChange() {
if (mListener != null) mListener.onChange();
}
public interface ChangeListener {
void onChange();
}
}
Usage:
public static void init() {
MonitoredVariable.ChangeListener tUpdateBackground = new MonitoredVariable.ChangeListener() {
#Override
public void onChange() { updateBackgroud();
}
};
mTop = new MonitoredVariable[]{
new MonitoredVariable<>(0, tUpdateBackground),
new MonitoredVariable<>(0, tUpdateBackground),
new MonitoredVariable<>(0, tUpdateBackground)
};
mBottom = new MonitoredVariable[]{
new MonitoredVariable<>(0, tUpdateBackground),
new MonitoredVariable<>(0, tUpdateBackground),
new MonitoredVariable<>(0, tUpdateBackground)
};
mAnimationLoop = new Handler();
mAnimation = new Runnable() {
#Override
public void run() {
Debug.Log(TAG, "RUNNING ANIMATION");
final Random RNG = new Random();
for (MonitoredVariable<Integer>[] tBackground: new MonitoredVariable[][] {mTop, mBottom}) {
for (MonitoredVariable<Integer> tColor : tBackground) {
int tRandomColor = RNG.nextInt(255);
//tColor.set(tRandomColor);
Shift.changeOverTime(tColor, tRandomColor, 2000, 100);
}
}
if(mAnimate.get()) {
mAnimationLoop.postDelayed(mAnimation, 10000);
}
}
};
mAnimate = new MonitoredVariable<>(false, new MonitoredVariable.ChangeListener() {
#Override
public void onChange() {
if (mAnimate.get()) mAnimationLoop.postDelayed(mAnimation, 0);
else mAnimationLoop.removeCallbacks(mAnimation);
}
});
}
public static void setBackground(final Activity tActivity){
final View tActivityBackground = tActivity.findViewById(R.id.background);
mListener = new ChangeListener() {
#Override
public void onChange() { tActivityBackground.setBackground(mBackground); }
};
notifyChange();
}
private static void updateBackgroud() {
int tTop = Color.argb(255, mTop[0].get(), mTop[1].get(), mTop[2].get());
int tBottom = Color.argb(255, mBottom[0].get(), mBottom[1].get(), mBottom[2].get());
int[] colors = {tTop, tBottom};
mBackground = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, colors);
mBackground.setCornerRadius(0f);
notifyChange();
}
public static void animateBackground(boolean tAnimate) {
mAnimate.set(tAnimate);
}
public static void notifyChange() {
if (mListener != null) mListener.onChange();
}
public interface ChangeListener {
void onChange();
}

How to solve java.util.concurrent.RejectedExecutionException

I have java.util.concurrent.RejectedExecutionException in this file. As I can see there is no more processes running after onStop called. Not sure where the error comes from. And I'm sure the executor isn't getting more tasks it can handle too.
Please help me to figure out where the error comes from.
public static final String TAG = BroadcastService.class.getSimpleName();
private static final int TIMER_DELAY_SECONDS = 3;
private volatile JmDNS mService = null;
private WifiManager.MulticastLock mMulticastLock = null;
private ScheduledExecutorService mExecutorService = null;
private ScheduledFuture mPublisherFuture = null;
private ScheduledFuture mApiPublisherFuture = null;
private NetworkUtils mNetworkUtils = null;
private Runnable mDelayedKiller = null;
public static Intent getStartIntent(Context context) {
final Intent serviceIntent = new Intent(context, BroadcastService.class);
serviceIntent.setAction(BroadcastService.INTENT_ACTION_BROADCAST_START);
return serviceIntent;
}
public static Intent getStopIntent(Context context) {
final Intent serviceIntent = new Intent(context, BroadcastService.class);
serviceIntent.setAction(BroadcastService.INTENT_ACTION_BROADCAST_STOP);
return serviceIntent;
}
#Override
public void onCreate() {
super.onCreate();
mNetworkUtils = NetworkUtils.getInstance(getApplicationContext());
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
if (intent == null) {
return START_STICKY;
}
if (intent.getAction() != null) {
switch (intent.getAction()) {
case INTENT_ACTION_BROADCAST_START:
startBroadcast();
break;
case INTENT_ACTION_BROADCAST_STOP:
stopBroadcast();
break;
}
}
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(final Intent intent) {
return null;
}
/**
* Starts broadcast on a background thread
*/
public void startBroadcast() {
if (mDelayedKiller != null) {
NetworkThread.getCommonInstance().removeTask(mDelayedKiller);
mDelayedKiller = null;
}
if (mExecutorService == null || mExecutorService.isShutdown()) {
mExecutorService = Executors.newScheduledThreadPool(2);
}
if (mPublisherFuture != null) {
mPublisherFuture.cancel(true);
}
final BonjourPublisher bonjourPublisher = new BonjourPublisher();
mPublisherFuture = mExecutorService.schedule(bonjourPublisher, 2, TimeUnit.SECONDS);
if (mApiPublisherFuture != null) {
mApiPublisherFuture.cancel(true);
}
final ApiPublisher apiPublisher = new ApiPublisher();
mApiPublisherFuture = mExecutorService.scheduleWithFixedDelay(apiPublisher, 0, 30, TimeUnit.SECONDS);
//inform listeners
EventBus.getDefault().post(new EventServiceBroadcasting(true));
}
public synchronized void stopBroadcast() {
if (mPublisherFuture == null && mApiPublisherFuture == null) {
return;
}
if (mPublisherFuture != null) {
mPublisherFuture.cancel(true);
if (mMulticastLock != null) {
mMulticastLock.release();
mMulticastLock = null;
}
}
if (mApiPublisherFuture != null) {
mApiPublisherFuture.cancel(true);
}
mDelayedKiller = new Runnable() {
#Override
public void run() {
mExecutorService.shutdownNow();
killService();
stopSelf();
}
};
NetworkThread.getCommonInstance().postDelayed(mDelayedKiller, 1000 * 20); //kill the service after 20 seconds
//inform listeners
EventBus.getDefault().post(new EventServiceBroadcasting(false));
}
#Override
public void onDestroy() {
super.onDestroy();
killService();
}
private synchronized void killService() {
if (mService != null) {
try {
mService.unregisterAllServices();
mService.close();
mService = null;
} catch (IOException e) {
e.printStackTrace();
}
} else {
}
}
public static class DiscoverableAssistant {
private DiscoverableAssistant() {
}
public static boolean isDiscoverable(Context context) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean(PREF_DEVICE_DISCOVERABLE, true); //true by default
}
public static void setDiscoverable(Context context, boolean discoverable) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putBoolean(PREF_DEVICE_DISCOVERABLE, discoverable).apply();
}
}
private class BonjourPublisher implements Runnable {
#Override
public void run() {
final String serviceName = mNetworkUtils.getDeviceName(BroadcastService.this);
final String serviceType = getString(R.string.multi_dns_network_name);
final Map<String, String> properties = new HashMap<>();
properties.put(DeviceViewActivity.DEVICE_PROPERTY_DEVICE_TYPE, "Android");
properties.put(DeviceViewActivity.DEVICE_PROPERTY_FILE_SERVER_PORT,
String.valueOf(mNetworkUtils.getAssignedPort()));
if (DiscoverableAssistant.isDiscoverable(BroadcastService.this)) {
properties.put(DeviceViewActivity.DEVICE_PROPERTY_DISCOVERABLE, "true");
} else {
properties.put(DeviceViewActivity.DEVICE_PROPERTY_DISCOVERABLE, "false");
}
//acquire wifi multicast lock
if (mMulticastLock == null) {
final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mMulticastLock.setReferenceCounted(true);
mMulticastLock.acquire();
}
try {
if (mService == null) {
mService = JmDNS.create(mNetworkUtils.getMyInet4Address(),
NetworkUtils.getHostName(mNetworkUtils.getDeviceName(BroadcastService.this)));
}
final ServiceInfo info = ServiceInfo.create(serviceType, serviceName, mNetworkUtils.getAssignedPort(), 0, 0, true, properties);
while (mService != null) {
mService.registerService(info);
Thread.sleep(TIMER_DELAY_SECONDS * 1000);
mService.unregisterAllServices();
Thread.sleep(1000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
} catch (Exception e) {
}
}
}
private class ApiPublisher implements Runnable {
private APo api = null;
private SimplifiedDeviceInfo mDeviceInfo = null;
public ApiPublisher() {
api = Utils.getRetrofitInstance(BroadcastService.this, null)
.create(api.class);
}
#Override
public void run() {
try {
if (mDeviceInfo == null) {
mDeviceInfo = new SimplifiedDeviceInfo(mNetworkUtils.getDeviceName(BroadcastService.this),
mNetworkUtils.getMyInet4Address().getHostAddress(), mNetworkUtils.getAssignedPort(),
NetworkUtils.getDeviceType(), BroadcastService.DiscoverableAssistant.isDiscoverable(BroadcastService.this));
}
Call<JsonElement> call = api.broadcastDevice(mDeviceInfo);
call.execute();
} catch (Exception e) {
}
}
}
The a RejectedExecutionException is thrown when you attempt to submit a task to an executor, and it is refuses it. In this case, there is a clue in the exception message:
java.util.concurrent.ScheduledThreadPoolExecutor#42209b70[
Sh‌​‌​utting down, pool size = 2, active threads = 2,
queued tasks = 0, completed tasks = 248]
This is telling me that you are attempting to submit a task to an Executor that is being shut down.
Now I can't pretend that I understand what your code is actually doing, but I can see that it is using postThread to schedule a Runnable that shuts down the executor. My guess is that the app has done that ... and then it is somehow trying to submit another task.
In reading your code I spotted a couple of places where you catch and then squash Exception. That is a really bad idea. I wouldn't be surprised if that is why you are having trouble debugging your code.

Categories

Resources