【问题标题】:Closing the app when user cancels immediate in app update当用户在应用更新中立即取消时关闭应用
【发布时间】:2020-09-15 09:26:21
【问题描述】:

目前我正在从 android 实现应用内更新功能。我正在使用立即更新方法,我面临的问题是当 UI 提示用户更新显示并且用户没有单击更新按钮而是单击十字按钮时。应用更新的 UI 刚刚关闭,用户可以继续使用该应用。

我想要的是,当用户单击十字按钮时,应用程序会立即关闭,直到用户更新应用程序,然后他们才能像往常一样使用该应用程序。我也使用java代码进行android开发。

public class LoginActivity extends AppCompatActivity {

private LoginViewModel loginViewModel;
public static final String MyPREFERENCES = "LoginPrefs" ;
public static final String Name = "nameKey";
public static final String User = "userKey";
public static final String con = "closed";
public static String error = "";
public static int userFlag = 0;
SharedPreferences sharedpreferences;
SharedPreferences.Editor editor;

public TextInputEditText usernameEditText;
public TextInputEditText passwordEditText;

private AppUpdateManager mAppUpdateManager;
private int RC_APP_UPDATE = 999;
private int inAppUpdateType;
private com.google.android.play.core.tasks.Task<AppUpdateInfo> appUpdateInfoTask;
private InstallStateUpdatedListener installStateUpdatedListener;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    loginViewModel = ViewModelProviders.of(this, new LoginViewModelFactory())
            .get(LoginViewModel.class);

    usernameEditText = findViewById(R.id.user);
    passwordEditText = findViewById(R.id.pass);
    final Button loginButton = findViewById(R.id.submitBTN);
    final TextInputLayout userL = findViewById(R.id.userL);
    final TextInputLayout passL = findViewById(R.id.passL);
    final JellyToggleButton jtb = findViewById(R.id.jtb);


    // Creates instance of the manager.
    mAppUpdateManager = AppUpdateManagerFactory.create(this);
    // Returns an intent object that you use to check for an update.
    appUpdateInfoTask = mAppUpdateManager.getAppUpdateInfo();
    //lambda operation used for below listener
    //For flexible update
    installStateUpdatedListener = installState -> {
        if (installState.installStatus() == InstallStatus.DOWNLOADED) {
            popupSnackbarForCompleteUpdate();
        }
    };
    mAppUpdateManager.registerListener(installStateUpdatedListener);

    inAppUpdateType = AppUpdateType.IMMEDIATE; //1
    inAppUpdate();

    if(userFlag==1){
        jtb.setChecked(true);
    }

    userL.setHint("Enter username");
    sharedpreferences = getSharedPreferences(MyPREFERENCES, MODE_PRIVATE);
    loginViewModel.getLoginFormState().observe(this, new Observer<LoginFormState>() {
        @Override
        public void onChanged(@Nullable LoginFormState loginFormState) {
            if (loginFormState == null) {
                return;
            }
            loginButton.setEnabled(loginFormState.isDataValid());
            if (loginFormState.getUsernameError() != null) {
                usernameEditText.setError(getString(loginFormState.getUsernameError()));

                loginButton.startAnimation(AnimationUtils.loadAnimation(LoginActivity.this,R.anim.shake));
            }
            if (loginFormState.getPasswordError() != null) {
                passwordEditText.setError(getString(loginFormState.getPasswordError()));
                loginButton.startAnimation(AnimationUtils.loadAnimation(LoginActivity.this,R.anim.shake));
            }
        }
    });

    loginViewModel.getLoginResult().observe(this, new Observer<LoginResult>() {
        @Override
        public void onChanged(@Nullable LoginResult loginResult) {
            if (loginResult == null) {
                return;
            }

            if (loginResult.getError() != null) {
                showLoginFailed(loginResult.getError());
            }
            if (loginResult.getSuccess() != null) {
                updateUiWithUser(loginResult.getSuccess());
                Intent i = new Intent(LoginActivity.this, user_dashboard.class);
                startActivity(i);
            }
            setResult(Activity.RESULT_OK);

            //Complete and destroy login activity once successful

        }
    });

