【问题标题】:How can I wait for an object filled asynchronously in Android UI thread without blocking it?如何等待在 Android UI 线程中异步填充的对象而不阻塞它?
【发布时间】:2018-01-11 10:12:49
【问题描述】:

我有一个单例来处理实体 Profilo (a Profile) 的注册和消除。

通过传递标识符并以异步方式在服务器上收集信息来设置此实体。

我的问题是,当我必须返回我的 profilo 实例时,如果它尚未加载,它将返回 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;
    }


}

【问题讨论】:

    标签: android multithreading asynchronous android-asynctask


    【解决方案1】:

    您可以使用回调机制代替调用getProfilo,在该机制中AccountHandler 类会在配置文件已加载时通知调用者。例如

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

    AccountHandler 类中创建一个内部接口MyCallback(重命名)

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

    现在,无论何时拨打setAccount,您都会通过回调并在配置文件可用时收到通知,例如

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

    【讨论】:

    • 谢谢,我没有用这个完全解决方案来解决,因为我需要让 getProfilo 返回一些东西。但是我已经接受了接口的想法,并将方法 onSucces(我称之为 profiloReady)放在递归处理程序中的 getProfilo 方法中。
    【解决方案2】:

    正如@Murat K. 建议的那样,我添加了一个接口到我的类,它将提供一个方法,以便在对象准备好使用时调用它。

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

    该方法在 getProfilo 中的 Handler 中调用,该 Handler 递归调用 getProfilo,直到 profilo 准备好使用,然后它调用回调方法,该类作为 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);
    }
    

    getProfilo 调用示例

    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
    
            }
        }
    

    【讨论】:

    • 这不好。因为如果用户按下它,它仍然会发布可运行文件。再次返回应用程序时将创建一个新的处理程序。所以你现在有两个处理程序。因为您没有通过handler.removeCallback(runnable) 删除回调或在onDestroy 中设置handler =null。您肯定会得到NPE。
    • @Bishoy Abd 如果我检查 if(myCallback == null) { return; } 会怎样
    猜你喜欢
    • 1970-01-01
    • 2019-09-24
    • 2016-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    相关资源
    最近更新 更多