如何返回响应调用函数? (Android的应用程序通过调用Java的JSON REST的服务器)

2019-10-29 15:07发布

我重写一个Android应用程序的一些作品来调用一个REST服务器,我用Java编写的,使用Spring-Boot的框架。

总之,让我们在app说,函数A调用我MainController函数B(这是应该管理客户端服务器通信)。 函数B调用(有一些额外的步骤)叫我的服务器。 当函数B进行调用时,它使用一个匿名内部类中重写定义如何处理响应的方法。 我很难得到匿名内部类响应函数B,因此它可以被返回到可悲的是A.功能,一些asynchronity参与,只是为了让事情EXTA位更有趣。

我第一次尝试是使用一个唯一的ID存储调用结果的地图,使其内部类的外部访问。 工作还算不错的理论,但在asyncronity崩溃

第二,我直言不讳地补充说,应该等待结果被放置在地图继续之前的循环,确保有东西回来。

不知何故,没有正确执行循环(我相信),当我使用循环,调用我的服务器无法完成(其中它在没有环)

请看下面的代码

客户:MainController

class MainController
{
    private final AtomicLong counter;
    private final HashMap<Long, Object> callResults;

    public MainController(){
        counter = new AtomicLong();
        callResults  = new HashMap<>();
    }

    public Login getLoginByUsername(String username)
    {
        long callID = counter.incrementAndGet();
        System.out.println("Start call");
        ServerConnection.get("myURL",null, new JsonHttpResponseHandler(){
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response){
                try {
                    System.out.println("Call success, enter result:");
                    callResults.put(callID, new CallResult(Login.parseFromJson(response)));
                    System.out.println(callResults.get(callID));

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });

        System.out.println("start waiting");
       while(callResults.get(callID) == null){
            System.out.print(".");
        }
        System.out.println("waiting over, return result:");
        System.out.println(callResults.get(callID));
        //return (Login) callResults.remove(callID).content;
        return null;
    }
}

客户:一个ServerConnection

import com.loopj.android.http.*;
import cz.msebera.android.httpclient.HttpEntity;

public class ServerConnection {

    private static final String BASE_URL = "http://1.3.3.7:8080/";

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(String url, RequestParams params, JsonHttpResponseHandler responseHandler) {
        client.get(BASE_URL+url, params, responseHandler);
    }
}

这是我所知道的:

  1. 预期的响应会最终。 当我不使用循环等待,只是返回null,控制台将显示消息“呼叫成功,进入结果是:”和Object-ID

  2. 当使用while循环接近尾声,它永远不会打印“” - 这只是什么都不做。 我知道应用程序仍在运行,虽然,因为AndroidStudio不断更新我的空间分配

  3. 尝试应用观察者模式可能完全是超出范围。 我必须真正深入挖掘,我宁愿不碰客户端片面代码。 我提供的代码是不完全易于使用是诚实的

这是,我假设的问题是:循环可防止进行异步REST调用,从而不可能终止。

我的问题:A)我怎样才能返回登录,我的对象从服务器接收到调用摆在首位的MainController.getLoginByUsername功能的功能?

B)这是怎么回事与while循环我尝试使用等待? 为什么不会主体( print("."); )来执行,更重要的是,为什么它停止正在执行的REST调用形式/成品?

(也可随时离开我的回帖风格的反馈,这是我第一次问一个问题在这里)

编辑:问题补充B,可能会提供一个更简单的方法来找到一个快速解决方案

编辑更新:对不起,不使这不够清楚:需要我去适应调用函数以及任何建议(如观测器模式,如LivedataRxjava或由Leo Pelozo提供的,否则真的好建议)是不可行的。 我至少利奥Pelozos建议测试,和底层代码根本不允许。 我无法访问的参数,并且不能利用函数返回了。 我知道,返工底层系统是最好的行动过程中,但现在这是根本谈不上的范围...

Answer 1:

你用GSON由谷歌,它JSON对象转换为Java对象,它的语法很简单,你一定会喜欢它,我用它所有的时间。 我用凌空用于HTTP请求响应。 只要使用GSON像

GSON gson = new GSON();
LoginObject login = new LoginObject();
login=gson.fromJson(responce,LoginObject.class);

瞧你做。



Answer 2:

如果你不希望使用LivedataRxjava你可以重构这个方法接受一个JsonHttpResponseHandler或定制的回调,这是不漂亮,但它的工作原理:

1。

