2011-06-20 9 views
1

私は過去数時間にわたって私の頭を壁に打ち倒しているという奇妙な問題があります。チタンHTTPClientが実行される前に結果が使用されない

私はAppcelerator TitaniumのiPhoneアプリで作業しています。現在、他のコードが実行されてから、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関数に行き、その後、(次の2行)、それを残して、getMarkers機能(最初の行)に起こっていることを意味します(最後の4各マーカーとしてmarkers.lengthの出力が加えられる)。その

を知って、私はここで見つけるの回答に基づいて.onload()コール前から.open()呼び出しを移動し、私は.open()の前か後に.onload()であるかどうか、同じを取得します。

httpClient呼び出しが非同期にタスクを実行するという情報が見つかりました(API参照に欠けている重要な情報)。これを知っていると、それは機能を残しているのは理にかなっていますが、追加する前にダウンロードしたマーカーが必要なので、情報の処理方法には悩まされます。

iPhoneデベロッパーの同僚と話しているとき、彼はデリゲートとdelegate.connectionDidFinishLoadingコールを使用してそれらを処理すると述べました。おそらく、これにフックする方法か、これを使用できるチタニウムの実装がありますか?

アプリが実際にそれらをダウンロードする前にマーカーをロードしようとしないようにする良い方法がありますか?それはiPhoneのためだけに働く必要があるので、iPhone固有のオプションはうまくいきます。

答えて

1

多くの検索と髪の毛を引っ張った後、私は最終的にそれが必要な方法で動作するように管理しました。

.open()には、HTTPClientを強制的に実行させる第3のブール値のパラメータがあります(ドキュメントには記載されていない別の情報もあります)。 falseに設定すると、同期して実行されます。そうすることで、私は実行すると予想される順番でコードをテストすることができました。

また、すべてのマーカーの配列を作成して一度に読み込むことができないことがわかったので、addMarker()関数を1つのマーカーだけを取り、マーカーデータを取得するループ内で呼び出すように調整しました。一旦それが機能したら、HTTPClientを再び非同期に呼び出すことができました。

+0

私は正確に同じ問題をあなたの質問を見つけたことを追加したいと思います。 しかし、私はiPhoneとAndroidの両方を開発しています。Android(標準)では.open()の不思議な3番目のパラメータが動作しないことがわかりました。 – Cyntech

+1

ええ、それはTiについて私を挫折させた事の一つです。私たちのAndroidとiPhoneのプロジェクトは分かれています(もちろん、Tiを使う目的の半分を奪っています)。しかし、それらを統合することさえできません。サポートレベル。 – Shauna

0

Androidでは、特にネットワークアクティビティがUIスレッドから開始されたタスクは、SDK 2.3以降の非同期である必要があります。

関連する問題