Activity still staying over previous activity in Android Strange Behaviour - java

The situation is I call an activity from my RouteActivity by:
arrived.observe(this, new Observer<Boolean>() {
#Override
public void onChanged(Boolean aBoolean) {
if(aBoolean==true){
Intent intent = new Intent(MyApplication.getAppContext(), RouteCompleteActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.slide_up, R.anim.do_nothing);
finish();
}
}
});
That is fine then when I close the activity by calling:
Intent navIntent = new Intent(MyApplication.getAppContext(), NavigationStartActivity.class);
navIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(navIntent);
finish();
This takes me back to my main NavigationStartActivity, then when I again choose to go back to my RouteActivity the original, the RouteCompleteActivity is still over the top of it? so instead of RouteActivity I get RouteCompleteActivity then if I press back it goes to the RouteActivity?? as if it has remembered some backstack? can anyone explain this?

I assume that you're using a LiveData from a viewModel or repository which keeps its value. The case is like this: arrived has a true value and onChanged will be called. The next time RouteActivity observes arrived, onChanged will be called again because it already has a value and another startAcrivity will be called. A simple solution would be using SingleLiveEvent instead which was created by google long time ago link
public class SingleLiveEvent<T> extends MutableLiveData<T> {
private static final String TAG = "SingleLiveEvent";
private final AtomicBoolean mPending = new AtomicBoolean(false);
#MainThread
public void observe(LifecycleOwner owner, final Observer<T> observer) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.");
}
// Observe the internal MutableLiveData
super.observe(owner, new Observer<T>() {
#Override
public void onChanged(#Nullable T t) {
if (mPending.compareAndSet(true, false)) {
observer.onChanged(t);
}
}
});
}
#MainThread
public void setValue(#Nullable T t) {
mPending.set(true);
super.setValue(t);
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
#MainThread
public void call() {
setValue(null);
}
}
It simply calls onChange when a new value is set. I also recommend to take a look at this article which describes it deeper

Related

How can I change value of variable in side method from anonymous inner class?

How can I change the value of a variable inside the method from anonymous inner class, to access this variable it must be a final, but if the variable final can't change its value, how solve this problem using java?
This is My Code, I want to change the value of addFlag.
public static boolean addUser(UserModle user){
Boolean addFlag ;
dbUser = FirebaseDatabase.getInstance().getReference("user");
Task task = dbUser.child(user.getId()).setValue(user);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
addFlag = true;
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
return addFlag;
}
IMHO, the current implementation of the addUser function is flawed. As per my understanding, you want to know if the user was added successfully to your firebase database based on the addFlag value that is returned from this function.
The addFlag will be updated once the Firebase database call will get back the data from the firebase realtime database. However, you are returning the flag immediately and hence you are not waiting for the result from your background network thread.
In order to achieve that, I would like to suggest an interface based implementation. You might have an interface as follows.
public interface FirebaseListener {
void onSuccess(boolean flag);
}
Then add an extra parameter in your addUser function to pass that interface from your Activity or Fragment where you are calling this function. Hence the function might look as follows.
// Change the return type to void, as we are not expecting anything from this function.
// Instead, we will wait for the success callback using the interface
public static void addUser(UserModle user, FirebaseListener listener) {
dbUser = FirebaseDatabase.getInstance().getReference("user");
Task task = dbUser.child(user.getId()).setValue(user);
task.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
listener.onSuccess(true);
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
listener.onSuccess(false);
}
});
}
Now implement the listener in your activity or fragment as follows.
public MyActivity extends AppCompatActivity implements FirebaseListener {
// ... Other functions of your activity
#Override
public void onSuccess(boolean flag) {
if (flag) {
// User add successful. Do something here
} else {
// User add not successful. Do something here
}
}
}
Now while calling the addUser function, you should pass the callback listener along with it as follows.
addUser(user, this);
I hope that helps.

RxJava gate mechanism

I want to implement something like gate mechanism.
I need one PublishSubject and a couple of subscribers. When PublishSubject send data via onNext only one subscriber will receive it.
For example:
I have 3 equals fragments inside tabs. They have subscription to global published called onLoginPublisher.
When onResume or onPause called gate becomes open or closed.
When onLogin called and no gates are opened because of no one of these fragments on screen, onNext will wait for fragment's onResume
Look at the pic:
You can use filter with the gate's state. For example, you can wrap all the logic into a class:
public final class GatedSubject<T> {
final PublishSubject<T> subject = PublishSubject.create();
final AtomicReferenceArray<Boolean> gates;
public GatedSubject(int numGates) {
gates = new AtomicReferenceArray<>(numGates);
}
public boolean getGateStatus(int gateIndex) {
return gates.get(gateIndex) != null;
}
public void setGateStatus(int gateIndex, boolean status) {
gates.set(gateIndex, status ? Boolean.TRUE : null);
}
public void Observable<T> getGate(int gateIndex) {
return subject.filter(v -> getGateStatus(gateIndex));
}
public void onNext(T item) {
subject.onNext(item);
}
public void onError(Throwable error) {
subject.onError(error);
}
public void onComplete() {
subject.onComplete();
}
}

