我使用登录功能创建了简单的应用程序。我创建了单独的任务来登录名为LoginTask
的服务器和一个名为LoginListener
的监听器类。
public interface LoginListener {
public void onLoginComplete();
public void onLoginFailure(String msg);
}
public class LoginTask extends AsyncTask<String, Void, Boolean>{
private final LoginListener listener;
private final Context c;
private String msg;
public LoginTask(final Context c, final LoginListener listener) {
this.c = c;
this.listener = listener;
}
@Override
protected Boolean doInBackground(String... args) {
// loging in to server
//return true if success
}
@Override
protected void onPostExecute(Boolean status) {
if(!status){
if(listener != null) listener.onLoginFailure(msg);
return;
}
// the problem is here, listener is null, because activity/fragment destroyed
if(listener != null) listener.onLoginComplete();
}
}
我从LoginTask
执行了LoginFragment
。 LoginFragment
实施LoginListener
。
public class LoginFragment extends Fragment implements LoginListener{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.frg_login, container, false);
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
doInitView();
};
private void doInitView(){
Button loginButton = (Button) getActivity().findViewById(R.id.login_btn);
Button regButton = (Button) getActivity().findViewById(R.id.toreg_btn);
ButtonListener listener = new ButtonListener();
loginButton.setOnClickListener(listener);
regButton.setOnClickListener(listener);
}
private void doLogin(){
Activity activity = getActivity();
EditText emailText = (EditText)activity.findViewById(R.id.login_email);
EditText pwdText = (EditText)activity.findViewById(R.id.login_pwd);
String email = emailText.getText().toString().trim();
String pwd = pwdText.getText().toString().trim();
if(StringUtil.isAnyNull(email, pwd)){
Popup.showMsg(getActivity(), "Silahkan lengkapi data", Popup.SHORT);
return;
}
savedEmail = email;
savedPwd = pwd;
String url = getActivity().getResources().getString(R.string.url_login);
Popup.showLoading(getActivity(), "Login", "Please wait...");
LoginTask task = new LoginTask(getActivity(), this);
task.execute(url, email, pwd);
}
private final class ButtonListener implements OnClickListener{
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.login_btn:
doLogin();
break;
case R.id.toreg_btn:
doToRegister();
break;
case R.id.demo_btn:
doDemo();
break;
}
}
}
@Override
public void onLoginComplete() {
// getActivity() is null
((MainActivity)getActivity()).gotoMain();
}
@Override
public void onLoginFailure(String msg) {
}
}
由于登录任务需要时间,因此有时在任务完成之前设备指示灯熄灭,因此活动被破坏。这导致任务无法调用侦听器(片段)。如何解决这个问题?
由于
答案 0 :(得分:3)
AsyncTask
应该用于需要更长时间并将结果返回到当前活动的任务。但是,它不适用于长时间运行的任务,也不适用于即使活动已被销毁也要评估其结果的情况。
您可以考虑在此处使用Service
。在任何情况下,您都不应该在onPostExecute()
中进行更新,因为活动上下文可能已经消失(请参阅 Doctoror Drive 的帖子)。
启用该服务后,您可以向系统发送Intent
或Broadcast
事件。然后在该意图活动/广播接收器中进行进一步处理。
答案 1 :(得分:1)
您可以取消LoginActivity的onDestroy()中的asynctask。
覆盖asynctask的onCancelled()。当活动被销毁时,将调用onCancelled()而不是onPostExecute()
在这里,您可以避免回到LoginActivity。
答案 2 :(得分:1)
您应该使用Service
或IntentService
。因为AsyncTask
不记录Activity
的任何变量或上下文。完成登录任务启动PendingIntent
或startActivity(intent)
后。这可能是Android的最佳实践。这样你永远不会得到例外。
答案 3 :(得分:0)
在onLoginComplete和onLoginFailure中检查片段是否仍附加到活动。如果没有,什么都不做。
@Override
public void onLoginComplete() {
if (isAdded() && !isRemoving() && !isDetached()) {
((MainActivity)getActivity()).gotoMain();
}
}