Inserting a while loop at oncreate method in android - android

I'm trying to create a while loop inside my onCreate method, but it crashes all the time(without the loop works great). Can someone please help me?
This is the code:
while(runnersNearby.size()<3)
{
GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(lat, lang), radius);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
#Override
public void onKeyEntered(String key, GeoLocation location) {
Toast.makeText(UserProfile.this, "Successfully Found"+key, Toast.LENGTH_SHORT).show();
if (key != user.getUid())
runnersNearby.add(key);
Log.d("Number of users", String.valueOf(runnersNearby.size()));
Log.d("KEY", String.valueOf(key));
}
#Override
public void onKeyExited(String key) {
Toast.makeText(UserProfile.this, "left the place", Toast.LENGTH_SHORT).show();
runnersNearby.remove(key);
}
#Override
public void onKeyMoved(String key, GeoLocation location) {
Toast.makeText(UserProfile.this, "key moved but here", Toast.LENGTH_SHORT).show();
}
#Override
public void onGeoQueryReady() {
System.out.println("All initial data has been loaded and events have been fired!");
}
#Override
public void onGeoQueryError(DatabaseError error) {
Toast.makeText(UserProfile.this, "Error Occured", Toast.LENGTH_SHORT).show();
}
});
radius=radius*1.5;
}
logcat after fixes which were recomended:
08-23 16:53:37.979 10116-10116/com.firebase.shahaf.datasignin E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.firebase.shahaf.datasignin, PID: 10116
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.firebase.shahaf.datasignin/com.firebase.shahaf.datasignin.UserProfile}: java.lang.IllegalArgumentException: Precision of GeoHash must be larger than zero!
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2305)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2365)
at android.app.ActivityThread.access$800(ActivityThread.java:148)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1283)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5272)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704)
Caused by: java.lang.IllegalArgumentException: Precision of GeoHash must be larger than zero!
at com.firebase.geofire.core.GeoHash.<init>(GeoHash.java:29)
at com.firebase.geofire.core.GeoHashQuery.queriesAtLocation(GeoHashQuery.java:85)
at com.firebase.geofire.GeoQuery.setupQueries(GeoQuery.java:224)
at com.firebase.geofire.GeoQuery.addGeoQueryEventListener(GeoQuery.java:325)
at com.firebase.shahaf.datasignin.UserProfile.onCreate(UserProfile.java:68)
at android.app.Activity.performCreate(Activity.java:5977)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2258)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2365) 
at android.app.ActivityThread.access$800(ActivityThread.java:148) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1283) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5272) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:909) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:704) 

Infinite loop. You're looping while(runnersNearby.size()<3). But the size of the array never changes. So you loop forever. Because of that your onCreate never returns, and the system eventually kills you for taking too long to create your activity, because it assumes something is wrong.
I'm assuming what you wanted to do is loop over the runnersNearby array?
There is one place in the code where runnersNearby can change, but its in an asynchronous callback. So it will never actually be called. until much later.

You should not use a while loop, it cant work with it, you should create another function and to call it under onGeoQueryReady() and over there to do the if(instead of the while), it should work.

Put everything Internet/Network related in an AsyncTasks doInBackground, and add the EventListener in OnPostExecute(...). Than just start the Asynctask in onCreate and let your app wait for the EventListeners to kick in.
Edit: Quick and dirty example code:
public class yourClass probablyExtends Activity{
onCreate(...){
new LoadRunners().execute();
NothingToSeeHereMoveAlongAndFollowYourUsualBusiness();
}
}
public class LoadRunners extends AsyncTask {
doInBackground(..){
double radius = 1.0;
while(runnersNearby.size()<3){
loadRunners(radius);
if(runnersNearby.size()<3)
radius*=1.5;
}
}
onPostExecute(...){
addEventListeners();
}
}

Related

I got a super weird crash on Fabric onResume of my FragmentActivity, at the super.onResume()

