0

ログイン機能を備えたシンプルなアプリケーションを作成しました。と呼ばれるサーバーにログインするための別のタスクと、と呼ば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) {

    }    
}

ログインタスクには時間がかかるため、タスクが完了する前にデバイスのライトがオフになり、アクティビティが破壊されることがあります。これにより、タスクがリスナー (フラグメント) の呼び出しに失敗しました。この問題を解決するには?

ありがとう

4

4 に答える 4

3

AsyncTask少し時間がかかり、現在のアクティビティに結果を返すタスクに使用する必要があります。ただし、実際に長時間実行されるタスクや、アクティビティが破棄された場合でもその結果を評価したい場合は対象外です。

ここでa を使用することを検討してServiceください。いずれにせよonPostExecute()、アクティビティ コンテキストが失われる可能性があるため、これ以上更新を行うべきではありません ( Doctoror Driveの投稿を参照してください)。

Intentそのサービスを用意すると、またはBroadcastイベントをシステムに送信できます。次に、そのインテント アクティビティ / ブロードキャスト レシーバーでさらに処理を行います。

于 2013-03-17T14:03:00.740 に答える
1

LoginActivity の onDestroy() で asynctask をキャンセルできます。

asynctask の onCancelled() をオーバーライドします。アクティビティが破棄されると、onPostExecute() の代わりに onCancelled() が呼び出されます。

ここで、LoginActivity へのコールバックを回避できます。

于 2013-03-17T13:55:38.387 に答える
1

Serviceまたはを使用する必要がありますIntentServiceAsyncTaskの変数やコンテキストを記録しないためですActivity。ログイン タスクの起動が終了したらPendingIntent、またはstartActivity(intent). これは Android のベスト プラクティスです。この方法では、例外が発生することはありません。

于 2013-03-17T14:08:52.200 に答える
0

onLoginComplete と onLoginFailure で、フラグメントがまだアクティビティにアタッチされているかどうかを確認します。そうでない場合は、何もしません。

@Override
public void onLoginComplete() {

    if (isAdded() && !isRemoving() && !isDetached()) {
        ((MainActivity)getActivity()).gotoMain();
    }
}
于 2013-03-17T13:51:43.453 に答える