2012-03-10 6 views
0

사용자 위치 (MyLocation 클래스)를 찾는 acitivty가 있고 geopoint가 있거나없는 경우 AsyncTask를 실행하여 서버에 연결하고 내 서버에서 도시 목록을 가져옵니다. 목록이 준비되면 ArrayList 도시에 저장할 수 있습니다. 일단 도시 ArrayList가 채워지면 (배열 변경에 대한 증명) 좋은 결과를 위해 저장되기를 바랍니다. CityItem은 Parcelable을 구현합니다. onSaveInstanceState에 저장하고 onCreate에서 검색합니다.구성 변경 후 변수에 대한 참조가 손실되었습니다.

이제 작업이 완료되고 도시 목록이 채워지면 모든 것이 올바르게 작동합니다. 그런 다음 장치를 앞뒤로 돌리고 Log.i ("StartActivity", "도시 목록 다운로드 :"+ cities.toString()); 호출됩니다. 다음,

public void gotCities(ArrayList<CityItem> _cities){ 

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

가 호출되는 (과 도시 완벽하게 괜찮 - GeoPoint의이을 발견 (하드가 빨리 발생하기 때문에 말하거나 작업 완료) 전에

그러나 나는 장치 를 회전하는 경우 로그에서)하지만 다시 한 번 회전하면 ArrayList 도시가 다시 null로 나타납니다.

구성이 변경되고 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에서 호출됩니다

@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

방향 cnange 히트가, 당신의 활동이 정지 파괴하고 새롭게 만들어지고되면 호출 할 수있는 콜백 만 onPause()입니다. 화면 잠금이 시작될 때도 마찬가지입니다. 세로 모드에서 활동을 시작합니다.

android activity lifecycle에 대해 읽어 보시기 바랍니다. 엄지 손가락의 규칙은 다음과 같습니다 활동이 상단에 제공되며 사용자

  • onPause에 제출하려 할 때

    • 에서 onCreate()가 인터페이스 객체와 서비스
    • onResume()가 호출을 initalizing입니다() 할 때 초점을 잃어 더 이상 사용할 수 없습니다.

    위치를 얻는 데 시간이 오래 걸리므로 작업에서 백그라운드 서비스로 이동하는 것이 좋습니다 (필요한 경우 onCreate()에서 시작). 활동에서 라이프 사이클을 분리합니다. 서비스는 브로드 캐스트 메시지 또는 Java 메소드 호출을 통해 결과에 작업을 전달할 수 있습니다.

    onSaveInstanceState()를 살펴보면 먼저 super.onSaveInstanceState()를 호출하고 데이터를 포함하도록 번들을 수정합니다. 이런 식으로 그들은 결코 구원받지 못합니다.

  • +0

    하지만 onSaveInstanceState의 콜백이 있으므로 호출됩니다. 위치 획득은 TimerTask로 이동합니다 (MyLocation이이를 처리하고 geopoint를 locationResult로 보냅니다). 나는 잠깐 전에 해결책을 찾았지만 괜찮은지 궁금해. –

    +1

    정적 필드는 정상입니다. 앱 JVM만큼 오래 지속되며 활동 라이프 사이클의 영향을받지 않습니다. –

    +0

    감사합니다. 그러나 나는 아직도 내가 뭔가를 놓치고 있다고 느낍니다. 나는 도시 변수가 단순히 유출되었다고 걱정한다. 그리고 나는 그것이 어디에서 일어 났는지 궁금해. –

    관련 문제