2

I've problem with the re-creation of the activity, the progress dialog and the Async Task when change the orientation of the screen. I saw some solutions here and i decided to use the onRetainCustomNonConfigurationInstance() to save the instance of AsyncTask. Well, in onCreate i check if there is an instance of AsyncTask and, if exist, i show a new Progress Dialog. But this dialog blocks the UI in an infinite loop (in the onPostExecute there is dialog.dismiss() ) and the activity doesn't show the results of course.

onCreate

getDirection = (GetDirection) getLastCustomNonConfigurationInstance();
if(getDirection != null) {
  dialog = new ProgressDialog(RouteActivity.this);
  dialog.setMessage(getResources().getString(R.string.loading_data));
  dialog.setIndeterminate(false);
  dialog.setCancelable(false);
  dialog.show();
} else {
  getDirection = new GetDirection();
  getDirection.execute();
}

onRetainCustomNonConfigurationInstance

@Override
public Object onRetainCustomNonConfigurationInstance() {
  return getDirection;
}

@Override
protected void onDestroy() {
  super.onDestroy();
  if (dialog.isShowing()) {
    dialog.dismiss();
  }
}

EDIT #1: I adopted the solution of Kingfisher with Fragment and Retained Fragment but there is a NPE on Expandable Listview when i change the orientation during the doInBackground of AsyncTask.

08-14 12:50:40.866: E/AndroidRuntime(22739): FATAL EXCEPTION: main
08-14 12:50:40.866: E/AndroidRuntime(22739): java.lang.NullPointerException
08-14 12:50:40.866: E/AndroidRuntime(22739):    at com.pasquini.adapter.ListRouteExpandableAdapter.getGroupCount(ListRouteExpandableAdapter.java:78)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.widget.ExpandableListConnector.getCount(ExpandableListConnector.java:399)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.widget.ListView.setAdapter(ListView.java:460)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.widget.ExpandableListView.setAdapter(ExpandableListView.java:470)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at com.pasquini.activity.RouteActivity.onPostExecute(RouteActivity.java:792)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:244)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:1)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.os.AsyncTask.finish(AsyncTask.java:631)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.os.AsyncTask.access$600(AsyncTask.java:177)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.os.Looper.loop(Looper.java:137)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at android.app.ActivityThread.main(ActivityThread.java:4895)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at java.lang.reflect.Method.invokeNative(Native Method)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at java.lang.reflect.Method.invoke(Method.java:511)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
08-14 12:50:40.866: E/AndroidRuntime(22739):    at dalvik.system.NativeStart.main(Native Method).

Here the code in Fragment:

public class GetDirectionFragment extends Fragment {

private Map<Leg, List<Step>> legsCollection;
private ArrayList<Object> legsAndSteps;
private List<Leg> legs;
private List<Poi> pois;
private List<LatLng> polyz;

/**
   * Callback interface through which the fragment will report the
   * task's progress and results back to the Activity.
   */
  public static interface TaskCallbacks {
    void onPreExecute();
    void onPostExecute();
    List<Poi> getListPoiByRoute();
    void setLegs(List<Leg> legs, Map<Leg, List<Step>> legsCollection);
    void setPolyline(List<LatLng> polyz);

  }

  private TaskCallbacks callbacks;
  private GetDirectionTask getDirectionTask;