What does this mean, and can be fixed somehow?
Not crashing in my code, but in the super of the FragmentActivity, I can't figure out what I am doing wrong:
Fatal Exception: java.lang.IllegalArgumentException
at android.os.Parcel.readException(Parcel.java:1688)
at android.os.Parcel.readException(Parcel.java:1637)
at android.app.ActivityManagerProxy.isTopOfTask(ActivityManagerNative.java:5505)
at android.app.Activity.isTopOfTask(Activity.java:5983)
at android.app.Activity.onResume(Activity.java:1253)
at android.support.v4.app.FragmentActivity.onResume(FragmentActivity.java:485)
at nl.hgrams.passenger.activities.PSTimelineFragmentsActivity.onResume(PSTimelineFragmentsActivity.java:576)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1270)
at android.app.Activity.performResume(Activity.java:6788)
at android.app.ActivityThread.performNewIntents(ActivityThread.java:2844)
at android.app.ActivityThread.handleNewIntent(ActivityThread.java:2858)
at android.app.ActivityThread.-wrap15(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1575)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6186)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
This is my onResume():
#Override
protected void onResume() {
super.onResume();
registerReceiver(addedPitstopBroadcastReceiver,
new IntentFilter("addedPitstop"));
if (PSApplicationClass.getInstance().pref.getUserId(PSTimelineFragmentsActivity.this) != null) {
renewSettings();
PSApplicationClass.getInstance().pref.setIsBackground(this, false);
if (PSApplicationClass.getInstance().pref.isRefetchUser(PSTimelineFragmentsActivity.this)) {
PSApplicationClass.getInstance().pref.setRefetchUser(PSTimelineFragmentsActivity.this, false);
MyFirebaseInstanceIDService.changeFirebaseToken(PSTimelineFragmentsActivity.this);
}
}
}
But it directly crashed at onResume, so it didn't pass to the next line. Also tried to reproduce me, but could not.
The user had a: LG G-Pad 8.3

Out of Memory Error RxAndroid + RxJava + Retrofit2

