2012-03-10 16 views
0

私はユーザーの場所(MyLocationクラス)を検索する機能を持っています。ジオポイントを使用するかどうかは、AsyncTaskを実行してサーバーに接続し、サーバーのリストを取得します。リストが準備ができたら、ArrayList都市に保存します。 cities ArrayListがいっぱいになると、それが良い(構成の変更を証明する)ために保存されたいと思います。 CityItemはParcelableを実装しています。私はそれらをonSaveInstanceStateに保存し、それらをonCreateで取得します。設定変更後に変数への参照が失われました

これで、タスクが完了して都市リストがいっぱいになるとすべて正常に機能します。次に、デバイスを前後に回転させ、Log.i( "StartActivity"、 "都市リストをダウンロード:" cities.toString());呼び出される。

しかし、私はデバイスを回転させた場合geopointが見つかった前(またはタスク終了 - それは速く起こるので伝えるのは難しい)、その後、

public void gotCities(ArrayList<CityItem> _cities){ 

    cities = _cities; 
    Log.i("StartActivity", "gotCities("+cities.size()+"): "+cities.toString()); 
} 

が呼び出されます(と都市は完全に罰金ですログに)しかし、私はもう一度それを回転させるときArrayList都市は再びのように見えます。

設定が変更され、savedInstanceState.citiesがnullの場合、ArrayList都市は何とか再作成され、getCities()関数のものと同じArrayListではないようです。

私はそれが何か簡単だと確信していますが、私は何時間も答えを探していました。私はそれをやり遂げることはできません。

活動のコード:

public class StartActivity extends Activity { 

public static final String PREFS_NAME = "PrefsFile"; 

MyLocation myLocationObject = null; 
LatLngPoint point = null; 
ArrayList<CityItem> cities = null; 

FindCityTask task = null; 
Activity startActivity; 

@Override 
public void onCreate(Bundle savedInstanceState) { 

if(savedInstanceState!=null) if(savedInstanceState.containsKey("cities")) cities = savedInstanceState.getParcelableArrayList("cities"); if(cities!=null) Log.i("Cities retrieved", cities.toString()); 

    super.onCreate(savedInstanceState); 

    startActivity = this; 

     setContentView(R.layout.start); 

     //check if the configuration (orientation) has been changed 
     NonConfigurationObject nco = (NonConfigurationObject)getLastNonConfigurationInstance(); 
     if(nco!=null) if(nco.myLocationObject!=null) myLocationObject = nco.myLocationObject; 
     if(nco!=null) if(nco.task!=null) task = nco.task; 

     if(cities==null){ 

      Log.i("StartActivity", "Cities list is empty - retrieve them."); 

      if(myLocationObject==null){ 
       getGeopoint(); 
      } 
     } else { 
      Log.i("StartActivity", "Cities list downloaded:"+cities.toString()); 

    } 

} 

private void getGeopoint(){ 

    if(isOnline()){ //there is internet connection 


     if(myLocationObject==null){ 

      myLocationObject = new MyLocation(); 
      //calls function to check user location (returns false if no providers are enabled 
      if(!myLocationObject.getLocation(this, locationResult)){ /*TODO handle */Log.i("StartActivity", "Location providers disabled");} 

     } 


    } else { //not online - show msg 

     Log.i("StartActivity", "No internet connection"); 

    } 

} 


//waits for user geopoint. then starts FindCityTask 
LocationResult locationResult = new LocationResult(){ 
    @Override 
    public void gotLocation(final Location location){ 
     if(location!=null){ 

      // location found 
      Log.i("StartActivity", "Received location: "+location.toString()); 
      point = new LatLngPoint((float)location.getLatitude(), (float)location.getLongitude()); 

     } else { 

      // location not found 
      Log.i("StartActivity", "No location received after 20 seconds"); 
      point = null; 

     } 

     //RUN TASK to connect to server to get cities list (even if there's no geopoint) 
     task = new FindCityTask(startActivity); 
     task.execute(point); 

    } 
}; 

public void gotCities(ArrayList<CityItem> _cities){ 

    cities = _cities; 
    Log.i("StartActivity", "gotCities("+cities.size()+"): "+cities.toString()); 
} 

@Override 
public void onSaveInstanceState(Bundle savedInstanceState) { 
    super.onSaveInstanceState(savedInstanceState); 
    Log.i("onSaveInstanceState", "onSaveInstanceState"); 
    if(cities!=null) savedInstanceState.putParcelableArrayList("cities", cities); 
} 

@Override 
public NonConfigurationObject onRetainNonConfigurationInstance() { 

    NonConfigurationObject nco = new NonConfigurationObject(); 

    if(myLocationObject!=null){ 
     nco.myLocationObject = myLocationObject; 
    } 
    if(task!=null){ 
     nco.task = task; 
    } 

    return nco; 

} 

static class NonConfigurationObject{ 