  /**
   * Hold a reference to the parent Activity so we can report the
   * task's current progress and results. The Android framework 
   * will pass us a reference to the newly created Activity after 
   * each configuration change.
   */
  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        callbacks = (TaskCallbacks) activity;
    } catch(ClassCastException e) {
        throw new ClassCastException(activity.toString() + " must implement TaskCallbacks");
    }
    pois = callbacks.getListPoiByRoute();
  }

  /**
   * This method will only be called once when the retained
   * Fragment is first created.
   */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Retain this fragment across configuration changes.
    setRetainInstance(true);

    // Create and execute the background task.
    getDirectionTask = new GetDirectionTask();
    getDirectionTask.execute();
  }

  /**
   * Set the callback to null so we don't accidentally leak the 
   * Activity instance.
   */
  @Override
  public void onDetach() {
    super.onDetach();
    callbacks = null;
  }

  private class GetDirectionTask extends AsyncTask<Void, Integer, Void> {

        @Override
        protected void onPreExecute() {
          if (callbacks != null) {
              callbacks.onPreExecute();
          }
        }

        /**
         * Note that we do NOT call the callback object's methods
         * directly from the background thread, as this could result 
         * in a race condition.
         */
        @Override
        protected Void doInBackground(Void... ignore) {
                List<String> lats = new ArrayList<String>();
                List<String> longs = new ArrayList<String>();

                for(Poi poi: pois) {
                    lats.add(poi.getCoordinates().getLatitude());
                    longs.add(poi.getCoordinates().getLongitude());
                }

                String stringUrl = "http://maps.googleapis.com/maps/api/directions/" +
                        "json?";
                //if(actualLanguage.equals("en")) {
                //  stringUrl += "language=en_EN";
                //} else {
                    stringUrl += "language=it";
                //}
                stringUrl+="&mode=walking&units=metric&origin=" +
                         lats.get(0) + "," +
                         longs.get(0);

                stringUrl += "&destination=" +
                        lats.get(pois.size()-1) + "," +
                        longs.get(pois.size()-1) + "&" +
                        "waypoints=";


                for(int i = 1; i<=lats.size()-2 && i<=longs.size()-2; i++) {
                    stringUrl += lats.get(i)+","+longs.get(i);
                    if(i==(lats.size()-2) && i==(longs.size()-2)) {
                        stringUrl += "&sensor=false";
                    } else {
                        stringUrl +="|";
                    }
                }

                Log.i("urlgoogle", stringUrl);

                StringBuilder response = new StringBuilder();
                try {
                    URL url = new URL(stringUrl);
                    HttpURLConnection httpconn = (HttpURLConnection) url
                            .openConnection();
                    if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        BufferedReader input = new BufferedReader(
                                new InputStreamReader(httpconn.getInputStream()),
                                8192);
                        String strLine = null;

                        while ((strLine = input.readLine()) != null) {
                            response.append(strLine);
                        }
                        input.close();
                    }

                    String jsonOutput = response.toString();

                    JSONObject jsonObject = new JSONObject(jsonOutput);


                    // routesArray contains ALL routes
                    JSONArray routesArray = jsonObject.getJSONArray("routes");
                    // Grab the first route
                    JSONObject route = routesArray.getJSONObject(0);

                    JSONArray legsArray = route.getJSONArray("legs");
                    legs = new ArrayList<Leg>();
                    legsAndSteps = new ArrayList<Object>();
                    String htmlInstructions;

                    legsCollection = new LinkedHashMap<Leg, List<Step>>();

                    for(int i=0; i<legsArray.length(); i++) {
                        List<Step> steps = new ArrayList<Step>();
                        Leg leg = new Leg();
                        //int idLeg = 0;
                        JSONObject legJson = legsArray.getJSONObject(i);
                        leg.setDistance(legJson.getJSONObject("distance").getString("text"));
                        leg.setDuration(legJson.getJSONObject("duration").getString("text"));
                        leg.setEndAddress(legJson.getString("end_address"));
                        leg.setStartAddress(legJson.getString("start_address"));
                        leg.setIdLeg(pois.get(i).getId());
                        leg.setStartPoiName(pois.get(i).getName());
                        leg.setEndPoiName(pois.get(i+1).getName());

                        legsAndSteps.add(leg);

                        JSONArray stepsArray = legJson.getJSONArray("steps");
                        for(int j=0; j<stepsArray.length(); j++) {
                            Step step = new Step();
                            JSONObject stepJson = stepsArray.getJSONObject(j);
                            step.setDistance(stepJson.getJSONObject("distance").getString("text"));
                            step.setDuration(stepJson.getJSONObject("duration").getString("text"));
                            htmlInstructions = android.text.Html.fromHtml(stepJson.getString("html_instructions")).toString();
                            step.setInstructions(htmlInstructions);
                            //step.setIdLeg(idLeg);

                            //Aggiunto per Exp
                            steps.add(step);

                            legsAndSteps.add(step);

                        }
                        legsCollection.put(leg, steps);


                        legs.add(leg);
                    }



                    JSONObject poly = route.getJSONObject("overview_polyline");
                    String polyline = poly.getString("points");
                    polyz = decodePoly(polyline);

                    callbacks.setLegs(legs, legsCollection);
                    callbacks.setPolyline(polyz);

                } catch (Exception e) {

                }

          return null;
        }



        @Override
        protected void onPostExecute(Void ignore) {
          if (callbacks != null) {
              callbacks.onPostExecute();
          }
        }
      }

  /* Method to decode polyline points */
    private List<LatLng> decodePoly(String encoded) {

        [code...]
    }

}

