2019独角兽企业重金招聘Python工程师标准>>>
前言:
项目需要实现session会话过期的功能,经过不断地调试,实现了该功能。下面我简单总结一下在客户端实现session会话过期的功能,希望对大家有所帮助!
需求:
Session会话过期,即5分钟会话到期时,用户退出应用程序。
以下四种情况需要弹出对话框提示:
1.App应用程序锁定 ;
2.从其他应用程序活动又回到App设备 ;
3.App应用程序不活动 ;
4.Refresh_token过期(在拦截器处理,这里不做介绍)。
对话框有一个“OK”按钮的样式,单击“OK”用户将返回到登录页面。
思路:
1.在BaseActivity基类实现该功能,其他Activity继承BaseActivity即可。
2.在App应用程序初始化的时候,用CountTimer来处理。
3.当App应用程序锁定或者从其他应用程序活动又回到App设备,用BroadcastReceiver来处理。
4.App应用程序不活动时,重写dispatchTouchEvent,并处理。
5.弹出对话框提示用AlertDialog。
实现步骤:
1.App应用程序初始化的时候,添加CountTimer计时器。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//设置5分钟后会话过期
if(timeStart==0){
countTimerView = new CountTimer(5 * 60 * 1000, 1000, BaseActivity.this);
}
}
...
}
@Override
protected void onResume() {
super.onResume();
timeStart();//开始计时
}
@Override
protected void onPause() {
super.onPause();
if (countTimerView != null) {
countTimerView.cancel();//当暂停的时候,要取消计时器
}
}
private void timeStart() {
new Handler(getMainLooper()).post(new Runnable() { //重新开一条线程
@Override
public void run() {
if (countTimerView != null)
countTimerView.start();//开始
}
});
}
2.当App应用程序锁定或者从其他应用程序活动又回到App设备,用BroadcastReceiver来处理。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//注册广播接收者
registerReceiver(myReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
registerReceiver(myReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
registerReceiver(myReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
...
}
@Override
protected void onStart() {
showLockScreenDialog();//调用onStart方法时,展示锁屏的dialog
super.onStart();
}
@Override
protected void onStop() {
count--;
if (count == 0) {
timeStart = new Date().getTime(); //调用onStop方法时,开始计时
}
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);//反注册
}
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {//屏幕亮起来
}
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { //锁屏
}
if (Intent.ACTION_USER_PRESENT.equals(intent.getAction()) && isDialogClose == 0) {//解锁
showLockScreenDialog();
}
}
};
private void showLockScreenDialog() {
if (count == 0) {
long timeEnd = new Date().getTime();
if (timeStart != 0 && timeEnd - timeStart >= 5 * 60 * 1000) { //5分钟会话过期,弹出对话框
if (countTimerView != null) {
countTimerView.showSessionDialog();//Show session dialog
}
}
}
count++;
}
3.App应用程序不活动时,重写dispatchTouchEvent,并处理。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP://弹起
if (countTimerView != null)
countTimerView.start();//开始计时
break;
case MotionEvent.ACTION_DOWN://按下
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
hideSoftInput(v.getWindowToken());
}
if (countTimerView != null)
countTimerView.cancel();//取消计时器
timeStart=0;
break;
default:
if (countTimerView != null)
countTimerView.cancel();//取消计时器
timeStart=0;
break;
}
return super.dispatchTouchEvent(ev);
}
4.在BaseActivity实现的完整代码。
public abstract class BaseActivity extends AppCompatActivity
implements IUIOperation, BaseView {
...
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//5分钟会话过期
if(timeStart==0){
countTimerView = new CountTimer(5 * 60 * 1000, 1000, BaseActivity.this);
}
//注册广播接收者
registerReceiver(myReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
registerReceiver(myReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
registerReceiver(myReceiver, new IntentFilter(Intent.ACTION_USER_PRESENT));
...
}
@Override
protected void onStart() {
showLockScreenDialog();//调用onStart方式时,弹出对话框
super.onStart();
}
@Override
protected void onResume() {
super.onResume();
timeStart();//开始计时
}
@Override
protected void onPause() {
super.onPause();
if (countTimerView != null) {
countTimerView.cancel();//取消计时器
}
}
@Override
protected void onStop() {
count--;
if (count == 0) {
timeStart = new Date().getTime();//调用onStop方法时,开始计时
}
if (isDialogClose == 1) {
if (mPDialog != null) {
mPDialog.dismiss();
mPDialog = null;
}
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
if (dialog2 != null) {
dialog2.dismiss();
dialog2 = null;
}
}
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
...
unregisterReceiver(myReceiver);//反注册
}
private void timeStart() {
new Handler(getMainLooper()).post(new Runnable() {//新开一条线程
@Override
public void run() {
if (countTimerView != null)
countTimerView.start();//开始计时
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP: //弹起
if (countTimerView != null)
countTimerView.start(); //开始计时
break;
case MotionEvent.ACTION_DOWN: //按下
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
hideSoftInput(v.getWindowToken());
}
if (countTimerView != null)
countTimerView.cancel(); //取消计时
timeStart=0;//将计时器置为0
break;
default:
if (countTimerView != null)
countTimerView.cancel(); //取消计时
timeStart=0;//将计时器置为0
break;
}
return super.dispatchTouchEvent(ev);
}
private boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] l = {0, 0};
v.getLocationInWindow(l);
int left = l[0], top = l[1], bottom = top + v.getHeight(), right = left
+ v.getWidth();
if (event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom) {
// Click on the EditText event and ignore it.
return false;
} else {
return true;
}
}
return false;
}
private void hideSoftInput(IBinder token) {
if (token != null) {
InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(token,
InputMethodManager.HIDE_NOT_ALWAYS);
}
}
//计时器的类
class CountTimer extends CountDownTimer {
private Context context;
public CountTimer(long millisInFuture, long countDownInterval, Context context) {
super(millisInFuture, countDownInterval);
this.context = context;
}
@Override
public void onFinish() {
showSessionDialog();//弹出对话框
}
@Override
public void onTick(long millisUntilFinished) {
}
//自定义对话框
private void showSessionDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
View view = LayoutInflater.from(context).inflate(R.layout.common_session_dialog, null);
try {
builder.setView(view);
TextView tvContent = (TextView) view.findViewById(R.id.tv_content);
Button btnOk = (Button) view.findViewById(R.id.btn_ok);
//Introducing a custom font style.
tvContent.setTypeface(Const.font300);
btnOk.setTypeface(Const.font700);
builder.setCancelable(false);
dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog2 = builder.show();
btnOk.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
GotoLoginActivity(context); //会话过期,要求用户直接登录
isDialogClose = 1;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private void GotoLoginActivity(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);//返回登录页面
AppManager.getInstance().finishOthersActivity(LoginActivity.class);
}
}
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {//屏幕亮起来
}
if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {//锁屏
}
if (Intent.ACTION_USER_PRESENT.equals(intent.getAction()) && isDialogClose == 0) {//解锁
showLockScreenDialog();//弹出对话框
}
}
};
private void showLockScreenDialog() {
if (count == 0) {
long timeEnd = new Date().getTime();
if (timeStart != 0 && timeEnd - timeStart >= 5 * 60 * 1000) {//5分钟会话过期
if (countTimerView != null) {
countTimerView.showSessionDialog();//弹出对话框
}
}
}
count++;
}
...
}
5.总结:在项目中已经实现了session会话过期四种场景的需求。欢迎大家围观,多多指教!