    TextWatcher afterTextChangedListener = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            // ignore
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // ignore
        }

        @Override
        public void afterTextChanged(Editable s) {
            loginViewModel.loginDataChanged(usernameEditText.getText().toString(),
                    passwordEditText.getText().toString());
        }
    };
    usernameEditText.addTextChangedListener(afterTextChangedListener);
    passwordEditText.addTextChangedListener(afterTextChangedListener);
    passwordEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {

        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                loginViewModel.login(usernameEditText.getText().toString(),
                        passwordEditText.getText().toString());
            }
            return false;
        }
    });

    loginButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            if(userFlag==0) {
                loginViewModel.login(usernameEditText.getText().toString(),
                        passwordEditText.getText().toString());
                getStaffData();
            }
            else if(userFlag==1){
                loginWorker();
            }

        }
    });

    jtb.setOnStateChangeListener(new JellyToggleButton.OnStateChangeListener() {
        @Override
        public void onStateChange(float process, State state, JellyToggleButton jtb) {
            if (state.equals(State.LEFT)) {

                userL.setHint("Enter username");
                error = "Username cannot be empty";
                userFlag = 0;
            }
            if (state.equals(State.RIGHT)) {

                userL.setHint("Enter badge ID");
                error = "Badge ID cannot be empty";
                userFlag = 1;
            }
        }
    });
}

@Override
protected void onDestroy() {
    mAppUpdateManager.unregisterListener(installStateUpdatedListener);
    finishAndRemoveTask();
    super.onDestroy();
}

@Override
protected void onResume() {
    try {
        mAppUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {
            if (appUpdateInfo.updateAvailability() ==
                    UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                // If an in-app update is already running, resume the update.
                try {
                    mAppUpdateManager.startUpdateFlowForResult(
                            appUpdateInfo,
                            inAppUpdateType,
                            this,
                            RC_APP_UPDATE);
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
            }
        });


        mAppUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {
            //For flexible update
            if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                popupSnackbarForCompleteUpdate();
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

    super.onResume();
}

@Override //For flexible update
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == RC_APP_UPDATE) {
        //when user clicks update button
        if (resultCode == RESULT_OK) {
            Toast.makeText(LoginActivity.this, "App download starts...", Toast.LENGTH_LONG).show();
        } else if (resultCode == RESULT_CANCELED) {
            //if you want to request the update again just call checkUpdate()
            Toast.makeText(LoginActivity.this, "App download canceled.", Toast.LENGTH_LONG).show();
        } else if (resultCode == RESULT_IN_APP_UPDATE_FAILED) {
            Toast.makeText(LoginActivity.this, "App download failed.", Toast.LENGTH_LONG).show();
        }
    }
}

private void updateUiWithUser(LoggedInUserView model) {

    String welcome = getString(R.string.welcome);
    // TODO : initiate successful logged in experience
    Toast.makeText(getApplicationContext(), welcome, Toast.LENGTH_LONG).show();
}

private void showLoginFailed(@StringRes Integer errorString) {
    Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_SHORT).show();
}

private void getStaffData() {
    String username = usernameEditText.getText().toString();
    APIInterface apiInterface3 = APIClient.getClient().create(APIInterface.class);
    Call<loginList> call3 = apiInterface3.staffData(username);
    call3.enqueue(new Callback<loginList>() {
        @Override
        public void onResponse(Call<loginList> call, Response<loginList> response) {
            loginList list = response.body();
            if (list!=null && list.getStatusCode()==1) { //response received.
                if(list.getStaffList().size()>0){
                    Log.d("check-in", list.getStatusCode() + " " + list.getStaffList().get(0).getName());
                    Toast.makeText(LoginActivity.this,"Logged in",Toast.LENGTH_SHORT).show();

                    final String name = list.getStaffList().get(0).getName();
                    final String badge = list.getStaffList().get(0).getBadge();
                    SharedPreferences.Editor editor = sharedpreferences.edit();
                    editor.putString(Name,name);
                    editor.putString(User,badge);
                    editor.putInt(con,1);
                    editor.apply();
                }
                else if(list.getStaffList().size()==0){

                }
            }
        }

        @Override
        public void onFailure(Call<loginList> call, Throwable t) {
            Log.d("fail",t.toString());
        }
    });
}

