-1

I have a method goToNextScreen() which does a check for 3 different asynchronous process, so when all process are done the validation will changes activity (Is kind of a Splash activity)

My example code access from 3 different result callbacks to the activity's method goToNextScreen() updating the flag value for each process and to validate other flags inside.

So far this approach works but i have the next questions:

Is this approach valid? Does it have a risk for some kind of deadlock? all threads/callbacks won't collide accessing the method at the same time causing wrong validations?

class LoadingActivity extends Activity{

  public boolean isFetchDone, isAnimationDone, isServiceDone, watchDog;

  Presenter presenter;

  protected void onCreate(@Nullable Bundle savedInstanceState) {

    presenter(this);
    runAnimation();
    presenter.runGetXService();
    runFetchFromDB();
  }

  //do some generic isAnimationDone
  private void runAnimation(){

    //animator set and animation assumed to be correct...
    //...

    animatorSet.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {
        // do anything before animation start
    }

    @Override
    public void onAnimationEnd(Animator animation) {
       isAnimationDone = true;
       goToNextScreen();
    }

    @Override
    public void onAnimationCancel(Animator animation) {
      // do something when animation is cancelled (by user/             developer)
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
       // do something when animation is repeating
    }
});
  }

//Some example function to fetch data from x DB
  private void runFetchFromDB() {
        final Realm realm = RealmProvider.getInstance();
        final ThingDB db = new ThingDBImpl(realm);

        realm.beginTransaction();

        db.getData(10L)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<XData>() {
                    @Override
                    public void onCompleted() {
                        isFetchDone = true;
                        goToNextScreen();
                    }

                    @Override
                    public void onError(Throwable e) {
                        //we dont care about the result
                        isFetchDone = true;
                        goToNextScreen();
                    }

                    @Override
                    public void onNext(XData dataSaved) {
                        //Should i update isFetchDone here?
                });

        realm.cancelTransaction();
    }

    private synchronized void goToNextScreen(){
      if(!watchDog) return;

      if(isFetchDone && isAnimationDone && isServiceDone){
        changeActivityFaded(this, SomeOtherActivity);
        finish();
        watchDog = true;
      }
    }
}

class Presenter {

  Activity activity;

  Presenter(Activity activity){
    this.activity = activity;
  }

  public void runGetXService(){
    new Presenter.GetServiceAsyncTask().execute();
  }

  private class GetServiceAsyncTask extends AsyncTask<Void, Void, Response> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            //do preparation for service response, etc, asumme all correct
        }

        @Override
        protected XResponse doInBackground(Void... voids) {
            try {
                return //Assume correct behaviour...
            } catch (NetworkConnectionException e) {
                return null;
            }
        }

        @Override
        protected void onPostExecute(XResponse xResponse) {
            super.onPostExecute(xResponse);
            ((LoadingActivity)activity).isServiceDone = true;
            ((LoadingActivity)activity).goToNextScreen();
        }
    }
}

EDIT:

I have changed the method goToNextScreen to synchronized so it supposed to not allow access from others threads at the same time. Still have doubts if withs the execution will be right.

Xaren
  • 491
  • 1
  • 4
  • 15

2 Answers2

1

Yes, making the method synchronized means it cannot be executed multiple times simultaneously. If a second thread calls it while it is still executing, the second thread will block until the synchronization lock is released.

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

nasch
  • 5,330
  • 6
  • 31
  • 52
  • Yes i think that the member goToNextScreen of the instance LoadingActivity which is current activity on screen will lock for different threads the access to that member. So far this approach has worked – Xaren May 31 '18 at 18:19
0

So far this approach by adding the synchronized to the method goToNextScreen member of the activity instance shared on the threads accessing it has worked so far. (View the question code for solution). Although i need to add a watch dog just in case some thread pass to execute code that its supposed to execute just once.

Xaren
  • 491
  • 1
  • 4
  • 15
  • Instead of all those variables you could use a CountDownLatch. https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html – nasch May 31 '18 at 19:00