我正在开发一个智能手机/平板电脑应用程序,仅使用一个APK,并根据屏幕大小加载所需的资源,最好的设计选择似乎是通过ACL使用片段。

到目前为止,此应用程序一直运行良好,仅基于 Activity 。这是一个模拟类,它说明了我如何在“ Activity ”中处理AsyncTasks和ProgressDialogs以便即使在屏幕旋转或在通信过程中发生配置更改时也能正常工作的情况。

我不会更改 list 以避免 Activity 的重演,我有很多理由不愿意这样做,但主要是因为官方文档说不建议这样做,而到目前为止我已经设法做到这一点,所以请不要建议路线。

public class Login extends Activity {

    static ProgressDialog pd;
    AsyncTask<String, Void, Boolean> asyncLoginThread;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.login);
        //SETUP UI OBJECTS
        restoreAsyncTask();
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        if (pd != null) pd.dismiss();
        if (asyncLoginThread != null) return (asyncLoginThread);
        return super.onRetainNonConfigurationInstance();
    }

    private void restoreAsyncTask();() {
        pd = new ProgressDialog(Login.this);
        if (getLastNonConfigurationInstance() != null) {
            asyncLoginThread = (AsyncTask<String, Void, Boolean>) getLastNonConfigurationInstance();
            if (asyncLoginThread != null) {
                if (!(asyncLoginThread.getStatus()
                        .equals(AsyncTask.Status.FINISHED))) {
                    showProgressDialog();
                }
            }
        }
    }

    public class LoginThread extends AsyncTask<String, Void, Boolean> {
        @Override
        protected Boolean doInBackground(String... args) {
            try {
                //Connect to WS, recieve a JSON/XML Response
                //Place it somewhere I can use it.
            } catch (Exception e) {
                return true;
            }
            return true;
        }

        protected void onPostExecute(Boolean result) {
            if (result) {
                pd.dismiss();
                //Handle the response. Either deny entry or launch new Login Succesful Activity
            }
        }
    }
}

这段代码可以正常工作,我有大约10.000个用户,没有任何提示,因此仅将这种逻辑复制到新的基于片段的设计中似乎很合逻辑,但是,当然这是行不通的。

这是LoginFragment:
public class LoginFragment extends Fragment {

    FragmentActivity parentActivity;
    static ProgressDialog pd;
    AsyncTask<String, Void, Boolean> asyncLoginThread;

    public interface OnLoginSuccessfulListener {
        public void onLoginSuccessful(GlobalContainer globalContainer);
    }

    public void onSaveInstanceState(Bundle outState){
        super.onSaveInstanceState(outState);
        //Save some stuff for the UI State
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setRetainInstance(true);
        //If I setRetainInstance(true), savedInstanceState is always null. Besides that, when loading UI State, a NPE is thrown when looking for UI Objects.
        parentActivity = getActivity();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            loginSuccessfulListener = (OnLoginSuccessfulListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnLoginSuccessfulListener");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        RelativeLayout loginLayout = (RelativeLayout) inflater.inflate(R.layout.login, container, false);
        return loginLayout;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //SETUP UI OBJECTS
        if(savedInstanceState != null){
            //Reload UI state. Im doing this properly, keeping the content of the UI objects, not the object it self to avoid memory leaks.
        }
    }

    public class LoginThread extends AsyncTask<String, Void, Boolean> {
            @Override
            protected Boolean doInBackground(String... args) {
                try {
                    //Connect to WS, recieve a JSON/XML Response
                    //Place it somewhere I can use it.
                } catch (Exception e) {
                    return true;
                }
                return true;
            }

            protected void onPostExecute(Boolean result) {
                if (result) {
                    pd.dismiss();
                    //Handle the response. Either deny entry or launch new Login Succesful Activity
                }
            }
        }
    }
}

我不能使用onRetainNonConfigurationInstance(),因为必须从Activity而不是Fragment中调用它,getLastNonConfigurationInstance()也是如此。我在这里读过一些类似的问题,没有任何答案。

我知道,可能需要一些工作才能使这些内容正确地组织成碎片,也就是说,我想保持相同的基本设计逻辑。

在配置更改期间保留AsyncTask的正确方法是什么,如果它仍在运行,则显示一个progressDialog,并考虑到AsyncTask是Fragment的内部类,而调用AsyncTask的是Fragment本身。执行()?

最佳答案

片段实际上可以使这一过程变得容易得多。只需使用Fragment.setRetainInstance(boolean)方法即可将片段实例保留在配置更改中。请注意,这是文档中Activity.onRetainnonConfigurationInstance()的推荐替代品。

如果由于某种原因您确实不想使用保留的片段,则可以采用其他方法。请注意,每个片段都有一个由Fragment.getId()返回的唯一标识符。您还可以通过Fragment.getActivity().isChangingConfigurations()找出是否要拆除某个片段以进行配置更改。因此,在决定停止AsyncTask的时候(最有可能在onStop()或onDestroy()中),您可以例如检查配置是否正在更改,是否将其粘贴在片段标识符下的静态SparseArray中,然后在您的onCreate()或onStart()中查看是否有可用的稀疏数组中的AsyncTask。

10-08 15:28