Android: How to use JobFinished of JobService

I didn't see example of using jobFinshed of JobService, seems like we have to track changes when some condition meet we have to call jobFinished() method, am I right?
The difficulty of calling jobFinished() from another class like an IntentService seems to be getting an instance of your class that extends JobService to use to call jobFinished(). You can get info on the scheduled job, but not on the JobService (at least, I can't find a way). I can think of 3 ways to call jobFinished().
If you don't care if your work is successful or not, or if your work takes very little time.
In one of my JobService classes, I'm doing periodic work. I'm not worried about handling failures. The task will execute again soon enough. If this is the case, you can do this.
public boolean onStartJob(JobParameters params) {
startService(new Intent(this, MyIntentServiceThatDoesTheWork.class));
// job not really finished here but we assume success & prevent backoff procedures, wakelocking, etc.
jobFinished(params, false);
return true;
}
This is also the way you want to do it if your work is short enough it's no problem to do it on the UI thread. In this case, do all your work in onStartJob() then return false.
Use a BroadcastReceiver to send a message from the IntentService to the JobService (a separate file for each class).
// common Strings
public static final String IS_SUCCESS = "isSuccess";
public static final String MY_BC_RCVR = "MyBroadcastRcvr";
Your JobService
public class MyJobService extends JobService {
JobParameters mParams;
public boolean onStartJob(JobParameters params) {
mParams = params;
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter(MY_BC_RCVR));
startService(new Intent(this, MyIntentServiceThatDoesTheWork.class));
return true;
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean isSuccess = false;
if(intent.hasExtra(IS_SUCCESS)) {
isSuccess = intent.getBooleanExtra(IS_SUCCESS, false);
}
LocalBroadcastManager.getInstance(context).unregisterReceiver(this);
jobFinished(mParams, !isSuccess);
}
};
}
& your IntentService
public class MyIntentServiceThatDoesTheWork extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
boolean isSuccess = methodToDoAllMyWork();
Intent bcIntent = new Intent(MY_BC_RCVR);
bcIntent.putExtra(IS_SUCCESS, isSuccess);
LocalBroadcastManager.getInstance(this).sendBroadcast(bcIntent);
}
}
Nest your worker thread class in the JobService class.
I've given an example of an AsyncTask based on this Medium post (also referenced by Arseny Levin) from a Google Developer Advocate but it should also be possible to use an IntentService (see this SO post for nesting IntentService).
public class MyJobService extends JobService {
JobParameters mParams;
public boolean onStartJob(JobParameters params) {
mParams = params;
new MyAsyncTaskThatDoesTheWork().execute();
return true;
}
private class MyAsyncTaskThatDoesTheWork extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... params) {
return methodToDoAllMyWork();
}
#Override
protected void onPostExecute(Boolean isSuccess) {
if(mParams != null) {
jobFinished(mParams, !isSuccess);
}
}
}
}
If your onStartJob() method returns true, that means that you are doing work in the background in support of this job. That background thread needs to call jobFinished() when that work has been completed or if the job needs to be rescheduled.
A simple approach is to start a new thread from onStartJob as shown below:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
#Override
public boolean onStartJob(final JobParameters params) {
new Thread(new Runnable() {
#Override
public void run() {
// do your job here
jobFinished(params, true);
}
}).start();
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
As #CommonsWare explained - inside onStartJob you'll decide if further work is required on a background thread. Only if that's the case, then you should call jobFinished from that background thread.
Just to answer your specific question - no condition tracking is required on your behalf. JobService will call onStopJob if the conditions you asked are no longer true.
Example of jobFinished can be found here:
https://medium.com/google-developers/scheduling-jobs-like-a-pro-with-jobscheduler-286ef8510129

Synchronized doesn't synchronize

I have a custom adapter that it's associated with a ListView in my MainActivity class and when I press on one of the items of the List (setOnItemClickListener method) I execute an AsyncTask to retrieve the info from the database and send it into a bundle.
Therefore, I have to wait until the AsyncTask finishes to send the info retrieved in the bundle.
For this purpose, I created an interface:
public interface OnCarListener {
void onCarCompleted(String c);
void onCarError(String error);
}
And I have my AsyncTask in another class:
class findCar extends AsyncTask<Integer, Integer, String> {
private final OnCarListener mListener;
public findCar(OnCarListener listener)
{
mListener = listener;
}
protected void onPreExecute() {
}
protected String doInBackground(Integer... idCar) {
String nameCar = "";
//Here the code to retrive the info
nameCar = obj.getString("name");
//Now nameCar = "Car1"
} catch (Exception ex) {
}
return nameCar;
}
protected void onProgressUpdate() {
}
protected void onPostExecute(String c) {
if (mListener != null) {
mListener.onCarCompleted(c);
}
}
}
And I execute my AsyncTask (in my MainActivity) as follows:
new findCar(new OnCarListener()
{
#Override
public void onCarCompleted(String c) {
synchronized (c)
{
name = c;
}
}
#Override
public void onCarError(String error) {
}
}).execute(idCar);
And after executing the AsyncTask I throw the bundle:
bundle.putString("name", name);
Note: I send more info with the bundle but I omitted it to simplify the question.
It should work in my opinion but in the first click in one element of the List the name isn't being passed by the bundle, just in the second and the rest of the clicks I made at the same or in the rest elements of the List, it works.
Expected result: AsyncTask will be executed and until it finishes the rest of the code shouldn't work. It is clear that it's not what it's doing right now.
What I want to know: Why the synchronized doesn't work in the first iteration? I mean, when I have the List and I click on one of the elements of the List the information of the element it's show (in another Activity) but the value name it's not shown.
If I go back and I do one or more clicks on the same element (or a different one) from the List, in all of them appears the value name correctly.
Why in the first iteration it doesn't work?
And I have another question: Why if I quit the synchronized as adelphus said in his answer, any of the times that I click on the elements of the List the value name appears?
I tried the solution in this question: synchronized not synchronizing but still doesn't work.
What could I do? (Without changing the logic of the program)
Thanks in advance!
I'm not sure you understand what synchronized does - it creates an exclusive lock on a given object to create ordered access to a section of code. When multiple threads attempt to enter a synchronized block (with the same lock object), only one thread will be allowed to continue into the block at a time.
In your code, you're synchronizing on the String parameter c. Since no other threads will be accessing this parameter, synchronized has no effect here.
Since your interface callback is being called on the UI thread (via onPostExecute()), you can just set the bundle value in the callback:
void amethod() {
final Bundle bundle = new Bundle();
new findCar(new OnCarListener()
{
#Override
public void onCarCompleted(String c) {
bundle.putString("name", c);
}
#Override
public void onCarError(String error) {
}
}).execute(idCar);
}