I am new to using RxAndroid and RxJava. I am using RxJava + Retrofit2 to make GET requests. I am doing approximately 1500 GET requests using the following code and getting Out of memory error. However the same code this time with only retrofit, NO RxAndroid and it works. So my conclusion was I am doing something wrong in RxAndroid. Can you please help with what I am missing?
Code Sample:
Subject<Story> mStoryEmitter = PublishSubject.create();
private void getStory(int storyID) {
HNApi.Factory.getInstance().getStory(storyID).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(getStoryObserver());
}
mStoryListEmitter.subscribe(new Observer<List<Integer>>() {
#Override
public void onSubscribe(Disposable d) {}
#Override
public void onNext(List<Integer> value) {
if(mRecyclerView != null) {
mRecyclerView.setAdapter(null);
if(mAdapter != null) {
mAdapter.clear();
mAdapter = null;
}
}
mAdapter = new SimpleRecyclerViewAdapter();
mRecyclerView.setAdapter(mAdapter);
for(Integer storyID : value) {
getStory(storyID);
}
}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {}
});
private DisposableObserver<Story> getStoryObserver() {
DisposableObserver<Story> observer = new DisposableObserver<Story>() {
#Override
public void onNext(Story value) {
mStoryEmitter.onNext(value);
dispose();
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
};
return observer;
}
Error:
Throwing OutOfMemoryError "Could not allocate JNI Env"
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:111)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.OutOfMemoryError: Could not allocate JNI Env
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:921)
at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1556)
at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:310)
at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:543)
at java.util.concurrent.ScheduledThreadPoolExecutor.submit(ScheduledThreadPoolExecutor.java:642)
at io.reactivex.internal.schedulers.NewThreadWorker.scheduleActual(NewThreadWorker.java:120)
at io.reactivex.internal.schedulers.IoScheduler$EventLoopWorker.schedule(IoScheduler.java:221)
at io.reactivex.Scheduler.scheduleDirect(Scheduler.java:130)
at io.reactivex.Scheduler.scheduleDirect(Scheduler.java:109)
AppData::create pipe(2) failed: Too many open files
at io.reactivex.internal.operators.observable.ObservableSubscribeOn.subscribeActual(ObservableSubscribeOn.java:36)
at io.reactivex.Observable.subscribe(Observable.java:10514)
at io.reactivex.internal.operators.observable.ObservableObserveOn.subscribeActual(ObservableObserveOn.java:44)
at io.reactivex.Observable.subscribe(Observable.java:10514)
at com.example.MainActivity.getStory(MainActivity.java:100)
at com.example.MainActivity.access$300(MainActivity.java:25)
at com.example.MainActivity$2.onNext(MainActivity.java:67)
at com.example.MainActivity$2.onNext(MainActivity.java:49)
at io.reactivex.subjects.PublishSubject$PublishDisposable.onNext(PublishSubject.java:263)
at io.reactivex.subjects.PublishSubject.onNext(PublishSubject.java:182)
at com.example.MainActivity$5.onNext(MainActivity.java:147)
at com.example.MainActivity$5.onNext(MainActivity.java:138)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:198)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:250)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
... 7 more
AppData::create pipe(2) failed: Too many open files
FATAL EXCEPTION: main
Process: com.example, PID: 15857
java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:111)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.OutOfMemoryError: Could not allocate JNI Env
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:921)
at java.util.concurrent.ThreadPoolExecutor.ensurePrestart(ThreadPoolExecutor.java:1556)
at java.util.concurrent.ScheduledThreadPoolExecutor.delayedExecute(ScheduledThreadPoolExecutor.java:310)
at java.util.concurrent.ScheduledThreadPoolExecutor.schedule(ScheduledThreadPoolExecutor.java:543)
at java.util.concurrent.ScheduledThreadPoolExecutor.submit(ScheduledThreadPoolExecutor.java:642)
at io.reactivex.internal.schedulers.NewThreadWorker.scheduleActual(NewThreadWorker.java:120)
at io.reactivex.internal.schedulers.IoScheduler$EventLoopWorker.schedule(IoScheduler.java:221)
at io.reactivex.Scheduler.scheduleDirect(Scheduler.java:130)
at io.reactivex.Scheduler.scheduleDirect(Scheduler.java:109)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn.subscribeActual(ObservableSubscribeOn.java:36)
at io.reactivex.Observable.subscribe(Observable.java:10514)
at io.reactivex.internal.operators.observable.ObservableObserveOn.subscribeActual(ObservableObserveOn.java:44)
at io.reactivex.Observable.subscribe(Observable.java:10514)
at com.example.MainActivity.getStory(MainActivity.java:100)
at com.example.MainActivity.access$300(MainActivity.java:25)
at com.example.MainActivity$2.onNext(MainActivity.java:67)
at com.example.MainActivity$2.onNext(MainActivity.java:49)
at io.reactivex.subjects.PublishSubject$PublishDisposable.onNext(PublishSubject.java:263)
at io.reactivex.subjects.PublishSubject.onNext(PublishSubject.java:182)
at com.example.MainActivity$5.onNext(MainActivity.java:147)
at com.example.MainActivity$5.onNext(MainActivity.java:138)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:198)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:250)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
... 7 more
Posted the same question at RxAndroid github.
And JakeWharton reply acually heped
The problem is that Schedulers.io() uses a cached thread pool without a limit and thus is trying to create 1500 threads. You should consider using a Scheduler that has a fixed limit of threads, or using RxJava 2.x's parallel() operator to parallelize the operation to a fixed number of workers.
If you're using raw Retrofit by default it uses OkHttp's dispatcher which limits the threads to something like 64 (with a max of 5 per host). That's why you aren't seeing it fail.
If you use createAsync() when creating the RxJava2CallAdapterFactory it will create fully-async Observable instances that don't require a subscribeOn and which use OkHttp's Dispatcher just like Retrofit would otherwise. Then you only need observeOn to move back to the main thread, and you avoid all additional thread creation.
Add all your Disposables to CompositeDisposable and dispose it for every cycle
CompositeDisposable disposable = new CompositeDisposable();
mStoryListEmitter.subscribe(new Observer<List<Integer>>() {
#Override
public void onSubscribe(Disposable d) {
disposable.add(d); // adding disposable
}
#Override
public void onNext(List<Integer> value) {
if(mRecyclerView != null) {
mRecyclerView.setAdapter(null);
if(mAdapter != null) {
mAdapter.clear();
mAdapter = null;
}
}
mAdapter = new SimpleRecyclerViewAdapter();
mRecyclerView.setAdapter(mAdapter);
for(Integer storyID : value) {
getStory(storyID);
}
}
#Override
public void onError(Throwable e) {}
#Override
public void onComplete() {
diposable.dispose(); // <--- Disposing on complete
}
})
;

