Is it really not valid to use setDataSource on the main thread? - android

I recently noticed that I'm getting reports of the following crash in my Android Developer Console:
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099)
at java.net.InetAddress.getHostByAddrImpl(InetAddress.java:440)
at java.net.InetAddress.getHostName(InetAddress.java:313)
at android.media.MediaPlayer.checkHostdata(MediaPlayer.java:869)
at android.media.MediaPlayer.isLocalhost(MediaPlayer.java:940)
at android.media.MediaPlayer.setDataSourceBase(MediaPlayer.java:980)
at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1085)
[the rest is irrelevant]
It seems that somewhere in the MediaPlayer.setDataSource method there is some code that touches the network which is causing StrictMode to bark. Which is a bit surprising as calling setDataSource on the main thread seems to be common practice.
So my question is, what's the best way to go about dealing with this issue? Should I move the mediaPlayer out of the main thread? Should I ignore it? Or, something else?

Well, strategically, this feels like a somewhat over-aggressive bit of StrictMode logic, one that perhaps could get fixed in the future, if getHostByAddrImpl() really isn't at risk of doing a blocking network I/O call.
Tactically, you should move the setDataSource() call to a background thread, particularly when the source is pointing at the network (http, rtsp, etc.).

Related

What would cause a thread interrupt?

I'm familiar with both what an interrupt is used for (to put it roughly: asking the interrupted thread kindly to terminate or at least stop its work as soon as conveniently possible, instead of killing it immediately) as well as how to handle it properly (in most common cases, maybe not the tricky ones).
But I'm having a hard time to understand who (if not my own code) could even call Thread.interrupt() in the first place, and when this "third party interrupt" could occur.
I'm finding lots of information on why anybody would want to interrupt a thread, but hardly anything about who would do that for "my" threads unless I coded it myself.
So on Android, if my own app code does not contain any calls to Thread.interrupt() or something similar like AsyncTask<,,>.cancel(), will any thread I start ever be interrupted at all?

Debugging Java InterruptedException i.e. finding the cause

During debugging of Android app, sometimes InterruptedException occurs and crashes the app. I've been able to set a break-point on default exception handler, but call stack is not informative.
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(AbstractQueuedSynchronizer.java:1991)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2025)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1048)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:776)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1035)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1097)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:820)
What is telling is that the interrupted thread is always RxCachedThreadScheduler-4 (or some other number)
What would be a systematic approach towards finding the root cause of the exception?
Set breakpoint at the method Thread::interrupt and catch the offender. If you think that this interruption should not happen, and you cannot switch off the call which interrupts your thread, then you can override Thread::interrupt in your thread implementation, and force the the thread pool to use your implementation by providing your own ThreadFactory.
It looks like the crash is happening from a third party code package, you should post your issue with the source project as well for additional help. Please post any code related to how you use this package to help troubleshoot too. Make sure you're using the latest version of this package in case they already fixed this issue. The stack trace isn't very helpful because the other project is launching threads and the crash happens from within one of their threads. Likely, you're not using the package as intended or there is a bug in it that they need to fix.
https://github.com/ReactiveX/RxJava

AsyncTask thread never ends

I'm using an app that uses async tasks to do short term background calculation jobs. These seem to end OK (go through onPostExecute() etc), but in the Eclipse debugger, one or more still hangs around.
Then I found this link - AsyncTask threads never die - so OK, it's about a thread pool and in theory not an issue.
Problems is however, I am also trying to use Google in-app billing code V3, and that appears to throw an exception whenever you carry out a purchase and there's already an AsyncTask thread hanging around. Catching the exception won't help - it still won't do anything.
How can I get around this? What do I need to do to guarantee the old calculation thread(s) have gone?
Found out what is going on here, and it wasn't what I thought. I'll detail it here as it may be useful to somebody. Has nothing to do with other AsyncTask threads and thread pooling.
In the IabHelper class are two functions flagStartAsync() and flagEndAsync(). The aim of these is to produce a single pass gate (bit like wait() and signal() in traditional multi-threading) so only one async operation (that is, communications with Google Play and the server) can occur at a time. If flagStartAsync() get called while something is already going on, it produces an exception. Not terribly graceful, but effective I guess.
The flagStartAsync() 'test and set' gets called at the start of launchPurchaseFlow() among other places, and flagEndAsync gets called in handleActivityResult() - again - among other places. So providing the purchase flow does something that always produces a result, no problem. The problem is - it doesn't always.
If you look at launchPurchaseFlow() there are several paths out that will not kick off the async operation, and if one of those get taken, mAsyncInProgress (the relevant flag) gets left set.
What blew it in my case was that I hadn't checked that the item was already purchased, and 'already purchased' is one of the paths out. Mea culpa, but the problem is that I cannot convince myself that there aren't several other paths that you just cannot avoid at times. What if operation is slow and the 'purchase' button gets pressed twice, for instance? I bet there are others as well. One could catch the exception, and that would stop a crash, but it wouldn't really help if nothing came along to clear the flag in the end. I guess the exception handler could call flagEndAsync() but it has an uncomfortable 'sledgehammer to crack a nut' feel.
It strikes me that this is probably a non-robust piece of code. What I've done for now is call flagEndAsync() in the various ways out of launchPurchaseFlow(), but that is just a temporary fix. I don't know enough about the IabHelper code, but I think it needs more careful thought and I need to analyse it to see everything it does.

SystemClock.sleep() vs. Thread.sleep() while waiting for a semaphore loop

In order to synchronize/queue access to a shared resource, I am about to use a Semaphore, aided by a wait loop.
In order not to run into CPU pegging, I would like to sleep() a little bit inside that while loop.
I searched the http://developer.android.com reference and found two such sleep() functions and I am confused as to which one fits which scenario:
Thread.sleep()
SystemClock.sleep()
Which one better suits the case I described and why?
First of all, do you really need a wait loop? You can typically solve your problems using proper notifications, i.e. having an Object, calling wait() and notify() on it or other means (like a blocking queue, or Semaphore.acquire() in your case).
That said, if you really want a polling loop (which you really shouldn't do unless you have to), I'd stick with Thread.sleep(). There's not much of a difference, as the documentation says, except that you have the option to interrupt a Thread.sleep(). Don't rid yourself the option to do so.
Note that in case of Thread.sleep(), you're going to have to catch that exception - if you're extremely lazy, you'll probably stick with SystemClock.sleep().
The truth is:
Thread.sleep(n) could be interrupted within a call like AsyncTask by using asyncTask.cancel(true)
SystemClock.sleep(n) seems to ignore any interrupted command, thus it could be a risk of memory leak when you use it similar like here: https://github.com/square/leakcanary/blob/master/leakcanary-sample/src/main/java/com/example/leakcanary/MainActivity.java

android stop thread

hi im wanting to stop all threads when my main activity closes as some are still running afterwards and are giving NullPointerException as they try to access ArrayLists which no longer exist. however none of the obvious methods are working and they are also deprecated. is it possible as im currently using a try/catch statement as a workaround but would prefer a fix.
TIA
ng93
You need to have your MainActivity tell your threads that it's time to end. You could do this with some sort of value that each thread checks before they access the ArrayLists. Or you could live with the try/catch workaround. But there aren't any good, safe ways of killing threads, which is why those methods got deprecated.

Categories

Resources