Here the code in Activity:

 @Override
public void onPostExecute() {


     expListView = (ExpandableListView) findViewById(R.id.lv_routepoi);
     ListRouteExpandableAdapter expListAdapter = new ListRouteExpandableAdapter(
             getApplicationContext(), legs, legsCollection);
     expListView.setAdapter(expListAdapter);

     setGroupIndicatorToRight();
     expListView.setChildDivider(getResources().getDrawable(R.drawable.divider_route));

    [code...]

    dialog.dismiss();


}

@Override
public void setLegs(List<Leg> legs, Map<Leg, List<Step>> legsCollection) {
    this.legs = legs;
    this.legsCollection = legsCollection;


}

@Override
public void setPolyline(List<LatLng> polyz) {
    this.polyz = polyz;

}

EDIT #2: I tried the new solution of Kingfisher but there is always an NPE in doInBackground method. If i don't change the orientation of screen during the loading, app doesn't crash and show data on listview.

08-14 17:27:44.897: I/AsyncTask(30604): java.lang.NullPointerException
08-14 17:27:44.897: E/AndroidRuntime(30604): FATAL EXCEPTION: main
08-14 17:27:44.897: E/AndroidRuntime(30604): java.lang.NullPointerException
08-14 17:27:44.897: E/AndroidRuntime(30604):    at com.pasquini.activity.RouteActivity.onPostExecute(RouteActivity.java:847)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:253)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:1)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at android.os.AsyncTask.finish(AsyncTask.java:631)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at android.os.AsyncTask.access$600(AsyncTask.java:177)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at android.os.Looper.loop(Looper.java:137)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at android.app.ActivityThread.main(ActivityThread.java:4895)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at java.lang.reflect.Method.invokeNative(Native Method)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at java.lang.reflect.Method.invoke(Method.java:511)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
08-14 17:27:44.897: E/AndroidRuntime(30604):    at dalvik.system.NativeStart.main(Native Method)

Here the code in Fragment:

public class GetDirectionFragment extends Fragment {

private Map<Leg, List<Step>> legsCollection;
private ArrayList<Object> legsAndSteps;
private List<Leg> legs;
private List<Poi> pois;
private List<LatLng> polyz;

/**
   * Callback interface through which the fragment will report the
   * task's progress and results back to the Activity.
   */
  public static interface TaskCallbacks {
    void onPreExecute();
    void onPostExecute();
    List<Poi> getListPoiByRoute();
    void setLegs(List<Leg> legs, Map<Leg, List<Step>> legsCollection);
    void setPolyline(List<LatLng> polyz);

  }

  private TaskCallbacks callbacks;
  private GetDirectionTask getDirectionTask;