private void loginWorker(){
    String username = usernameEditText.getText().toString();
    String password = passwordEditText.getText().toString();

    APIInterface apiInterface3 = APIClient.getClient().create(APIInterface.class);
    Call<loginList> call3 = apiInterface3.loginWorker(username,password);
    call3.enqueue(new Callback<loginList>() {
        @Override
        public void onResponse(Call<loginList> call, Response<loginList> response) {
            loginList list = response.body();
            Log.d("response", response.body().toString());
            if (list!=null && list.getStatusCode()==1) { //response received.
                if(list.getLoginList().size()>0){
                    Log.d("check-in", list.getStatusCode() + " " + list.getLoginList().get(0).getName());
                    Toast.makeText(LoginActivity.this,"Logged in",Toast.LENGTH_SHORT).show();
                    List<login> item = response.body().getLoginList();
                    final String name = list.getLoginList().get(0).getName();
                    SharedPreferences.Editor editor = sharedpreferences.edit();
                    editor.putString(Name,name);
                    editor.putInt(con,1);
                    editor.apply();

                }
                String welcome = getString(R.string.welcome);
                Toast.makeText(getApplicationContext(), welcome, Toast.LENGTH_SHORT).show();
                Intent i = new Intent(LoginActivity.this, user_dashboard.class);
                startActivity(i);
            }
            else
            Toast.makeText(LoginActivity.this, "wrong ID or password",Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(Call<loginList> call, Throwable t) {
            Log.d("fail",t.toString());
        }
    });
    editor = sharedpreferences.edit();
    editor.putString(User, username);
    editor.commit();
}

@Override
public void onBackPressed() {
    new MaterialAlertDialogBuilder(LoginActivity.this,R.style.MyDialogTheme)
            .setTitle("Exit")
            .setMessage("Confirm to exit?")
            .setBackground(getDrawable(R.drawable.alert_dialog))
            // Specifying a listener allows you to take an action before dismissing the dialog.
            // The dialog is automatically dismissed when a dialog button is clicked.
            .setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // Continue with delete
                    finishAffinity();

                }
            })


            .setNegativeButton(android.R.string.no, null)

            .show();


}

private void inAppUpdate() {
    try {
        // Checks that the platform will allow the specified type of update.
        appUpdateInfoTask.addOnSuccessListener(new OnSuccessListener<AppUpdateInfo>() {
            @Override
            public void onSuccess(AppUpdateInfo appUpdateInfo) {
                if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
                        // For a flexible update, use AppUpdateType.FLEXIBLE
                        && appUpdateInfo.isUpdateTypeAllowed(inAppUpdateType)) {
                    // Request the update.
                    try {
                        mAppUpdateManager.startUpdateFlowForResult(
                                // Pass the intent that is returned by 'getAppUpdateInfo()'.
                                appUpdateInfo,
                                // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
                                inAppUpdateType,
                                // The current activity making the update request.
                                LoginActivity.this,
                                // Include a request code to later monitor this update request.
                                RC_APP_UPDATE);

                    } catch (IntentSender.SendIntentException ignored) {

                    }
                }
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

}

private void popupSnackbarForCompleteUpdate() {
    try {
        Snackbar snackbar =
                Snackbar.make(
                        findViewById(R.id.coordinatorL),
                        "An update has just been downloaded.\nRestart to update",
                        Snackbar.LENGTH_INDEFINITE);

        snackbar.setAction("INSTALL", view -> {
            if (mAppUpdateManager != null){
                mAppUpdateManager.completeUpdate();
            }
        });
        snackbar.setActionTextColor(getResources().getColor(R.color.orange));
        snackbar.show();

    } catch (Resources.NotFoundException e) {
        e.printStackTrace();
    }
}
}

我从谷歌借来的图片,在左边的图片中可以看到右上角有一个十字按钮,用户可以点击关闭更新过程

【问题讨论】:

    标签: java android


    【解决方案1】:

    我要强调的最重要的一点是,除非绝对必要(例如某些安全问题等),否则您不应强迫用户更新应用程序。强制用户更新被认为是非常糟糕的用户体验。

    对于您提出的问题,您的问题本身就有答案。如果您检查代码,您的 onActivityResult 方法中有类似的内容-

    if (requestCode == RC_APP_UPDATE) {
            //when user clicks update button
            if (resultCode == RESULT_OK) {
                Toast.makeText(LoginActivity.this, "App download starts...", Toast.LENGTH_LONG).show();
            } else if (resultCode == RESULT_CANCELED) {
                //if you want to request the update again just call checkUpdate()
                Toast.makeText(LoginActivity.this, "App download canceled.", Toast.LENGTH_LONG).show();
            } else if (resultCode == RESULT_IN_APP_UPDATE_FAILED) {
                Toast.makeText(LoginActivity.this, "App download failed.", Toast.LENGTH_LONG).show();
            }
        }
    

    如果用户取消resultCode == RESULT_CANCELED或更新失败resultCode == RESULT_IN_APP_UPDATE_FAILED,您可以采取任何您想要的操作。您可以完成活动或任何适合您情况的活动。

    【讨论】:

    • 如果您想区分灵活更新和即时更新怎么办?即 - 如果用户关闭对话框以立即更新,您只想关闭应用程序?有什么方法可以告诉用户在onActivityResult 中取消了什么样的更新?
    • 您可以为这两个请求设置不同的请求代码,并根据响应分别采取行动
    • 啊哈,现在我知道这是在哪里传递的了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 1970-01-01
    相关资源
    最近更新 更多