AsyncTask和方向的变化

时间:2013-08-13 16:23:33

标签: android android-asynctask progressdialog screen-orientation

在更改屏幕方向时,重新创建活动,进度对话框和异步任务时出现问题。我在这里看到了一些解决方案,我决定使用onRetainCustomNonConfigurationInstance()来保存AsyncTask的实例。好吧,在onCreate中我检查是否有AsyncTask的实例,如果存在,我会显示一个新的进度对话框。但是这个对话框在无限循环中阻塞UI(在onPostExecute中有dialog.dismiss()),并且活动当然没有显示结果。

的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();
  }
}

编辑#1 : 我采用了具有Fragment和Retained Fragment的Kingfisher解决方案,但是当我在AsyncTask的doInBackground期间更改方向时,在Expandable Listview上有一个NPE。

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).

这里是片段中的代码:

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...]
    }

}

此处为活动中的代码:

 @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;

}

编辑#2 :我尝试了Kingfisher的新解决方案,但在doInBackground方法中总是有一个NPE。如果我在加载过程中没有更改屏幕的方向,应用程序不会崩溃并在列表视图上显示数据。

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)

这里是片段中的代码:

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;
    }

}

此处为活动中的代码:

@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...]



}

6 个答案:

答案 0 :(得分:2)

点击此链接:Handling Configuration Changes with Fragments或您可以使用AsyncTaskLoader。我建议使用Retained Fragment来处理配置更改。仔细阅读文章。 已编辑:请勿在{{1​​}}中致电callback.set。您应该在重新创建活动时找到doInBackground,并在Retained Fragment尝试使用onPost function {1}}获取获取列表结果的函数。

Retained Fragment

希望得到这个帮助。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

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

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

答案 3 :(得分:0)

我想出了一个相对简单的解决方案来解决这个问题。您可以使用持有者,该持有者可以参考您正在运行的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);
        }
    }
}

AsyncTask:

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);
    }
}

答案 4 :(得分:0)

我编写了相同的代码来解决这个问题

第一步是制作应用类:

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并从内存中删除。

对我来说足够了。

答案 5 :(得分:0)