Call a method only once after 1 second from a method which get called 2-3 times

The below method onReceivedTitlegets called 2-3 times with in a second when webview url changes. I want to call a method in it, when onReceivedTitle is being called last time. I am doing this because I just want to monitor url changes with in webview. shouldOverrideUrlLoading is not getting called when url changes through ajax.
class MyWebChromeClient extends WebChromeClient {
#Override
public void onReceivedTitle(WebView view, String title) {
Log.v("onReceivedTitle", "=>" + title);
// callAMehod();
super.onReceivedTitle(view, title);
}
}
If you want to throttle how often a method call causes another method call you can do so for example via a Handler. The simplest version enqueues a delayed message on the first call and any subsequent call while there is an enqueued message will not enqueue a new one. That results in 1 call every X time to go though - but it take at least that amount of time until the first action happens.
Example implementation (you can put that class unmodified somewhere in your code)
public abstract class ThrottleExecutor {
private final long mMinDelay;
public ThrottleExecutor(long minDelay) {
mMinDelay = minDelay;
}
/** Implement to do something */
public abstract void doThrottled();
public final void scheduleExecution() {
if (mHandler.hasMessages(0)) {
// message already enqueued, do nothing
} else {
// otherwise enqueue a message for later
mHandler.sendEmptyMessageDelayed(0, mMinDelay);
}
}
public final void cancelExecution() {
mHandler.removeMessages(0);
}
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
doThrottled();
}
};
}
And then use it for example like so
class Usage {
private ThrottleExecutor mThrottle = new ThrottleExecutor(2000) {
#Override
public void doThrottled() {
// happens at most every 2000ms
methodToBeThrottled();
}
};
void methodThatHappensTooOften() {
mThrottle.scheduleExecution();
}
void methodToBeThrottled() {
Log.d("TAG", "triggered at 2000ms before");
}
}
You might want to use Handler and do something like this:
class MyWebChromeClient extends WebChromeClient {
private boolean mOnReceivedTitleInvoked;
#Override
public synchronized void onReceivedTitle(final WebView view, final String title) {
if (!mOnReceivedTitleInvoked) {
mOnReceivedTitleInvoked = true;
Log.v("onReceivedTitle", "=>" + title);
handler.postDelayed(new Runnable() {
#Override
public void run() {
super.onReceivedTitle(view, title);
mOnReceivedTitleInvoked = false;
}
}, 1000);
}
}
}
Although you might want to reconsider the onReceivedTitle behaviour.

Categories