由于活动被破坏,如何在长期任务后与活动进行通信

时间:2013-03-17 13:48:30

标签: android android-activity android-fragments

我使用登录功能创建了简单的应用程序。我创建了单独的任务来登录名为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执行了LoginFragmentLoginFragment实施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) {

    }    
}

由于登录任务需要时间,因此有时在任务完成之前设备指示灯熄灭,因此活动被破坏。这导致任务无法调用侦听器(片段)。如何解决这个问题?

由于

4 个答案:

答案 0 :(得分:3)

AsyncTask应该用于需要更长时间并将结果返回到当前活动的任务。但是,它不适用于长时间运行的任务,也不适用于即使活动已被销毁也要评估其结果的情况。

您可以考虑在此处使用Service。在任何情况下,您都不应该在onPostExecute()中进行更新,因为活动上下文可能已经消失(请参阅 Doctoror Drive 的帖子)。

启用该服务后,您可以向系统发送IntentBroadcast事件。然后在该意图活动/广播接收器中进行进一步处理。

答案 1 :(得分:1)

您可以取消LoginActivity的onDestroy()中的asynctask。

覆盖asynctask的onCancelled()。当活动被销毁时,将调用onCancelled()而不是onPostExecute()

在这里,您可以避免回到LoginActivity。

答案 2 :(得分:1)

您应该使用ServiceIntentService。因为AsyncTask不记录Activity的任何变量或上下文。完成登录任务启动PendingIntentstartActivity(intent)后。这可能是Android的最佳实践。这样你永远不会得到例外。

答案 3 :(得分:0)

在onLoginComplete和onLoginFailure中检查片段是否仍附加到活动。如果没有,什么都不做。

@Override
public void onLoginComplete() {

    if (isAdded() && !isRemoving() && !isDetached()) {
        ((MainActivity)getActivity()).gotoMain();
    }
}