    MyLocation myLocationObject; 
    FindCityTask task; 

} 

gotCities()メソッドは、AsyncTask onPostExecuteから呼び出される:方位cnangeがヒットすると、あなたの活動は、停止して破壊され、新たに作成され

@Override 
protected void onPostExecute(Void result) { 
    if(this.activity!=null){ 
     ((StartActivity) activity).gotCities(cities); 
    } 
} 

答えて

0

私はついにそれを手に入れました。これは、間違った(構成変更前の)アクティビティを指し示すAsyncTaskです。そのトリックは、アクティビティへの参照をタスクにアタッチすることです(そして、適切なタイミングで実行する)。

だから、まず最初に行うには、AsyncTaskでこれらの機能を置くことです:タスクが最初に呼び出されたときに

void attach(Activity activity){ 
    this.activity = activity; 
} 

void detach(){ 
    this.activity = null; 
} 

我々はそれに活動を添付しなければなりません。 次に、onRetainNonConfigurationInstance()をデタッチします。

@Override  
public NonConfigurationObject onRetainNonConfigurationInstance() { 

    //normally it would return only the task, but i have to return another object 
    //hence the NonConfigurationObject which holds reference to both the AsyncTask and MyLocation 
    //(as seen in the original question) 

    NonConfigurationObject nco = new NonConfigurationObject(); 

    if(task!=null){ 
     task.detach(); 
     nco.task = task; 
    } 

    return nco; 

} 

最後に、onCreate()でgetLastNonConfigurationInstance()を呼び出すと、再び添付します。

 //check if the configuration (orientation) has been changed 
     NonConfigurationObject nco = (NonConfigurationObject)getLastNonConfigurationInstance(); 

     if(nco!=null){ //not created for the first time 

      Log.i("StartActivity", "NCO: "+nco.toString()); 
      task = nco.task; 
      if(task!=null){ //nco can be present but task still null 
       task.attach(this); 
      } else { 
       task = new FindCityTask(this); 
      } 

     } else { 
      Log.i("StartActivity", "NCO: null"); 
      task = new FindCityTask(this); 
     } 

お持ちの場合は、この解決策に関するご意見をお寄せください。私は問題をよりよく適合させるように質問を修正します。それが呼び出されるよう

0

、およびコールされることが保証されているコールバックだけがonPause()です。同じことが、スクリーンロックが蹴られたときに起こります - あなたの活動をポートレートモードに強制します。

androidアクティビティのライフサイクルについてお読みください。親指のルールがある:あなたの活動が上に来て、ユーザー

  • onPauseに提示されようとしているとき

    • のonCreate()は、インタフェースオブジェクトおよびサービス
    • onResume()が呼び出されたのinitalizingためである()ときそれは焦点を失い、もはや使用するために提示されません。

    ロケーションの取得には時間がかかるため、必要に応じてonCreate()で起動し、アクティビティからライフサイクルを切り離してください。サービスはブロードキャストメッセージまたはJavaメソッド呼び出しを使用して結果をアクティビティに渡すことができます。

    あなたのonSaveInstanceState()を調べます。まずsuper.onSaveInstanceState()を呼び出してから、データを組み込むようにバンドルを変更します。こうして彼らは決して救われません。

  • +0

    は、しかし、私はonSaveInstanceStateからのコールバックを持っています。位置の取得はTimerTaskに移動されます(MyLocationはこれを処理し、geopointをlocationResultに送信します)。私はちょうど1秒前に解決策を見つけましたが、大丈夫かどうか疑問に思います。 –

    +1

    静的フィールドはOKです。アプリのJVMと同じくらい長く存続し、アクティビティのライフサイクルの影響を受けません。 –

    +0

    ありがとうございます。しかし、私はまだ何かが欠けていると感じています。都市の変数が単に漏れてしまったのではないかと心配しています。私はどこでそれを起こさせたのだろうか。 –

    関連する問題