0

ユーザーの場所 (MyLocation クラス) を検索するアクティビティがあり、ジオポイントの有無にかかわらず、AsyncTask を実行してサーバーに接続し、サーバーから都市のリストを取得します。リストの準備ができたら、それらを ArrayList の都市に保存します。都市のArrayListがいっぱいになったら、それを永久に保存したいと思います(構成変更の証拠)。CityItem は Parcelable を実装しています。それらを onSaveInstanceState に保存し、onCreate で取得します。

これで、タスクが完了し、都市リストが満たされていれば、すべて正常に機能します。次に、デバイスを前後に回転させ、Log.i("StartActivity", "Cities list Download:"+cities.toString()); 呼ばれます。

しかし、ジオポイントが見つかる前にデバイスを回転させた場合(またはタスクが終了した場合 - 高速に発生するためわかりにくい)、

public void gotCities(ArrayList<CityItem> _cities){

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

が呼び出されます (そして都市はログで完全に問題ありません) が、もう一度ローテーションするとArrayList の都市が再び null のように見えます

構成が変更され、savedInstanceState.cities が null だった場合、ArrayList の都市が何らかの形で再度作成され、gotCities() 関数内のものと同じ 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);   
    }
}
4

2 に答える 2

0

方向変更がヒットすると、アクティビティは停止され、破棄され、新たに作成されます。呼び出されることが保証されている唯一のコールバックは onPause() です。画面ロックが開始された場合も同じことが起こります。これにより、アクティビティが強制的に縦向きモードになります。

Android アクティビティのライフサイクルについて読むことをお勧めします。経験則は次のとおりです。

  • onCreate() は、インターフェイス オブジェクトとサービスを初期化するためのものです。
  • onResume() は、アクティビティが一番上に来て、ユーザーに提示されようとしているときに呼び出されます
  • onPause() は、フォーカスを失い、もはや使用するために提示されていない場合。

位置情報の取得には時間がかかるため、位置情報をアクティビティからバックグラウンド サービスに移動し (必要に応じて onCreate() で開始)、そのライフサイクルをアクティビティから分離することをお勧めします。サービスは、ブロードキャスト メッセージまたは Java メソッド呼び出しを介してアクティビティに結果を渡すことができます

そして onSaveInstanceState() を調べます。最初に super.onSaveInstanceState() を呼び出してから、バンドルを変更してデータを含めます。このようにして、彼らは決して救われません。

于 2012-03-10T13:01:56.867 に答える
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);
        }

もしあれば、この解決策についてあなたの考えを共有してください。質問を修正して、問題により適したものにします。

于 2012-03-10T21:58:02.907 に答える