OnErrorNotImplementedException somehow still being called with included error handling

Im performing a write to a BLE characteristic, where with these specific devices certain characteristics are not writeable if the peripheral is still locked.
I'd like to simply provide a visual notification if this is called while the device is still locked, instead of the exception being thrown.
Here is the first part of the code which is from a custom library I've written for this application:
public Observable<byte[]> setInterval(int interval) {
if (!(interval > 0)) {
return Observable.error(new IllegalArgumentException("Interval must be greater than 0."));
}
byte[] bytes = Utils.formatIntToBytes(interval);
return mConnection.writeCharacteristic(Constants.INTERVAL, bytes)
.doOnError(throwable -> Log.d(TAG, "call: Error writing to the interval characteristic"))
.onErrorReturn(throwable -> {
return new byte[0];
});
}
And here is the method that uses the previous:
private void setInterval(int interval) {
mDevice.setInterval(interval)
.onErrorResumeNext(throwable -> {
return Observable.empty();
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<byte[]>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onNext(byte[] bytes) {
if (bytes != null) {
Toast.makeText(DeviceDetailActivity.this, Utils.formatResponse(bytes), Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(DeviceDetailActivity.this, "Seems to of been an error. Ensure the device is unlocked.", Toast.LENGTH_SHORT).show();
}
}
});
}
This was previously just an Action1, but I changed to a Subscriber to clearly show onError() has been implemented.
I've added a bunch of extra operators (onErrorReturn(), onErrorResumeNext()) in an attempt to prevent the exception.
Why is the exception still coming through?
EDIT: The stack trace:
java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.
at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:112)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: rx.exceptions.OnErrorNotImplementedException
at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:386)
at rx.internal.util.InternalObservableUtils$ErrorNotImplementedAction.call(InternalObservableUtils.java:383)
at rx.internal.util.ActionSubscriber.onError(ActionSubscriber.java:44)
at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:152)
at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:115)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.checkTerminated(OperatorObserveOn.java:276)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.call(OperatorObserveOn.java:219)
at rx.android.schedulers.LooperScheduler$ScheduledAction.run(LooperScheduler.java:107)
at android.os.Handler.handleCallback(Handler.java:739) 
at android.os.Handler.dispatchMessage(Handler.java:95) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5417) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
Caused by: BleGattException{status=8, bleGattOperation=BleGattOperation{description='CHARACTERISTIC_WRITE'}}
at com.polidea.rxandroidble.internal.connection.RxBleGattCallback.propagateStatusErrorIfGattErrorOccurred(RxBleGattCallback.java:245)
at com.polidea.rxandroidble.internal.connection.RxBleGattCallback.access$100(RxBleGattCallback.java:26)
at com.polidea.rxandroidble.internal.connection.RxBleGattCallback$1.onCharacteristicWrite(RxBleGattCallback.java:110)
at android.bluetooth.BluetoothGatt$1.onCharacteristicWrite(BluetoothGatt.java:407)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:279)
at android.os.Binder.execTransact(Binder.java:453)

