我重写一个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);
}
}
这是我所知道的:
预期的响应会最终。 当我不使用循环等待,只是返回null,控制台将显示消息“呼叫成功,进入结果是:”和Object-ID
当使用while循环接近尾声,它永远不会打印“” - 这只是什么都不做。 我知道应用程序仍在运行,虽然,因为AndroidStudio不断更新我的空间分配
尝试应用观察者模式可能完全是超出范围。 我必须真正深入挖掘,我宁愿不碰客户端片面代码。 我提供的代码是不完全易于使用是诚实的
这是,我假设的问题是:循环可防止进行异步REST调用,从而不可能终止。
我的问题:A)我怎样才能返回登录,我的对象从服务器接收到调用摆在首位的MainController.getLoginByUsername功能的功能?
B)这是怎么回事与while循环我尝试使用等待? 为什么不会主体( print(".");
)来执行,更重要的是,为什么它停止正在执行的REST调用形式/成品?
(也可随时离开我的回帖风格的反馈,这是我第一次问一个问题在这里)
编辑:问题补充B,可能会提供一个更简单的方法来找到一个快速解决方案
编辑更新:对不起,不使这不够清楚:需要我去适应调用函数以及任何建议(如观测器模式,如Livedata
或Rxjava
或由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:
如果你不希望使用Livedata
或Rxjava
你可以重构这个方法接受一个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)