Лямбда-выражение, возвращающее ноль андроида - PullRequest
0 голосов
/ 16 сентября 2018

Я пишу лямбда-выражение для преобразования заданной широты и долготы в адрес.Предполагается, что выражение принимает координаты в качестве аргументов и возвращает их соответствующий адрес.Однако возвращаемое значение равно нулю.Ниже приведен мой класс:

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:

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 и соответствующий интерфейс:

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

Когда я пытаюсь распечатать координаты из соответствующего адаптера, они печатаются правильно.Таким образом, местоположение устанавливается правильно, но когда я пытаюсь получить доступ к нему из другого класса, оно показывает мне нулевое значение для строки.Не могли бы вы посоветовать альтернативный метод для извлечения местоположения из выражения?

1 Ответ

0 голосов
/ 17 сентября 2018

Прежде всего, Лямбда-выражение - это просто реализация анонимного класса, она была спроектирована для использования в качестве аргумента метода или класса и для решения проблем теневого копирования анонимного класса.
Так что в вашем случае,вам это вообще не нужно, просто просто реализуйте интерфейс CoordinatesToAddressInterface как именованный класс, как обычно.

Во-вторых, вы неправильно использовали Volley, первая лямбда, указанная вами для StringRequest, далее будет обратным вызовом ответа на вызов, будет вызываться после завершения HTTP-запроса, но оператор возврата

return getLocation();

вернет ноль непосредственно перед тем, как ваш setLocation(location) или даже ваш ответный обратный вызов когда-либо будет выполнен, поэтому вы получаете нулевое значение каждый раз, когда вызываете convert(), хотя вы все равно можете видеть журнал, который вы печатаете, потому что ответный обратный вызов все равно будет выполнен(предположим, что запрос успешен).

Чтобы правильно использовать ответный обратный вызов, вы должны обновить свой пользовательский интерфейс внутри обратного вызова, примерно так:

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

Конечно, вы можете отредактировать сигнатуру метода вашего интерфейса и заставить свой адаптер реализовать этоинтерфейс (хотя я бы предпочел сделать это таким образом), но дело в том, что вы должны обрабатывать асинхронные результаты в методе обратного вызова, никогда не ожидайте, что обратный вызов асинхронной операции завершится до ваших следующих строк кода.

RequestQueue не следует создавать для каждого запроса, так как он управляет внутренним состоянием, которое помогает вам ускорить выполнение запроса (кэширование), вы также можете отменить запросы и в случае, например, ротации телефона, и в этом случае вы получите уничтожение,просто вызовите метод отмены в Activity / Fragment onStop()

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

Ответный обратный вызов не будет вызван после отмены запроса.

...