Android Glide Error:You cannot start a load for a destroyed activity

i am using glide to view images which am getting as url from database in my activity,and i am deleting an image in activity where after deleting next activity will be opened but first time the image is deleting without any error,second time if open to and press delete I am getting this error:
java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
This is my code to delete the image:
alert.setNegativeButton("Delete", new DialogInterface.OnClickListener() {
#Override
public void onClick(final DialogInterface dialogInterface, final int i) {
try {
final Query postRef = ref.child("Pendingevents").orderByChild("Eventtitle").equalTo(Title);
postRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child : dataSnapshot.getChildren()) {
child.getRef().removeValue();
Toast.makeText(getApplicationContext(), "Event Deleted", Toast.LENGTH_SHORT).show();
Intent intent=new Intent(getApplicationContext(),PendingEvents.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
#Override
public void onCancelled(DatabaseError firebaseError) {
}
});
}catch (Exception e)
{
Toast.makeText(ApproveEvents.this, "Unknown Error,please Try Again", Toast.LENGTH_SHORT).show();
}
}
});
AlertDialog build=alert.create();
build.show();
}
});
Logcat:
java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
at com.a.a.e.o.b(Unknown Source)
at com.a.a.e.o.a(Unknown Source)
at com.a.a.f.a(Unknown Source)
at bootcamplearning.humanplanet.u.a(Unknown Source)
at com.google.android.gms.b.ol.a(Unknown Source)
at com.google.android.gms.b.qh.b(Unknown Source)
at com.google.android.gms.b.qn.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5294)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)
Update
It is better not to use the approach, described at the bottom of post.
The main idea is that Glide is concerned about lifecycle of an element where it works. If a Fragment or an Activity will be destroyed, Glide finishes its work for image processing. Here is a detailed discussion of the issue.
To sum up, you should check if your activity is alive before calling load going back from some AsyncTask or other threads:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && someActivity.isDestroyed()) {
return;
} else {
Glide.with(someActivity)
.load(imageUrl)
....;
}
Workaround, not recommended because it will lead to some unnecessary processing if Activity was destroyed. But it is easy to use and makes its work.
In Glide.with(context) try to pass Application context instead of Activity. In this case you should not depend from Activity lifecycle.
For example, in activity you could use this:
Glide.with(getApplicationContext())
.load(imageUrl)
.into(yourImageView);
Or in framgent:
Glide.with(getActivity().getApplicationContext())
.load(imageUrl)
.into(yourImageView);
In the fragment, use:
if(getActivity !=null) {
Glide.with(getActivity())
.load(imageUrl)
.into(yourImageView);
}

How to properly handle onError inside RxJava (Android)?

I'm getting a list of installed apps on the device. It's a costly operation, so I'm using Rx for that:
Observable<List> observable = Observable.create(subscriber -> {
List result = getUserApps();
subscriber.onNext(result);
subscriber.onError(new Throwable());
subscriber.onCompleted();
});
observable
.map(s -> {
ArrayList<String> list = new ArrayList<>();
ArrayList<Application> applist = new ArrayList<>();
for (Application p : (ArrayList<Application>) s) {
list.add(p.getAppName());
applist.add(p);
}
return applist;
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage()))
.subscribe(s -> createListView(s, view));
However, my problem is with handling errors.
Normally, user launches this screen, waits for apps to load, selects what is best and goes to next page. However, when user quickly changes the UI - app crashes with NullPointer.
Okay, so I implemented this onError. However it still doesn't work, and with above usecase it throws me this:
04-15 18:12:42.530 22388-22388/pl.digitalvirgo.safemob E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:52)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
Caused by: rx.exceptions.OnErrorNotImplementedException
at rx.Observable$31.onError(Observable.java:7134)
at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:154)
at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)
at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70)
at rx.internal.operators.NotificationLite.accept(NotificationLite.java:147)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:177)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.access$000(OperatorObserveOn.java:65)
at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:153)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:176)
            at android.app.ActivityThread.main(ActivityThread.java:5419)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
            at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.Throwable