  /**
   * Hold a reference to the parent Activity so we can report the
   * task's current progress and results. The Android framework 
   * will pass us a reference to the newly created Activity after 
   * each configuration change.
   */
  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        callbacks = (TaskCallbacks) activity;
    } catch(ClassCastException e) {
        throw new ClassCastException(activity.toString() + " must implement TaskCallbacks");
    }
    pois = callbacks.getListPoiByRoute();
  }

  /**
   * This method will only be called once when the retained
   * Fragment is first created.
   */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Retain this fragment across configuration changes.
    setRetainInstance(true);

    // Create and execute the background task.
    getDirectionTask = new GetDirectionTask();
    getDirectionTask.execute();
  }

  /**
   * Set the callback to null so we don't accidentally leak the 
   * Activity instance.
   */
  @Override
  public void onDetach() {
    super.onDetach();
    callbacks = null;
  }

  private class GetDirectionTask extends AsyncTask<Void, Integer, Void> {

        @Override
        protected void onPreExecute() {
          if (callbacks != null) {
              callbacks.onPreExecute();
          }
        }

        /**
         * Note that we do NOT call the callback object's methods
         * directly from the background thread, as this could result 
         * in a race condition.
         */
        @Override
        protected Void doInBackground(Void... ignore) {
                List<String> lats = new ArrayList<String>();
                List<String> longs = new ArrayList<String>();

                for(Poi poi: pois) {
                    lats.add(poi.getCoordinates().getLatitude());
                    longs.add(poi.getCoordinates().getLongitude());
                }

                String stringUrl = "http://maps.googleapis.com/maps/api/directions/" +
                        "json?";
                //if(actualLanguage.equals("en")) {
                //  stringUrl += "language=en_EN";
                //} else {
                    stringUrl += "language=it";
                //}
                stringUrl+="&mode=walking&units=metric&origin=" +
                         lats.get(0) + "," +
                         longs.get(0);

                stringUrl += "&destination=" +
                        lats.get(pois.size()-1) + "," +
                        longs.get(pois.size()-1) + "&" +
                        "waypoints=";


                for(int i = 1; i<=lats.size()-2 && i<=longs.size()-2; i++) {
                    stringUrl += lats.get(i)+","+longs.get(i);
                    if(i==(lats.size()-2) && i==(longs.size()-2)) {
                        stringUrl += "&sensor=false";
                    } else {
                        stringUrl +="|";
                    }
                }

                Log.i("urlgoogle", stringUrl);

                StringBuilder response = new StringBuilder();
                try {
                    URL url = new URL(stringUrl);
                    HttpURLConnection httpconn = (HttpURLConnection) url
                            .openConnection();
                    if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        BufferedReader input = new BufferedReader(
                                new InputStreamReader(httpconn.getInputStream()),
                                8192);
                        String strLine = null;

                        while ((strLine = input.readLine()) != null) {
                            response.append(strLine);
                        }
                        input.close();
                    }

                    String jsonOutput = response.toString();

                    JSONObject jsonObject = new JSONObject(jsonOutput);


                    // routesArray contains ALL routes
                    JSONArray routesArray = jsonObject.getJSONArray("routes");
                    // Grab the first route
                    JSONObject route = routesArray.getJSONObject(0);

                    JSONArray legsArray = route.getJSONArray("legs");
                    legs = new ArrayList<Leg>();
                    legsAndSteps = new ArrayList<Object>();
                    String htmlInstructions;

                    legsCollection = new LinkedHashMap<Leg, List<Step>>();

                    for(int i=0; i<legsArray.length(); i++) {
                        List<Step> steps = new ArrayList<Step>();
                        Leg leg = new Leg();
                        //int idLeg = 0;
                        JSONObject legJson = legsArray.getJSONObject(i);
                        leg.setDistance(legJson.getJSONObject("distance").getString("text"));
                        leg.setDuration(legJson.getJSONObject("duration").getString("text"));
                        leg.setEndAddress(legJson.getString("end_address"));
                        leg.setStartAddress(legJson.getString("start_address"));
                        leg.setIdLeg(pois.get(i).getId());
                        leg.setStartPoiName(pois.get(i).getName());
                        leg.setEndPoiName(pois.get(i+1).getName());

                        legsAndSteps.add(leg);

                        JSONArray stepsArray = legJson.getJSONArray("steps");
                        for(int j=0; j<stepsArray.length(); j++) {
                            Step step = new Step();
                            JSONObject stepJson = stepsArray.getJSONObject(j);
                            step.setDistance(stepJson.getJSONObject("distance").getString("text"));
                            step.setDuration(stepJson.getJSONObject("duration").getString("text"));
                            htmlInstructions = android.text.Html.fromHtml(stepJson.getString("html_instructions")).toString();
                            step.setInstructions(htmlInstructions);
                            //step.setIdLeg(idLeg);

                            steps.add(step);

                            legsAndSteps.add(step);

                        }
                        legsCollection.put(leg, steps);


                        legs.add(leg);
                    }



                    JSONObject poly = route.getJSONObject("overview_polyline");
                    String polyline = poly.getString("points");
                    polyz = decodePoly(polyline);

                    setLegs(legs, legsCollection);
                    setPolyline(polyz);

                } catch (Exception e) {
                            Log.i(TAG, e.toString());
                }

          return null;
        }



        @Override
        protected void onPostExecute(Void ignore) {
          if (callbacks != null) {
              callbacks.onPostExecute();
          }
        }
      }

  /* Method to decode polyline points */
    private List<LatLng> decodePoly(String encoded) {

        [code...]
    }

