Android 异步任务与方向的变化

Android 异步任务与方向的变化,android,android-asynctask,progressdialog,screen-orientation,Android,Android Asynctask,Progressdialog,Screen Orientation,在更改屏幕方向时,我遇到了重新创建活动、进度对话框和异步任务的问题。我在这里看到了一些解决方案,并决定使用onRetainStatonConfiguration()保存AsyncTask的实例。在onCreate中,我检查是否有AsyncTask的实例,如果存在,我将显示一个新的进度对话框。但是这个对话框将UI阻塞在无限循环中(在onPostExecute中有dialog.disease()),当然活动不会显示结果 onCreate getDirection=(getDirection)getL

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

onCreate

getDirection=(getDirection)getLastCustomNonConfigurationInstance();
if(getDirection!=null){
dialog=新建ProgressDialog(RouteActivity.this);
setMessage(getResources().getString(R.string.loading_data));
dialog.setUndeterminate(false);
对话框。可设置可取消(false);
dialog.show();
}否则{
getDirection=新的getDirection();
getDirection.execute();
}
重新设置为非配置状态

@覆盖
公共对象OnRetainCustomOnConfiguration安装(){
返回方向;
}
@凌驾
受保护的空onDestroy(){
super.ondestory();
if(dialog.isShowing()){
dialog.dismise();
}
}
编辑#1: 我采用了带有片段和保留片段的翠鸟解决方案,但当我在AsyncTask的doInBackground期间更改方向时,可扩展Listview上会出现NPE

08-14 12:50:40.866:E/AndroidRuntime(22739):致命异常:主
08-14 12:50:40.866:E/AndroidRuntime(22739):java.lang.NullPointerException
08-14 12:50:40.866:E/AndroidRuntime(22739):位于com.pasquini.adapter.ListRouteExpandableAdapter.getGroupCount(ListRouteExpandableAdapter.java:78)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于android.widget.ExpandableListConnector.getCount(ExpandableListConnector.java:399)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于android.widget.ListView.setAdapter(ListView.java:460)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于android.widget.ExpandableListView.setAdapter(ExpandableListView.java:470)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于com.pasquini.activity.RouteActivity.onPostExecute(RouteActivity.java:792)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:244)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:1)
08-14 12:50:40.866:E/AndroidRuntime(22739):在android.os.AsyncTask.finish(AsyncTask.java:631)
08-14 12:50:40.866:E/AndroidRuntime(22739):在android.os.AsyncTask.access$600(AsyncTask.java:177)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
08-14 12:50:40.866:E/AndroidRuntime(22739):在android.os.Handler.dispatchMessage(Handler.java:99)上
08-14 12:50:40.866:E/AndroidRuntime(22739):在android.os.Looper.loop(Looper.java:137)上
08-14 12:50:40.866:E/AndroidRuntime(22739):位于android.app.ActivityThread.main(ActivityThread.java:4895)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于java.lang.reflect.Method.Invokenactive(本机方法)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于java.lang.reflect.Method.invoke(Method.java:511)
08-14 12:50:40.866:E/AndroidRuntime(22739):在com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
08-14 12:50:40.866:E/AndroidRuntime(22739):位于com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
8-14 12:50:40.866:E/AndroidRuntime(22739):在dalvik.system.NativeStart.main(本机方法)。
这里是代码片段:

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);
    }
}
公共类GetDirectionFragment扩展了片段{
私人地图立法会;
私人ArrayList legsAndSteps;
私人名单;
私人名单;
私人名单polyz;
/**
*回调接口,片段将通过该接口报告
*任务的进度和结果返回到活动。
*/
公共静态接口任务回调{
void onPreExecute();
void onPostExecute();
列出GetListPoiberRoute();
void setLegs(列出legs、映射legsCollection);
void setPolyline(列表polyz);
}
私有任务回调回调;
私有GetDirectionTask GetDirectionTask;
/**
*保留对父活动的引用,以便我们可以报告
*任务的当前进度和结果。Android框架
*将在之后向我们传递对新创建活动的引用
*每次配置更改。
*/
@凌驾
公共事务主任(活动){
超级转速计(活动);
试一试{
回调=(TaskCallbacks)活动;
}catch(ClassCastException e){
抛出新的ClassCastException(activity.toString()+“必须实现TaskCallbacks”);
}
pois=callbacks.getListPoiberRoute();
}
/**
*此方法仅在保留
*首先创建片段。
*/
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//跨配置更改保留此片段。
setRetainInstance(真);
//创建并执行后台任务。
getDirectionTask=新建getDirectionTask();
getDirectionTask.execute();
}
/**
*将回调设置为null,这样我们就不会意外泄漏
*活动实例。
*/
@凌驾
公共无效连接(){
super.onDetach();
回调=null;
}
私有类GetDirectionTask扩展了AsyncTask{
@凌驾
受保护的void onPreExecute(){
if(回调!=null){
callbacks.onPreExecute();
}
}
/**
*注意,我们不调用回调对象的方法
*直接从后台线程,因为这可能导致
*处于比赛状态。
*/
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);
    }
}
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);
}
}
<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;
    }
}

}