Lambda表达式返回空Android [英] Lambda expression returning null android

查看:83
本文介绍了Lambda表达式返回空Android的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个lambda表达式,以将给定的经度和纬度转换为地址.该表达式应该以坐标为参数并返回其对应的地址.但是,返回的值为null.以下是我的课程:

I'm writing a lambda expression to convert the given latitude and longitude into an address. The expression is supposed to take co-ordinates as arguments and returns their corresponding address. However, the value returned is null. Following is my class:

public class LambdaDeclarations {

String loc;

private static final String TAG = "LambdaDeclarations";

public CoordinatesToAddressInterface convert = (latitude, longitude, context) -> {
    RequestQueue queue = Volley.newRequestQueue(context);

    Log.d(TAG, "onCreate: Requesting: Lat: "+latitude+" Lon: "+longitude);
    String url ="https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins="+latitude+","+longitude+"&destinations="+latitude+","+longitude+"&key=AIzaSyCdKSW0glin4h9sGYa_3hj0L83zI0NsNRo";
    // Request a string response from the provided URL.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            (String response) -> {
                try {
                    JSONObject jsonObject = new JSONObject(response);
                    JSONArray destinations = jsonObject.getJSONArray("destination_addresses");
                    Log.d(TAG, "GETRequest: JSON Object: "+destinations.toString());
                    String location = destinations.toString();
                    Log.d(TAG, "Location: "+location);
                    setLocation(location);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }, error -> Log.d(TAG, "onErrorResponse: That didn't work!"));
    queue.add(stringRequest);
    return getLocation();
};


public String getLocation() {
    return loc;
}

public void setLocation(String location) {
    this.loc = location;
    }
}

以下是logcat的输出:

Following is the output from logcat:

09-16 10:31:09.160 26525-26525/com.rmit.tejas.mad_foodtruck_2 D/LambdaDeclarations: GETRequest: JSON Object: ["77 State Route 32, West Melbourne VIC 3003, Australia"]
Location: ["77 State Route 32, West Melbourne VIC 3003, Australia"]
09-16 10:31:09.176 26525-26525/com.rmit.tejas.mad_foodtruck_2 D/LambdaDeclarations: GETRequest: JSON Object: ["111 Adderley St, West Melbourne VIC 3003, Australia"]
Location: ["111 Adderley St, West Melbourne VIC 3003, Australia"]
09-16 10:31:09.177 26525-26525/com.rmit.tejas.mad_foodtruck_2 D/LambdaDeclarations: GETRequest: JSON Object: ["4\/326 William St, Melbourne VIC 3000, Australia"]
Location: ["4\/326 William St, Melbourne VIC 3000, Australia"]

以下是我的用法:

myViewHolder.textView3.setText("Location: i->"+i+" add: "+l.convert.toAddress(trackingInfos.get(i).getLatitude(),trackingInfos.get(i).getLongitude(),context));

l LambdaDeclarations 类的对象,下面是相关的接口:

l is an object of the class LambdaDeclarations and following is the relevant interface:

public interface CoordinatesToAddressInterface {
String toAddress(double latitude, double longitude, Context context);
}

当我尝试从相关适配器打印坐标时,它们将正确打印.因此,位置设置正确,但是当我尝试从另一个类访问它时,它显示了字符串的空值.您能否建议使用另一种方法从表达式中提取位置?

When I try to print the coordinates from the relevant adapter they are getting printed correctly. So the location is getting set properly but when I try to access it from another class it shows me a null value for the string. Can you please advise an alternate method to extract the location from the expression?

推荐答案

首先, Lambda Expression 只是一个匿名类实现,它被设计为用作方法或类参数并解决匿名类的影子问题.
因此,就您而言,根本就不需要它,只需像往常一样简单地将 CoordinatesToAddressInterface 接口实现为命名类即可.

First of all, Lambda Expression is just a anonymous class implementation, it was design to be used as a method or class argument and solve shadowing issues of anonymous class.
So in your case, you don't need it at all, just simply implement CoordinatesToAddressInterface interface as named class as usual.

第二,您使用Volley错误,您提供给 StringRequest 的第一个lambda,此后将是调用响应回调,将在HTTP请求完成但返回语句

Second, you used Volley wrong, the first lambda you provided to StringRequest, hereafter will be call response callback, is going to be called when HTTP request finish but the return statement

return getLocation();

将立即在您的 setLocation(location)甚至您的响应回调执行之前返回null,这就是为什么每次调用 convert()时都会得到null的原因.您仍然可以看到打印的日志,因为无论如何都会执行响应回调(假设请求成功).

will return null immediately before your setLocation(location) or even your response callback ever get executed, that why you got null every time you call convert(), though you can still see log that you print because the response callback will be executed anyway (assume that request is success).

要正确使用响应回调,您必须在回调内部更新UI,就像这样

To use response callback correctly, you have to update your UI inside callback, pretty much like this

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
public static final String TAG = "MyAdapter";
private RequestQueue mQueue;

public MyAdapter(Context context) {
    this.mQueue = Volley.newRequestQueue(context);
}

public RequestQueue getMyAdapterRequestQueue() {
    return this.mQueue;
}

    ...

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
    String url ="some url";

    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            (String response) -> {
                try {
                    JSONObject jsonObject = new JSONObject(response);
                    JSONArray destinations = jsonObject.getJSONArray("destination_addresses");
                    Log.d(TAG, "GETRequest: JSON Object: "+destinations.toString());
                    String location = destinations.toString();
                    Log.d(TAG, "Location: "+location);
                    // update UI
                    holder.mTextView.setText(location);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }, error -> Log.d(TAG, "onErrorResponse: That didn't work!"));

    stringRequest.setTag(TAG);
    mQueue.add(stringRequest);
}

当然,您可以编辑接口的方法签名,并使适配器实现该接口(不过,我宁愿采用这种方式),但要点是您必须在回调方法中处理异步结果,永远不要期望异步操作的回调要在下一行代码之前完成.

Of course, you can edit your interface's method signature and make your adapter implement that interface (I would rather do it this way though) but the point is that you have to process asynchronous results in callback method, never expect asynchronous operation's callback to finish before your next lines of code.

RequestQueue 不应按请求创建,因为它管理内部状态,可帮助您更快地进行请求(缓存),在电话旋转等事件中也可以取消请求,这样您就可以在这种情况下,只需在Activity/Fragment的 onStop()

RequestQueue shouldn't be created per-request since it manages internal state that help you make request faster (caching), you can also cancel requests too in an event like phone rotation and your will get destroy, in this case, just call cancel method in Activity/Fragment's onStop()

@Override
protected void onStop () {
    super.onStop();
    if (myAdapter.getMyAdapterRequestQueue() != null) {
        myAdapter.getMyAdapterRequestQueue().cancelAll(MyAdapter.TAG);
    }
}

取消请求后,不会调用响应回调.

Response callback won't be called after you cancel request.

这篇关于Lambda表达式返回空Android的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