执行Async Task任务后,变量会丢失数据

时间:2012-10-24 16:28:08

标签: java android multithreading garbage-collection android-asynctask

我有一个AsyncTask子类的活动。执行异步任务后,我丢失了所有变量。我在调试模式下单步执行代码。只要“MyAsync()。execute()”完成“formatedURL”变量(以及所有其他变量)都没有值。在此之前,他们有正确的价值观。然后,由于一些奇怪的原因,他们失去了价值。我是在做一个简单的OO错误,还是垃圾收集做了我不知道的事情。

public class NearbyList extends Activity {

    double lat;
    double lng;
    String restName;
    GPSHandling gps;
    String formatedURL;
    JSONObject jobject;
    ArrayList<HashMap<String, String>> listOfHM;
    ArrayList<String> listOfValues;
    String currentName;
    ListView lv;
    Context context;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nearby_places_list);

        context = getApplicationContext();
        gps = new GPSHandling(this);
        lat = gps.getMyLatitude();
        lng = gps.getMyLongitude();
        restName ="";
        formatedURL = GooglePlacesStuff.placesURL(lat, lng, 16000, "food", restName, true);  //make a proper url. next step is to get a JSON object from this.


        new MyAsync().execute();// in order to run networking it must not be done in the UIthread. I use async task to take care of this in order to 
           //reduce the code of doing complex threading since this is a simple calculation
    }
        class MyAsync extends AsyncTask<Void, Integer, Boolean>{
            @Override
            protected Boolean doInBackground(Void... params) {
                try {
                    jobject = GooglePlacesStuff.getTheJSON(formatedURL);
                    listOfHM = JSONextractor.getJSONHMArrayL(jobject);
                    // iterate through and get the names of the nearby restaurants from the array of hasmap strings
                    for(int i =0 ; i < listOfHM.size() ;i++ ){
                        currentName = listOfHM.get(i).get(JSONextractor.TAG_NAME);
                        listOfValues.add(currentName);
                    }
                    return true;
                } catch (Exception e){
                    Log.e("Nearby List Activity", "exception", e);
                    return false;}
            }

            @Override
            protected void onPostExecute(Boolean result){
                super.onPostExecute(result);
                if (result){
                    ListAdapter adapter = new SimpleAdapter(context, listOfHM, R.layout.nearby_places_list, new String[]{JSONextractor.TAG_NAME,
                            JSONextractor.TAG_VICINITY, JSONextractor.TAG_GEO_LOC_LAT}, new int[]{ R.id.name, R.id.vicinity, R.id.phone});

                    // adding data to listview
                    lv.setAdapter(adapter);
                } else{
                    Toast.makeText(getApplicationContext(), "Need Internet & GPS access for this to work", Toast.LENGTH_LONG).show();
                }
                gps.stopUsingGPS();  // stop using the gps after i get the list to save on resource
            }
        }
}

EDIT1: 看起来它试图在doinbackground()方法中多次运行“super.onCreate(Bundle savedInstanceState)”

Edit2:如果我将值设为静态,它们不会丢失。它很奇怪,甚至在异步任务中分配的变量“jobject”也不会进行赋值,除非它是一个静态变量....从未见过这样的东西

3 个答案:

答案 0 :(得分:2)

当你说他们没有值时,你是否在AsyncTask中检查它们?如果是这样,这可能是原因(来自AsyncTask):

  

记忆可观察性

     

AsyncTask保证所有回调调用的同步方式使得以下操作在没有显式同步的情况下是安全的。

     
      
  • 在构造函数或onPreExecute()中设置成员字段,并在doInBackground(Params ...)中引用它们。
  •   
  • 在doInBackground(Params ...)中设置成员字段,并在onProgressUpdate(Progress ...)和onPostExecute(Result)中引用它们。
  •   

基本上,您不应该从doInBackground()访问实例变量,因为它不是线程安全的。就像函数说的那样,它在一个单独的(后台)线程中运行。您可以通过使它们静态(您尝试过)或同步它们来解决它,但最好按照预期的方式使用AsyncTask。

所以我认为你应该做到以下几点:

  1. 将formatedURL作为参数传递给AsyncTask

  2. 返回ArrayList&lt; HashMap&lt; String,String&gt;&gt;来自doInBackground()(listOfHM)

  3. 使用传入的ArrayList&lt; HashMap&lt; String,String&gt;&gt;在onPostExecute()

  4. 我还要在onCreate中设置ListAdapter,只需更新支持ListAdapter onPostExecute()的数据。但我不会在这里讨论,因为它可能是一个单独的问题。这个是可选的。

  5. 代码:

    class MyAsync extends AsyncTask<String, Integer, ArrayList<HashMap<String, String>>> {
        @Override
        protected ArrayList<HashMap<String, String>> doInBackground(String... urls) {
            ArrayList<HashMap<String, String>> listOfHM = null;
            if (urls != null && urls.length > 0 && urls[0] != null) {
                String formattedUrl = urls[0];
                try {
                    JSONObject jobject = GooglePlacesStuff.getTheJSON(formattedURL);
                    listOfHM = JSONextractor.getJSONHMArrayL(jobject);
                } catch (Exception e) {
                    // log error
                }
            }
            return listOfHM;
        }
    
        @Override
        protected void onPostExecute(ArrayList<HashMap<String, String>> listOfHM){
            if (listOfHM != null && !listOfHM.isEmpty()) {
                // iterate through and get the names of the nearby restaurants from the array of hasmap strings
                for(int i =0 ; i < listOfHM.size() ;i++ ){
                    String currentName = listOfHM.get(i).get(JSONextractor.TAG_NAME);
                    listOfValues.add(currentName);
                }
                // do your adapter stuff
            }
            gps.stopUsingGPS();  // stop using the gps after i get the list to save on resource
        }
    }
    

    在你的onCreate()中你会做

    new MyAsync(formattedUrl).execute();
    

    希望它有所帮助!

答案 1 :(得分:0)

尝试分离功能和职责,在异步类中创建构造函数并将活动作为参数传递,就像维护线程中的上下文以避免任何内存泄漏一样,在活动中定义一些函数来使使用活动中的“生活”数据执行后执行任务(定义适配器,将适配器分配给列表视图,停止gps使用等),并在onpostexecute中调用mActiviy.doAfterTaskFinish()。关键在于分离责任,这可以帮助您找到问题出错的地方。

答案 2 :(得分:0)

事实证明,我问了一个关于我的申请中实际上没有发生的事情的问题。显然,当你使用Async Task类时,on create方法中的所有变量以及onPostExecute()和doInBackground()中的所有变量(几乎文件中的所有变量)都不会显示值(除非你使它们静止)即使它们确实有值,而你正在踩踏这些方法。我不知道为什么会这样。我太依赖于使用调试器来检查我的变量是什么。对不起,感到困惑。