简体   繁体   中英

How can I wait for an object filled asynchronously in Android UI thread without blocking it?

I have a singleton to handle the registration and elimination of an entity Profilo ( a Profile).

This entity is set by passing an identifier and gathering information on the server in an async way.

My problem is that when I have to return my instance of profilo if it's not still loaded it will return null.

public class AccountHandler {
    private static AccountHandler istanza = null;

    Context context;
    private boolean logged;
    private Profilo profilo;


    private AccountHandler(Context context) {
        this.context = context;
        //initialization
        //setting logged properly
            assignField(this.getName());
        }
    }

    public static AccountHandler getAccountHandler(Context context) {
        if (istanza == null) {
            synchronized (AccountHandler.class) {
                if (istanza == null) {
                    istanza = new AccountHandler(context);
                }
            }
        }
        return istanza;
    }

    public void setAccount(String nickname, String accessingCode) {
        logged = true;
        assignField(nickname);
    }

    //other methods

    private void assignField(String nickname) {
        ProfiloClient profiloClient = new ProfiloClient();
        profiloClient.addParam(Profilo.FIELDS[0], nickname);
        profiloClient.get(new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode,
                                  Header[] headers,
                                  JSONArray response) {
                JSONObject objson = null;
                try {
                    objson = (JSONObject) response.getJSONObject(0);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                AccountHandler accountHandler = AccountHandler.getAccountHandler(context);
    // Profilo is created with a JSONObject
    // **setProfilo is called in async**
                **accountHandler.setProfilo(new Profilo(objson));**
            }

        });
    }


    private void setProfilo(Profilo profilo) {
        this.profilo = profilo;
    }



    public Profilo getProfilo() {
        if( logged && profilo == null)
            //How can I wait that profilo is loaded by the JsonHttpResponseHandler before to return it

        return this.profilo;
    }


}

Instead of calling getProfilo you could use a callback mechanism in which the AccountHandler class notifies the caller when the profile has been loaded. eg

  public void setAccount(String nickname, String accessingCode, MyCallback cb) {
      assignField(nickname, cb);
  }
  private void assignField(String nickname, MyCallback cb) {
      ....
      accountHandler.setProfilo(new Profilo(objson));
      cb.onSuccess(this.profilo);
  }

Create an inner Interface MyCallback (rename it) in your AccountHandler class

public class AccountHandler {
    public interface MyCallback {
        void onSuccess(Profilo profile);
    }
}

Now whenever you call setAccount you will pass the callback and get notified when the profile is available eg

accountHandler.setAccount("Test", "Test", new AccountHandler.MyCallback() {
        void onSuccess(Profilio profile) {
            // do something with the profile
        }
    }

I added, as @Murat K. suggested, an interface to my Class that will provide a method to be call with the object when it is ready to be used.

   public class AccountHandler {

    public interface Callback {
            void profiloReady(Profilo profilo);
    }
}

This method is called in getProfilo in a Handler that makes recursive calls to getProfilo until profilo is ready to be used, then it call the callback method which class is passed as argument of getProfilo.

public void getProfilo(final Callback Callback) {
    if( logged && (profilo == null || !profilo.isReady() ) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                getProfilo(Callback);
            }
        }, 500);
    }else
        Callback.profiloReady(profilo);
}

Example of getProfilo call

public class ProfiloCall implements AccountHandler.MyCallback {

        @Override
        public void profiloReady(Profilo profilo) {
            //Use profilo as needed
            //EXECUTED ONLY WHEN PROFILO IS READY
        }


        public void callerMethod() {
            //useful code
            accountHandler.getProfilo(this);
            //other useful code

        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM