Estou trabalhando em um aplicativo de smartphone / tablet, usando apenas um APK e carregando recursos conforme necessário, dependendo do tamanho da tela, a melhor escolha de design parece ser usar Fragments via ACL.
Este aplicativo tem funcionado bem até agora sendo apenas baseado em atividades. Esta é uma aula simulada de como eu lido com AsyncTasks e ProgressDialogs nas Atividades para que funcionem mesmo quando a tela é girada ou ocorre uma alteração na configuração durante a comunicação.
Não vou alterar o manifesto para evitar a recriação da Activity, há muitos motivos pelos quais não quero fazer isso, mas principalmente porque os documentos oficiais dizem que não é recomendado e eu consegui sem ele até agora, então por favor não recomende isso rota.
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
}
}
}
}
Este código está funcionando bem, tenho cerca de 10.000 usuários sem reclamação, então parecia lógico apenas copiar essa lógica para o novo Fragment Based Design, mas, é claro, não está funcionando.
Aqui está o 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
}
}
}
}
}
Não posso usar onRetainNonConfigurationInstance()porque tem que ser chamado da Activity e não do Fragment, o mesmo acontece getLastNonConfigurationInstance(). Eu li algumas perguntas semelhantes aqui sem resposta.
Eu entendo que pode ser necessário algum trabalho ao redor para que essas coisas sejam organizadas adequadamente em fragmentos. Dito isso, gostaria de manter a mesma lógica básica de design.
Qual seria a maneira adequada de reter o AsyncTask durante uma alteração de configuração e, se ainda estiver em execução, mostrar um progressDialog, levando em consideração que o AsyncTask é uma classe interna ao Fragment e é o próprio Fragment que invoca o AsyncTask.execute ()?