when I use exoplayer I get a player is accessed on the wrong thread error. How can I solve this?
Non-fatal Exception: java.lang.IllegalStateException: Player is accessed on the wrong
thread.
Current thread: 'main'
Expected thread: 'ConnectivityThread'
See https://exoplayer.dev/issues/player-accessed-on-wrong-thread
The player is started as a service via my BackgroundAudioService.class.
exoPlayer = new ExoPlayer.Builder(getApplicationContext()
.build();
In the main thread my looper is running, the
which updates the UI via exoplayer.getCurrentPosition().
public final Runnable updatePosition = new Runnable() {
#Override
public void run() {
position = BackgroundAudioService.getCurrentPostion();
}
}
myHandler.postDelayed(updatePosition, myHandlerSleep);
I don't know how to solve this problem (which occurs just sometimes), please help.
Thanks
Alejandro
I solved this by calling the status via a handler in the player's event listener. Starting a runnable from the listener which runs only when player.isPlaying() == true.
player.addListener(new Player.Listener() {
#Override
public void onEvents(Player player, Player.Events events) {
Player.Listener.super.onEvents(player, events);
if (events.contains(Player.EVENT_IS_PLAYING_CHANGED)) {
if (player.isPlaying()) {
positionHandler.postDelayed(getCurrentPositionTask,CURRENT_POSITION_SLEEP);
} else {
positionHandler.removeCallbacks(getCurrentPositionTask);
}
}
}
});
public Runnable getCurrentPositionTask = new Runnable() {
#Override
public void run() {
if (exoPlayer != null) {
currentPostion = exoPlayer.getCurrentPosition();
positionHandler.postDelayed(getCurrentPositionTask,CURRENT_POSITION_SLEEP);
}
}
};
The UI calls the current position the same way in a runnable.
I can't say whether this is the best way. but it's going well.
GGK
Related
Can someone help me to correct my code.
(https://i.stack.imgur.com/jKOvH.png)
I am trying to display realtime Count from 0 to 10 and displaying that on textView but always crash. Iam new on android but Very excited to learn.please help me explain that problem. Sorry for my bad English.
Well, i'm not an Android developer myself but from what i understood online, what you did is to create a Handler and provide Looperassociated with the main thread. This associate this handler to the main thread. When we post the Runnable, it gets queued in the main thread’s MessageQueue and then executed in the main thread.
Creating an own thread and providing Lopper and MessageQueue is not the right way to deal with the problem. So, Android has provided HandlerThread(subclass of Thread) to streamline the process. Internally it does the same things that we have done but in a robust way. So, always use HandlerThread.
private class MyHandlerThread extends HandlerThread {
Handler handler;
public MyHandlerThread(String name)
{
super(name);
}
#Override
protected void onLooperPrepared() {
handler = new Handler(getLooper()) {
#Override
public void handleMessage(Message msg) {
// process incoming messages here
// this will run in non-ui/background thread
}
};
}
}
Information found at: https://blog.mindorks.com/android-core-looper-handler-and-handlerthread-bd54d69fe91a
Try this code to create new thread under activity. there is no need to create handler.
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i <= 10; i++) {
final int value = i;
text.setText(value);
}
}
};
new Thread(runnable).start();
just :
new Handler().post(new Runnable() {
#Override
public void run() {
...
}
});
you can try it.
I have got a Class for a CustomView that has to inner Classes, both implement Runnable to do a Job in a separate Thread.
public class ValueSelector extends LinearLayout{
.....
private class AutoIncrementer implements Runnable {
#Override
public void run() {
if (plusButtonIsPressed) {
incrementValue();
mHandler.postDelayed(new AutoIncrementer(), REPEAT_INTERVAL_MS);
} else {
mHandler.removeCallbacks(this);
Thread.currentThread().interrupt();
}
}
}
private class AutoDecrementer implements Runnable {
#Override
public void run() {
if (minusButtonIsPressed) {
decrementValue();
mHandler.postDelayed(new AutoDecrementer(), REPEAT_INTERVAL_MS);
} else {
mHandler.removeCallbacks(this);
Thread.currentThread().interrupt();
}
}
}
}
How to clean them up properly?
Do they get Destroyed automatically when the Activity hosting those CustomViews gets destroyed?
Cheers
It will not get destroyed causing a memory leak, as your thread will have a strong reference to your view, and hence your activity.
Make the inner class static and hold weak reference to variables you need in run method.
Second thing you can do is interrupt your thread , when you view get detached from the window and have check in the run method if thread got interrupted or not, though not necessary if your thread is not doing too much work.
Here is what your runnable should look like
private static class AutoDecrementer implements Runnable {
AutoDecrementer (ValueSelector valueSelector ){
this.weakRef = new WeakReference<>(valueSelector);
}
#Override
public void run() {
ValueSelector valueSelector = (ValueSelector )weakRef.get();
if(valueSelector == null){
return ;
}
if (valueSelector.minusButtonIsPressed) {
valueSelector .decrementValue();
valueSelector .mHandler.postDelayed(new AutoDecrementer(), REPEAT_INTERVAL_MS);
} else {
valueSelector.mHandler.removeCallbacks(this);
Thread.currentThread().interrupt();
}
}
}
I have not checked for any errors.
No, it will cause error if Activity is destroyed while timer event is still pending. To avoied that, use WeakReference to some object, decrementing value.
But, generally it is bad practice - to mix UI and some ligic, because it is difficule to test. Consider using rxJava library, this will look like
Subscriptioin s = Observable.just(100, TimeUnit.Milliseconds)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.computation())
.subscribe(t -> decrementValue());
in your onPause() method cancel that actioin by
if (s != null && !s.inUnsubscribed()) {
s.unsubscribe();
s = null;
}
I want to make downloader, which download data and then call function in UI thread. I have this in main activity
onCreate(){
...
dataRepository.downloadIfNewOrEmpty(new DownloadResponse() {
#Override
public void SuccessResponse(Response response) {
// do something in UI
}
});
}
My function downloadIfNewOrEmpty looks for now only simple with sleep()
public void downloadIfNewOrEmpty(final DownloadResponse response){
//final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
response.SuccessResponse(ResponseCode.SUCCESS);
/*handler.post(new Runnable() {
#Override
public void run() {
response.SuccessResponse(ResponseCode.SUCCESS);
}
});*/
}catch (Exception e){
// Log...
}
}
}).start();
}
If I run this code, it normally does the job and update my UI. I found this solution with Handler (android.os.Handler) but if I run it without or with Handler (commented version) it works same.
Although without handler function SuccessResponse is run in UI thread?
Thank you
Although without handler function SuccessResponse is run in UI thread?
Yes, because response is instance of DownloadResponse which is passed from UI Thread as parameter to downloadIfNewOrEmpty.
I am currently creating an Android app and encounter an issue and I haven't solved yet.
I use the Retrofit library to send requests to a server, according to the Retrofit library it is done in a background thread.
I call this Retrofit request in the main thread and I want to wait for this background thread to finish in order to work on its output.
I found a similar question on the forum but I don't know how to implement :
Android: how to wait AsyncTask to finish in MainThread?
I call the request with Retrofit, when the request is finished, the success method of the Callback object starts, but main thread is still running and it reaches the last line before the background task has finished.
How can I force my main thread to wait for the background task to finish ?
My code :
// ... (main thread)
// CALL TO THE SERVER
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(LoginScreen.ENDPOINT).build();
WebServices getFiles = restAdapter.create(WebServices.class);
Callback<Response> callback = new Callback<Response>()
{
#Override
public void success(Response s, Response response)
{
fileAvailable = new String(((TypedByteArray) s.getBody()).getBytes());
//THIS IS EXECUTED WHEN THE BACKGROUND TASK IS FINISHED
}
#Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
getFiles.getFiles(id, callback);
// I want here to work with fileAvailable, but the code
// reaches this line before the background task is over.
I tried to create a Handler object as in the previous link and call sendEmptyMessage in the success method but it didn't work.
I would be really grateful if somebody could help me.
Thank you in advance,
You don't want to block your main thread, that's the whole point of this library. You need to reconsider how you do this because if you block the main thread the UI will hang (be unresponsive) and the user will be upset. Think about the last time you used an app and everything locked up for several seconds. That is what happens if you block the main thread.
Instead, you should continue your logic in the response handler, or you can call into a function of the outer class from the inner class (callback is the inner class).
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(LoginScreen.ENDPOINT).build();
WebServices getFiles = restAdapter.create(WebServices.class);
Callback<Response> callback = new Callback<Response>()
{
#Override
public void success(Response s, Response response)
{
fileAvailable = new String(((TypedByteArray) s.getBody()).getBytes());
doSomethingOnSuccess();
}
#Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
//this runs before success(), so show a spinner or something,
//eg:http://stackoverflow.com/questions/9157504/put-a-progressbar-on-actionbar
}
-- Update (per your comment about having multiple background tasks --
If you've got 2 or more background tasks running in parallel (meaning they don't depend on each others output) but you need all of them to complete before you can do anything with them, it would probably look like this:
public class MyActivity extends Activity {
private Result result1 = null;
private Result result2 = null;
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
Callback<Response> callback1 = new Callback<Response>() {
#Override
public void success(Response s, Response response)
{
result1 = new String(((TypedByteArray) s.getBody()).getBytes());
checkComplete();
}
#Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
Callback<Response> callback2 = new Callback<Response>() {
#Override
public void success(Response s, Response response)
{
result2 = new String(((TypedByteArray) s.getBody()).getBytes());
checkComplete();
}
#Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
getFiles.getFiles(id, callback1);
otherthing.doSomething(id, callback2);
}
private void checkComplete() {
if (result1 != null && result2 != null) {
doSomethingWithResults();
}
}
private void doSomethingWithResults() {
//update UI
}
}
There's no "last line" for the main thread, it's ongoing. Main thread is not finished after onCreate() is done executing. Just put the code you want to execute on the data into the success handler right where
//THIS IS EXECUTED WHEN THE BACKGROUND TASK IS FINISHED
is.
I have a thread inside a class like this-
import java.util.Observable;
public class Download extends Observable {
private int state = 0;
private final Thread myThread = new Thread(() -> {
/*
some work to do here
*/
setChanged();
notifyObservers(state);
});
public void download(int state) {
if (!myThread.isAlive()) {
this.state = state;
myThread.start();
}
}
public Thread getThread() {
return myThread;
}
public static void MyMethod() throws InterruptedException {
Download down = new Download();
down.addObserver((Observable ob, Object dat) -> {
System.out.println(ob);
if ((int) dat == 1) {
down.download(2);
} else {
System.out.println("success");
}
});
down.download(1);
down.getThread().join();
}
public static void main() throws InterruptedException {
MyMethod();
}
}
The problem is I never get it to print the "success" message.
I assume, it is because all observers are being notified from inside of MyThread. So when down.download(2) is called from the observer inside MyMethod(), the previous thread is still running and the call is ignored.
How can I notify all observers from the main thread, not from the myThread?
You are calling down.download(2) from within the execution of MyThread, therefore the thread is still alive which means that your download method does nothing because of if(!myThread.isAlive()).
I would recommend you to use the Executor framework and Listenable Futures from Guava instead of creating threads manually. Example code from the Guava wiki:
ListeningExecutorService service =
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
public Explosion call() {
return pushBigRedButton();
}
});
Futures.addCallback(explosion, new FutureCallback<Explosion>() {
// we want this handler to run immediately after we push the big red button!
public void onSuccess(Explosion explosion) {
walkAwayFrom(explosion);
}
public void onFailure(Throwable thrown) {
battleArchNemesis(); // escaped the explosion!
}
});
Note that Futures.addCallback(..) also has an overload which allows you to determine which executor should execute the callback, this seems to be what you want.