public void setLegs(List<Leg> legs, Map<Leg, List<Step>> legsCollection) {
            this.legs = legs;
            this.legsCollection = legsCollection;
        }

    public void setPolyline(List<LatLng> polyz) {
        this.polyz = polyz;

    }

    public List<Leg> getLegs() {
        return this.legs;
    }

    public Map<Leg, List<Step>> getMap() {
        return this.legsCollection;
    }

    public List<LatLng> getPolyline() {
        return this.polyz;
    }

}

Here the code in Activity:

@Override
    protected void onCreate(Bundle savedInstanceState) {
               [code...]
           FragmentManager fm = getSupportFragmentManager();
           getDirectionFragment = (GetDirectionFragment) fm.findFragmentByTag(TASK_FRAGMENT_TAG);

            // If the Fragment is non-null, then it is currently being
            // retained across a configuration change.
            if (getDirectionFragment == null) {
                getDirectionFragment = new GetDirectionFragment();
                fm.beginTransaction().add(getDirectionFragment, TASK_FRAGMENT_TAG).commit();

         [code...]
            }

 @Override
public void onPostExecute() {

           legs = getDirectionFragment.getLegs();
    legsCollection = getDirectionFragment.getMap();
    polyz = getDirectionFragment.getPolyline();

     expListView = (ExpandableListView) findViewById(R.id.lv_routepoi);
     ListRouteExpandableAdapter expListAdapter = new ListRouteExpandableAdapter(
             getApplicationContext(), legs, legsCollection);
     expListView.setAdapter(expListAdapter);

     setGroupIndicatorToRight();
     expListView.setChildDivider(getResources().getDrawable(R.drawable.divider_route));

    [code...]



}
4

5 回答 5

2

检查此链接:使用片段处理配置更改,或者您可以使用AsyncTaskLoader。我建议使用它Retained Fragment来处理配置更改。仔细阅读文章。 已编辑:不要在 中调用callback.set函数。doInBackground您应该找到Retained Fragment重新创建活动的时间,并onPost function尝试使用Retained Fragment'get 函数来获取列表结果。

//Activity recreated
FragmentManager fm = getFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag("task");

//onPost method
yourList = mTaskFragment.getLegsAndMoveList();
// Do lisview data changing here

希望这有帮助。

于 2013-08-13T17:00:40.253 回答
0

在清单文件中的标记活动中使用android:configChanges="keyboardHidden|orientation|screenSize"。这会导致活动不再以改变方向运行,您不需要保存任何数据

于 2013-08-13T16:32:29.133 回答
0

您永远不会更新异步任务中的对话框,以便它会关闭新的对话框(因此看似无限循环,但实际上只是阻塞了 UI,没有循环)。

当您保存状态并重新加载时,您需要将该对话框更新为新对话框,以便dismiss() 将关闭正确的对话框。

只需向您的任务添加一个 setDialog() 方法,然后在 onCreate() 中使用新对话框调用它。

还有一件事,您可能需要考虑在设置新对话框并显示它之前添加一个检查以查看 AsyncTask 是否完成。它有可能在您更改方向之后但在 onCreate() 之前完成,在这种情况下,您的 UI 将被阻止。这在 onCreate 中是安全的,因为 onPostExecute 和 onCreate 都在同一个线程(UI 线程)上运行。

于 2013-08-13T17:04:17.227 回答
0

我写了samepl代码来解决这个问题

第一步是制作应用程序类:

public class TheApp extends Application {

private static TheApp sTheApp;
private HashMap<String, AsyncTask<?,?,?>> tasks = new HashMap<String, AsyncTask<?,?,?>>();

@Override
public void onCreate() {
    super.onCreate();
    sTheApp = this;
}

public static TheApp get() {
    return sTheApp;
}

public void registerTask(String tag, AsyncTask<?,?,?> task) {
    tasks.put(tag, task);
}

public void unregisterTask(String tag) {
    tasks.remove(tag);
}

public AsyncTask<?,?,?> getTask(String tag) {
    return tasks.get(tag);
}
}

在 AndroidManifest.xml 中

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name="com.example.tasktest.TheApp">

活动代码:

public class MainActivity extends Activity {

private Task1 mTask1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mTask1 = (Task1)TheApp.get().getTask("task1");

}

/*
 * start task is not running jet
 */
public void handletask1(View v) {
    if (mTask1 == null) {
        mTask1 = new Task1();
        TheApp.get().registerTask("task1", mTask1);
        mTask1.execute();
    } else
        Toast.makeText(this, "Task is running...", Toast.LENGTH_SHORT).show();

}

/*
 * cancel task if is not finished
 */
public void handelCancel(View v) {
    if (mTask1 != null)
        mTask1.cancel(false);
}

public class Task1 extends AsyncTask<Void, Void, Void>{

    @Override
    protected Void doInBackground(Void... params) {
        try {
            for(int i=0; i<120; i++) {
                Thread.sleep(1000);
                Log.i("tests", "loop=" + i);
                if (this.isCancelled()) {
                    Log.e("tests", "tssk cancelled");
                    break;
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onCancelled(Void result) {
        TheApp.get().unregisterTask("task1");
        mTask1 = null;
    }

    @Override
    protected void onPostExecute(Void result) {
        TheApp.get().unregisterTask("task1");
        mTask1 = null;
    }
}

}

当活动方向改变时,变量 mTask 是从应用程序上下文中初始化的。当任务完成时,变量设置为 null 并从内存中删除。

对我来说已经足够了。

于 2013-12-03T20:37:59.150 回答
0

我想出了一个相对简单的解决方案来解决这个问题。你可以使用一个 Holder 来引用你正在运行的 AsyncTask。

活动:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            FragmentTransaction transaction = getFragmentManager().beginTransaction();
            transaction.add(R.id.container, new MainFragment());
            transaction.commit();
        }
    }
}

片段:

public class MainFragment extends Fragment implements View.OnClickListener, SampleAsyncTask.Callback {


    private Button mExecuteButton;
    private ProgressDialog mProgressDialog;


    @Override
    public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_main, container, false);

        mExecuteButton = (Button) view.findViewById(R.id.execute_button);
        mExecuteButton.setOnClickListener(this);

        SampleAsyncTask asyncTask = SampleAsyncTask.Holder.Instance.get();
        asyncTask.setCallback(this);

        if (asyncTask.isRunning()) {
            showProgressDialog(asyncTask.getProgress());
        }

        return view;
    }


    @Override
    public void onDetach () {

        SampleAsyncTask asyncTask = SampleAsyncTask.Holder.Instance.get();
        if (asyncTask.isRunning()) {
            asyncTask.setCallback(null);
        }

        if (mProgressDialog != null) {
            mProgressDialog.dismiss();
            mProgressDialog = null;
        }

        super.onDetach();
    }


    private void showProgressDialog (int progress) {

        mProgressDialog = new ProgressDialog(getActivity());
        mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        mProgressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "Cancel", makeNegativeButtonListener());
        mProgressDialog.setCancelable(false);
        mProgressDialog.setProgress(progress);
        mProgressDialog.setMax(100);

        mProgressDialog.show();
    }


    private DialogInterface.OnClickListener makeNegativeButtonListener () {

        DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {

            @Override
            public void onClick (DialogInterface dialog, int which) {

                SampleAsyncTask asyncTask = SampleAsyncTask.Holder.Instance.get();
                if (asyncTask.isRunning()) {
                    asyncTask.cancel(true);
                    mProgressDialog.dismiss();
                }
            }
        };

        return listener;
    }


    @Override
    public void onClick (View v) {

        SampleAsyncTask asyncTask = SampleAsyncTask.Holder.Instance.get();
        asyncTask.setCallback(this);

        if (!asyncTask.isRunning()) {
            showProgressDialog(0);
            asyncTask.execute(100, 200);
        }
    }


    // SampleAsyncTask.Callback implementation


    @Override
    public void onPostExecute (boolean success) {

        String message = (success) ? "SUCCESS" : "FAIL";
        Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show();

        mProgressDialog.dismiss();
    }


    @Override
    public void onProgressUpdate (int progressValue) {

        if (mProgressDialog != null) {
            mProgressDialog.setProgress(progressValue);
        }
    }
}

