Титаниум HTTPClient не работает до использования результатов - PullRequest
1 голос
/ 20 июня 2011

У меня странная проблема: я в течение последних нескольких часов вбивал голову в стену.

Я работаю над приложением для iPhone в Appcelerator Titanium, и в настоящее время оно хочет подождатьпока другой код не будет запущен до получения результатов нескольких запросов HTTPClient, несмотря на то, что я вызываю их, прежде чем пытаюсь использовать их результаты. Сначала вызывается

function getMarkers(e, miles){ //The function with the HTTPClient calls that are firing last, trimmed to have only the relevant code.

    var markers = [];
    Ti.API.info("Getting markers");
    xhr.onload = function()
    {
        var data = Ti.XML.parseString(this.responseText);

        var ref = data.documentElement.getElementsByTagName("reference");

        for(var i =0; i < ref.length; i++){
            var marker = new Object();
            marker.ref = ref.item(i).text;

            var request = Titanium.Network.createHTTPClient();
            request.setTimeout(10000);

            request.onload = function(){
                var data = Ti.XML.parseString(this.responseText);
                marker.address = data.documentElement.getElementsByTagName("formatted_address").item(0).text;

                if(data.documentElement.getElementsByTagName("formatted_phone_number") != null){
                    marker.phone = data.documentElement.getElementsByTagName("formatted_phone_number").item(0).text;
                } else {
                    marker.phone = null;
                }
                marker.icon = data.documentElement.getElementsByTagName("icon").item(0).text;
                marker.lat = data.documentElement.getElementsByTagName("lat").item(0).text;
                marker.lng = data.documentElement.getElementsByTagName("lng").item(0).text;
                marker.name = data.documentElement.getElementsByTagName("name").item(0).text;
                if(data.documentElement.getElementsByTagName("url") != null) {
                    marker.url = data.documentElement.getElementsByTagName("url").item(0).text;
                } else {
                    marker.url = null;
                }

                markers.push(marker);
                Ti.API.info(markers.length);
            }

            request.open("GET","https://maps.googleapis.com/maps/api/place/details/xml?reference=" + marker.ref + "&sensor=true&key=" + Ti.App.apiKey);

            request.send();
        }
    };

    xhr.open("GET","https://maps.googleapis.com/maps/api/place/search/xml?location=" + googleLatLng + "&radius=" + radius + "&types=" + Ti.App.types + "&sensor=true&key=" + Ti.App.apiKey);
    xhr.send();
    return markers;
}

// actually draw the markers on the map
function drawMap(markers, currentLoc)
{
    var i;

    Ti.API.info("Adding markers...");
    for(i=0;i<markers.length;i++)
    {
        Ti.API.info("Marker " + i);
        Ti.API.info(markers[i].name);
        var ann = Titanium.Map.createAnnotation({
            image:markers[i].icon,
            animate:true,
            latitude:markers[i].lat,
            longitude:markers[i].lng,
            title:markers[i].name,
            subtitle:markers[i].address
        });

        if(markers[i].url != null){
            ann.rightButton = markers[i].url;
        }
        mapview.addAnnotation(ann);
    }
    Ti.API.info("Markers added"); //When this block is called, markers.length == 0
}

// find the user's location and mark it on the map
function waitForLocation(e)
{
   //Do stuff about finding current location and marking it on the map. This stuff works and a pin drops for the current location

    drawMap(getMarkers(e), currentLoc);

}

waitForLocation, который затемназывает остальных.Xcode выводит следующее:

[INFO] Getting markers
[INFO] Adding markers...
[INFO] Markers added
[INFO] 1
[INFO] 2
[INFO] 3
[INFO] 4

Это означает, что он входит в функцию getMarkers (первая строка), затем покидает ее (следующие две строки), затем возвращается к функции getMarkers для фактического получения маркеров (последние четыре строки, вывод markers.length при добавлении каждого маркера).Зная, что

я переместил вызов .open() до вызова .onload(), основываясь на ответе, найденном здесь, но я получаю то же самое, независимо от того, находится .open() до или после .onload().

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

Говоря с моим коллегой по разработке для iPhone, он упомянул, что обрабатывает их, используя делегат и вызов Delegate.connectionDidFinishLoading.Может быть, есть ли способ подключиться к этому, или реализация Titanium, которую я мог бы использовать?

Есть ли еще один хороший способ убедиться, что он не пытается загрузить маркеры раньше?приложение фактически загрузило их?Он должен работать только на iPhone, поэтому параметры, подходящие для iPhone, подойдут.

Ответы [ 2 ]

1 голос
/ 22 июня 2011

После долгих поисков и стягивания волос мне, наконец, удалось заставить его работать так, как мне нужно.

.open() имеет третий, логический параметр, который заставляет HTTPClient работать синхронно (еще один лакомый кусочек, не упомянутый в документации). Установка false сделает его синхронным. Это позволило мне протестировать код в том порядке, в котором он ожидался.

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

0 голосов
/ 16 апреля 2012

В Android любая задача, запущенная из потока пользовательского интерфейса, особенно активность сети, должна быть асинхронной с SDK 2.3 и выше.

...