简体   繁体   English

无法在 onClick 上获得正确的 SharedPreferences 值

[英]Cannot get correct SharedPreferences value on onClick

I'm currently making a small app and I'm getting stuck on changing fragments using an onClick listener.我目前正在制作一个小型应用程序,但我被困在使用 onClick 侦听器更改片段上。 I've searched the site and could find similar situations, but none of the proposed solutions worked.我已经搜索了该站点,并且可以找到类似的情况,但是所提出的解决方案都没有奏效。

So, when a user logs in, it sets a few values in SharedPreferences such as username, email and account level using a method from a class used to set and get SharedPreferences values.因此,当用户登录时,它会使用用于设置和获取 SharedPreferences 值的类中的方法在 SharedPreferences 中设置一些值,例如用户名、电子邮件和帐户级别。 Afterwards, it should automatically redirect the user to a different Fragment.之后,它应该自动将用户重定向到不同的 Fragment。 What's not happening, is redirecting the user to the other fragment.没有发生的是将用户重定向到另一个片段。

I'm using AsyncTask for accessing the database.我正在使用 AsyncTask 访问数据库。 This is my code for the Login AsyncTask:这是我的登录异步任务代码:

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

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

    public LoginSync(Context context){
        this.context = context;
    }

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

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        if(result.equals("login")) {
            dialog.setMessage("Logged in successfully!");
        }else{
            dialog.setMessage("Failed to login! Please check username/password.");
        }
        dialog.show();
    }

    @Override
    protected String doInBackground(String... voids) {

        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;
    }
}

Using the debugger, I see that the values are being set as intended in the SharedPreferences.使用调试器,我看到这些值是按照 SharedPreferences 中的预期设置的。 However, in the onClick check on the Login Fragment, it's set to false until the onClick method ends.但是,在登录片段的 onClick 检查中,它被设置为 false,直到 onClick 方法结束。

This is my Login Fragment code:这是我的登录片段代码:

public class LoginFragment extends Fragment {

    private FragmentLoginBinding binding;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        binding = FragmentLoginBinding.inflate(inflater, container, false);
        View root = binding.getRoot();

        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 login = new LoginSync(getActivity());
                login.execute(user,pass);

                if(AppPreferences.getLoggedStatusBool(getActivity()).equals(true)){
                    NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
                }

            }
        });

        binding.lnkRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_register);
            }
        });

        return root;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}

On the first click, the values are set correctly, but checking the onClick with the debugger tells me that it's still false, after running the AsyncTask, and it doesn't trigger the fragment change in the if clause.在第一次单击时,值设置正确,但使用调试器检查 onClick 告诉我在运行 AsyncTask 后它仍然是错误的,并且它不会触发 if 子句中的片段更改。 On the second click, it changes the fragment.在第二次单击时,它会更改片段。

What am I doing wrong?我究竟做错了什么? How can I make it change the fragment on the same click as it sets the information?如何使它在设置信息的同时单击更改片段?

Thank you.谢谢你。

You are getting correct value from sharedPreference, only your timing to get that value is not correct.您从 sharedPreference 中获得了正确的值,只是您获得该值的时间不正确。 You are using async task, which works on a different thread.您正在使用异步任务,该任务在不同的线程上工作。 in your onCLick you have these lines:在您的 onCLick 中,您有以下几行:

LoginSync login = new LoginSync(getActivity());
login.execute(user,pass);

if(AppPreferences.getLoggedStatusBool(getActivity()).equals(true)){
     NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
}

you must have assumed that your if statement will execute after your login async task is completed, but this will not happen, it will execute straight after starting the login process and will check the sharedPref before the value is even set.您必须假设您的 if 语句将在您的登录异步任务完成后执行,但这不会发生,它将在启动登录过程后立即执行,并会在设置值之前检查 sharedPref。 You are doing network call and IO operation which will take some time and shared pref should be checked after the async task has been completed.您正在进行网络调用和 IO 操作,这将需要一些时间,并且应在异步任务完成后检查共享首选项。 So yo should write your if statement in async class's onPostExecute method like this:所以你应该在异步类的 onPostExecute 方法中编写你的 if 语句,如下所示:

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
    if(result.equals("login")) {
        dialog.setMessage("Logged in successfully!");
        if(AppPreferences.getLoggedStatusBool(getActivity()).equals(true)){
NavHostFragment.findNavController(getParentFragment()).navigate(R.id.action_nav_login_to_nav_home);
    }
        }else{
            dialog.setMessage("Failed to login! Please check username/password.");
        }
        dialog.show();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM