The Android client implements the function of session expiration

Foreword:

The project needs to implement the function of session expiration. After continuous debugging, this function is realized. Let me briefly summarize the function of implementing session expiration on the client side, I hope it will be helpful to everyone!

need:

The Session session expires, that is, when the 5-minute session expires, the user exits the application.
The following four situations require a pop-up dialog box to prompt:
1. The App is locked; 
2. The app is active and back to the App device; 
3. The App is inactive; 
4. The Refresh_token expires (processed in the interceptor, not here make an introduction).
The dialog has the style of an "OK" button, and clicking "OK" will return the user to the login page.

Ideas:

1. Implement this function in the BaseActivity base class, and other Activities can inherit BaseActivity.
2. When the App is initialized, use CountTimer to handle it.
3. When the App is locked or returned to the App device from other application activities, use BroadcastReceiver to handle it.
4. When the App is not active, rewrite the dispatchTouchEvent and handle it.
5. A dialog box will pop up to prompt you to use AlertDialog.

Implementation steps:

1. When the App application is initialized, add a CountTimer timer.

...
private CountTimer countTimerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
        ...
        //设置5分钟后会话过期 
        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. When the App locks or returns to the App device from other app activities, use BroadcastReceiver to handle it.

@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();
}


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. When the App is not active, rewrite the dispatchTouchEvent and handle it.

@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();//取消计时器
                break;

            default:
                if (countTimerView != null)
                    countTimerView.cancel();//取消计时器
                break;
        }
        return super.dispatchTouchEvent(ev);
}

4. Complete code implemented in BaseActivity.

public abstract class BaseActivity extends AppCompatActivity
        implements IUIOperation, BaseView {
    private ProgressDialog mPDialog;
    private CountTimer countTimerView;
    private AlertDialog dialog;
    private AlertDialog dialog2;
    public int count = 0;
    private long timeStart;
    private int isDialogClose = 0;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ...
        //5分钟会话过期   
        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();
    }

    
    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(); //取消计时
                break;

            default:
                if (countTimerView != null)
                    countTimerView.cancel(); //取消计时
                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. Summary: The four scenarios of session expiration have been implemented in the project. Welcome everyone to watch and give advice!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324897363&siteId=291194637