0

我有一个查找用户位置(MyLocation 类)的活动,然后使用或不使用地理点运行 AsyncTask 以连接到服务器并从我的服务器获取城市列表。当列表准备好时,它将它们保存在 ArrayList 城市中。一旦城市 ArrayList 被填满,我希望它被保存好(证明配置更改)。CityItem 实现 Parcelable。我将它们保存在 onSaveInstanceState 中并在 onCreate 中检索它们。

现在,如果任务已完成且城市列表已填满,则一切正常。然后我来回旋转我的设备和 Log.i("StartActivity", "Cities list added:"+cities.toString()); 被调用。

但是,如果我在找到地理点之前旋转设备(或任务完成 - 很难说,因为它发生得很快),那么

public void gotCities(ArrayList<CityItem> _cities){

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

被调用(并且城市在日志中非常好)但是当我再次旋转它时ArrayList 城市似乎再次为空

看来,如果配置更改并且 savedInstanceState.cities 为空,则 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;

}

从 AsyncTask onPostExecute 调用 gotCities() 方法:

@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(),然后修改 bundle 以包含您的数据。这样他们永远不会得救。

于 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 回答