public void getLoginByUsername(String username, JsonHttpResponseHandler callback)
{
    long callID = counter.incrementAndGet();
    System.out.println("Start call");
    ServerConnection.get("myURL",null, callback);

}

然后调用它像这样:

getLoginByUsername("myUsername", new JsonHttpResponseHandler(){
        @Override
        public void onSuccess(int statusCode, Header[] headers, JSONObject response){
            try {
                Login myLogin = Login.parseFromJson(response);
                //do stuff

            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    });

要么

2。

class MainController {
    private final AtomicLong counter;
    private final HashMap<Long, Object> callResults;

    interface OnLogin{
        void onSuccessLogin(Login login);
    }

    public MainController() {
        counter = new AtomicLong();
        callResults = new HashMap<>();
    }

    public void getLoginByUsername(String username, OnLogin callback)
    {

        ServerConnection.get("myURL",null, new JsonHttpResponseHandler(){
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response){
                try {
                    Login loginObject = Login.parseFromJson(response);
                    callback.onSuccessLogin(loginObject);

                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        });

    }


}

你这样称呼它:

    MainController controller = new MainController();
    controller.getLoginByUsername("myUsername", new MainController.OnLogin() {
        @Override
        public void onSuccessLogin(Login login) {
            //do whatever here
        }
    });


Answer 3:

你可以用它来轻松实现这一目标CompletableFuture<?> 。 它的工作原理在JavaScript中的承诺与此类似。 如果您需要API等级24之前的兼容性,检查这里这个答案 。

所以,你的getLoginByUsername会是这个样子:

public CompletableFuture<Login> loginByUsername(String username) {
    CompletableFuture<Login> promise = new CompletableFuture<Login>();

    System.out.println("Start call");
    ServerConnection.get("myURL",null, new JsonHttpResponseHandler(){
        @Override
        public void onSuccess(int statusCode, Header[] headers, JSONObject response){
            try {
                System.out.println("Call success, enter result:");
                promise.complete(Login.parseFromJson(response));

            } catch (JSONException e) {
                promise.completeExceptionally(e);
            }
        }
    });

    return promise;
}

和你通话的网站是这样的:

Login login = loginByUsername("user").get();
// Or wait a maximum time
Login login = loginByUsername("user").get(30, TimeUnit.SECONDS);

不要调用get()在UIThread。 这将阻止用户界面,并为用户提供一个坏的经验



Answer 4:

感谢你的帮助! 我发现我的情况下有效的解决方案。

首先,这只是一个原型,我并不真的需要我的请求是异步的,所以我改变了ServerConnection使用SyncHttpClient代替:

public class ServerConnection {

    private static final String BASE_URL = "http://10.203.58.11:8080/";

    private static SyncHttpClient client = new SyncHttpClient();

    public static void get(String url, RequestParams params, JsonHttpResponseHandler responseHandler) {
        client.get(getAbsoluteUrl(url), params, responseHandler);
    }
}

然后,Android将不会允许我执行主线程上的请求。 这不是一个问题AsyncHttpClient ,作为异步部分是在它自己的线程来处理。 因此,我不得不线程添加到我的请求。 因此,我MainController现在看起来是这样的:

public class MainController
{
    private final AtomicLong counter;
    private final HashMap<Long, CallResult> callResults;

    public MainController(){
        counter = new AtomicLong();
        callResults  = new HashMap<>();
    }

public Login getLoginByUsername(String username)
    {
        long callID = counter.incrementAndGet();
        new Thread(new Runnable() {
            @Override
            public void run() {
                ServerConnection.get("person-login-relations?byUsername="+username,null, new JsonHttpResponseHandler(){
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, JSONObject response){
                        try {
                            callResults.put(callID, new CallResult(Login.parseFromJson(response)));
                            System.out.println(callResults.get(callID));

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });


            }
        })   .start();

        while(callResults.get(callID) == null){
            //wait
        }
        return (Login) callResults.remove(callID).content;
    }
}

我猜while循环我用现在等待的作品,因为它没有阻止这是负责执行和处理请求的线程。 不能完全肯定的,虽然。

诚然,这可能不是理想的解决方案,但它给我的具体语境是最可行的。

我几个月,我会负责返工我现在延伸到连接到客户端应用程序。 在这一点上我会确保实现大部分的您的建议! 所以,对任何人阅读此解决方案:这一权利这里是一个解决办法,因为我并不需要异步请求,我不应该改变调用你在这里看到的方法的功能! 我建议你还是看对方回复,因为它们在性质上是优异!



文章来源: How to return response to calling function? (Android-App calling Java REST-Server via JSON)