异步任务:

public class SampleAsyncTask extends AsyncTask<Integer, Integer, Boolean> {


    public static final String LOG_TAG = SampleAsyncTask.class.getSimpleName();

    private static final Callback LOG_CALLBACK = new Callback() {

        @Override
        public void onPostExecute (boolean success) {
            Log.i(LOG_TAG, "#onPostExecute (" + success + ")");
        }


        @Override
        public void onProgressUpdate (int progressValue) {
            Log.i(LOG_TAG, "#onProgressUpdate(" + progressValue + ")");
        }
    };

    private boolean mRunning = false;
    private int mProgress = -1;
    private Callback mCallback = LOG_CALLBACK;


    public void setCallback (Callback callback) {

        if (callback == null) {
            mCallback = LOG_CALLBACK;
        }
        else {
            mCallback = callback;
        }
    }


    public boolean isRunning () {

        return mRunning;
    }


    public int getProgress () {

        return mProgress;
    }


    @Override
    protected Boolean doInBackground (Integer... params) {

        mRunning = true;

        for (int i = 0; i < params[0]; i++) {

            if (isCancelled()) {
                return false;
            }

            try {
                Thread.sleep(params[1]);
                mProgress = i;
                publishProgress(i);
            }
            catch (InterruptedException e) {
                return false;
            }
        }

        return true;
    }


    @Override
    protected void onPostExecute (Boolean success) {

        mRunning = false;
        Holder.Instance.reset();

        mCallback.onPostExecute(success);
    }


    @Override
    protected void onProgressUpdate (Integer... values) {

        mCallback.onProgressUpdate(values[0]);
    }


    @Override
    protected void onCancelled (Boolean aBoolean) {

        mRunning = false;
        Holder.Instance.reset();
    }


    @Override
    protected void onCancelled () {

        mRunning = false;
        Holder.Instance.reset();
    }


    public enum Holder {

        Instance;
        private SampleAsyncTask mSampleAsyncTask;


        public SampleAsyncTask get () {

            if (mSampleAsyncTask == null) {
                mSampleAsyncTask = new SampleAsyncTask();
            }

            return mSampleAsyncTask;
        }


        private void reset () {

            mSampleAsyncTask = null;
        }
    }

    public interface Callback {

        public void onPostExecute (boolean success);
        public void onProgressUpdate (int progressValue);
    }
}
于 2013-11-16T12:18:08.240 回答