Доступ к Android Тот же метод экземпляра для активности из разных потоков без блокировки.Добавлен синхронизированный метод - PullRequest
0 голосов
/ 28 мая 2018

У меня есть метод goToNextScreen(), который выполняет проверку для 3 различных асинхронных процессов, поэтому, когда все процессы завершены, проверка изменит активность (является видом действия Splash)

Мой пример доступа к коду из3 различных результата обратного вызова метода действия goToNextScreen (), обновляющего значение флага для каждого процесса и проверяющего другие флаги внутри.

Пока этот подход работает, но у меня есть следующие вопросы:

Естьэтот подход действителен?Есть ли риск какого-то тупика?все потоки / обратные вызовы не будут сталкиваться при доступе к методу одновременно, вызывая неправильные проверки?

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();
        }
    }
}

РЕДАКТИРОВАТЬ:

Я изменил метод goToNextScreensynchronized, поэтому он не должен разрешать доступ другим потокам одновременно.Все еще сомневаюсь, что с исполнением будет правильно.

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Пока что этот подход, добавив синхронизированный к методу goToNextScreen член экземпляра действия, совместно используемый в потоках, обращающихся к нему, до сих пор работал.(Посмотреть код вопроса для решения).Хотя мне нужно добавить сторожевую собаку на случай, если какой-нибудь поток пройдет для выполнения кода, который должен выполняться только один раз.

0 голосов
/ 30 мая 2018

Да, синхронизация метода означает, что он не может быть выполнен несколько раз одновременно.Если второй поток вызывает его во время выполнения, второй поток будет блокироваться до тех пор, пока не будет снята блокировка синхронизации.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...