at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment.lambda$getAppList$25(ApplicationsFragment.java:267)
at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment.access$lambda$2(ApplicationsFragment.java)
at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment$$Lambda$3.call(Unknown Source)
at rx.Observable$1.call(Observable.java:145)
at rx.Observable$1.call(Observable.java:137)
at rx.Observable.unsafeSubscribe(Observable.java:7304)
at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
at java.util.concurrent.FutureTask.run(FutureTask.java:234)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:153)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:267)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
How should I properly handle this problem?
.doOnError() is an operator, and is not as such a part of the Subscriber.
Therefore, having a .doOnError() does not count as an implemented onError().
About the question in one of the comments, of course it is possible to use lambdas.
In this case simply replace
.doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage()))
.subscribe(s -> createListView(s, view))
with
.subscribe(s -> createListView(s, view),
throwable -> L.e(TAG, "Throwable " + throwable.getMessage()))
My take is: you are probably using Action1 in
.subscribe(s -> createListView(s, view));
You will need to replace it with Subscriber or Observer which has abstract method onError. This method will be called from subscriber.onError(new Throwable());
EDIT: This is how I would do it. Upon closer look I think the main problem in your code is the early part where you call subscriber.onError even when there's no error. You probably don't need map either because you are technically passing data as-is without manipulation. But I left it in case it is needed later.
Observable.create(new Observable.OnSubscribe<Application>() {
#Override
public void call(Subscriber<? super Application> subscriber) {
List result = getUserApps();
if (result != null){
for (Application app : result){
subscriber.onNext(app);
}
subscriber.onComplete();
}else{
subscriber.onError(new IOException("no permission / no internet / etc"));
//or if this is a try catch event you can pass the exception
}
}
})
.subscribeOn(Schedulers.io())//the thread *observer* runs in
.observeOn(AndroidSchedulers.mainThread())//the thread *subscriber* runs in
.map(new Func1<Application, String>() {
// Mapping methods are where data are manipulated.
// You can simply skip this and
//do the same thing in Subscriber implementation
#Override
public String call(Application application) {
return application.getName();
}
}).subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
Toast.makeText(context, "completed", Toast.LENGTH_SHORT).show();
//because subscriber runs in main UI thread it's ok to do UI stuff
//raise Toast, play sound, etc
}
#Override
public void onError(Throwable e) {
Log.e("getAppsError", e.getMessage());
//raise Toast, play sound, etc
}
#Override
public void onNext(String s) {
listAdapter.add(s);
}
});
Here is the newbie response (because I am new in javarx and finally fix this issue) :
Here is your implementation :
Observable.create(new Observable.OnSubscribe<RegionItem>() {
#Override
public void call(Subscriber<? super RegionItem> subscriber) {
subscriber.onError(new Exception("TADA !"));
}
})
.doOnNext(actionNext)
.doOnError(actionError)
.doOnCompleted(actionCompleted)
.subscribe();
In this previous implementation, when I subscribe I trigger the error flow ... and I get an application crash.
The problem is that you HAVE TO manage the error from the subscribe() call. The "doOnError(...)" is just a kind of helper that clone the error and give you a new place to do some action after an error. But it doesn't Handle the error.
So you have to change your code with that :
Observable.create(new Observable.OnSubscribe<RegionItem>() {
#Override
public void call(Subscriber<? super RegionItem> subscriber) {
subscriber.onError(new Exception("TADA !"));
}
})
.subscribe(actionNext, actionError, actionCompleted);
Not sure about the real explanation, but this is how I fix it. Hope it will help.

Categories

Resources