You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android onClick无法获取正确SharedPreferences值致Fragment跳转失效

问题原因

核心错误是对AsyncTask的执行逻辑理解有误:

  • AsyncTask.execute()是异步非阻塞调用,调用后会立即返回,后台的网络请求、SharedPreferences写入逻辑跑在独立子线程,不会阻塞主线程继续往下执行。
  • 你当前的代码执行顺序完全不符合预期:点击按钮调用execute()后,主线程会立刻执行后续的登录状态读取判断,这时候子线程的登录逻辑还没执行到写入登录状态的步骤,读出来的状态必然是false;等整个onClick方法执行完毕后,子线程任务才跑完把登录状态写入,所以第二次点击按钮时判断才会成立,触发跳转。
  • 另外你当前的onPostExecute实现有小缺陷:方法入参s就是doInBackground的返回结果,直接用成员变量result做判断存在多线程值同步风险,应该优先使用入参做逻辑判断。
修复方案

核心原则:所有依赖异步任务执行结果的逻辑,必须放到异步任务执行完成的回调里触发,不能直接写在execute()调用之后。
具体修改步骤:

  • 给LoginSync增加结果回调接口,把登录成功/失败的事件抛给调用方,避免AsyncTask和页面跳转逻辑强耦合
  • 把原来写在onClick里、execute()调用后的状态判断和跳转逻辑全部删除,移到登录成功的回调方法里执行
  • 修正onPostExecute的判断逻辑,使用方法入参作为登录结果判断依据

修改后的LoginSync核心代码如下,doInBackground内的原有业务逻辑不需要改动:

public class LoginSync extends AsyncTask <String, Void, String> {

    // 新增登录结果回调接口
    public interface LoginCallback {
        void onLoginSuccess();
        void onLoginFailed(String errorMsg);
    }

    AlertDialog dialog;
    Context context;
    String result;
    JSONObject jObject;
    String username, password;
    String jEmail, jLevel;
    private LoginCallback callback;

    // 修改构造方法,传入回调实例
    public LoginSync(Context context, LoginCallback callback){
        this.context = context;
        this.callback = callback;
    }

    @Override
    protected void onPreExecute() {
        dialog = new AlertDialog.Builder(context).create();
        dialog.setTitle("Login Status");
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        // 直接使用入参s判断登录结果,避免多线程下成员变量值不同步
        if("login".equals(s)) {
            dialog.setMessage("Logged in successfully!");
            dialog.show();
            if(callback != null) {
                callback.onLoginSuccess();
            }
        }else{
            dialog.setMessage("Failed to login! Please check username/password.");
            dialog.show();
            if(callback != null) {
                callback.onLoginFailed(s);
            }
        }
    }

    @Override
    protected String doInBackground(String... voids) {
        // 原有网络请求、SharedPreferences写入逻辑保持不变即可
        username = voids[0];
        password = voids[1];

        String connstr = "URL HERE";

        try{
            URL url = new URL(connstr);
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setRequestMethod("POST");
            http.setDoInput(true);
            http.setDoOutput(true);

            OutputStream ops = http.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(ops, StandardCharsets.UTF_8));
            String data = URLEncoder.encode("username","UTF-8")+"="+URLEncoder.encode(username,"UTF-8")
                    +"&&"+URLEncoder.encode("password","UTF-8")+"="+URLEncoder.encode(password,"UTF-8");

            writer.write(data);
            writer.flush();
            writer.close();
            ops.close();

            InputStream ips = http.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(ips, StandardCharsets.ISO_8859_1));
            String line;

            while((line = reader.readLine()) != null){
                jObject = new JSONObject(line);
                result = "false";

                if (jObject != null){
                    jEmail = jObject.getString("email");
                    jLevel = jObject.getString("account_level");
                    result = "login";
                }
            }

            if(result.equals("login")) {
                AppPreferences.setUserInfo(context.getApplicationContext(), username,jEmail,jLevel);
                AppPreferences.setLoggedStatus(context.getApplicationContext(), true);
            }

            reader.close();
            ips.close();
            http.disconnect();
            return result;

        }catch (MalformedURLException e){
            result = e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return result;
    }
}

对应修改LoginFragment里的登录按钮点击逻辑:

binding.btnLogin.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        final String user = binding.username.getText().toString().trim();
        final String pass = binding.password.getText().toString().trim();

        // 传入回调实例化LoginSync
        LoginSync login = new LoginSync(getActivity(), new LoginSync.LoginCallback() {
            @Override
            public void onLoginSuccess() {
                // 该方法会在登录成功、SP写入完成后在主线程触发,跳转逻辑可以正常执行
                NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
            }

            @Override
            public void onLoginFailed(String errorMsg) {
                // 可按需添加登录失败的额外提示逻辑
            }
        });
        login.execute(user,pass);
    }
});

额外说明:AsyncTask在Android 11(API 30)已被官方废弃,后续开发异步网络请求场景建议替换为协程、Retrofit等官方推荐的异步实现,避免出现API兼容问题。

内容的提问来源于stack exchange,提问作者André Bandeira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:39:24