当前位置: 首页 > news >正文

Android 通过自定义注解实现Activity间跳转时登录路由的自动拦截

应用场景

在Android 中部分软件需要登录才能使用,但是有的页面又不需要登录,Android不同于Web可以直接拦截重定向路由,因此如果在Android中如果需要检测是否登录,如果没登录跳转登录的话就需要再每个页面中判断,当然也可以写成公共方法,但是这样的方式还是比较麻烦。这里讲一个自定义注解实现这个需求的方法

编写注解

先直接编写一个注解

@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME) //运行时有效
public @interface NeedLogin {/*** 开关,可以不需要,但是我觉得还有有比较好,看个人需求,默认为不开启检测是否登录*/boolean enable() default false;
}

编写公共代码

我们可以再onStart生命周期中进行检测:是否启用注解是否登录,记得写在BaseActivity中,这样后面继承BaseActivity时方法自动生效,在需要登录拦截的Activity中只需要添加一个注解就可以实现自动拦截、登录、回显!
是否启动注解:这里需要一点自定义注解的理论知识,请自行学习

    private boolean isNeedLogin() {// 通过反射或注解处理器获取当前 Activity 是否需要登录boolean isAnnotation = getClass().isAnnotationPresent(NeedLogin.class);if (!isAnnotation) {return false;}NeedLogin needLogin = getClass().getAnnotation(NeedLogin.class);if (needLogin == null) {return false;}return needLogin.enable();}

是否登录:这个没任何讲解的,你是使用SharedPreferences还是MMKV还是别的存储登录信息都可以无所谓,简单写个示例:

    private boolean checkLogin() {// 检查登录状态的逻辑,true代表已登录,false代表未登录return !errorService.isLogin();}

然后在onStart生命周期方法中进行检测

    @Overrideprotected void onStart() {super.onStart();if (errorService == null) {return;}//不包含注解或者登录注解未开启if (!isNeedLogin()) {return;}//已登录,则跳转登录if (!checkLogin()) {return;}//TODO 这里可以跳转登录了}

提出疑问

  1. 如果想登录成功后再回调这个页面然后刷新页面怎么实现?
  2. 跳转页面的时候是否可以保持原参数的传递
  3. 登录页怎么写

问题解决

思考问题

如果想跳转回来肯定需要告知登录页我当前页面的路径,那么我们跳转登录的时候就必须要传递过去,那么我们定义一个参数存储这个当前页面路径TARGET_ACTIVITY

    /*** 跳转目标Activity页面,目前用于自动检测登录的作用*/public static final String TARGET_ACTIVITY = "targetActivity";

那么我稍微修改下跳转登录,修改完善一下上面的onStart

    @Overrideprotected void onStart() {super.onStart();if (errorService == null) {return;}//不包含注解或者登录注解未开启if (!isNeedLogin()) {return;}//已登录,则跳转登录if (!checkLogin()) {return;}//如果未登录跳转登录并且把当前页的信息传递过去,以便于登录后回传Bundle bundle = getIntent().getExtras();if (bundle == null) {bundle = new Bundle();}bundle.putString(ConstantsHelper.TARGET_ACTIVITY, getClass().getName());errorService.toLogin(this, bundle);//就是一个简单的Intent跳转finish();}

完善登录页面代码

简单思考一下我们再登录页需要跳转到哪几个目标页:首页指定目标页返回上一页
那么我们编写几个接口方法

public interface UserView extends BaseView {/*** 直接返回上个页面*/void toLast();/*** 是否有需要跳转的目标页面* @return true有目标页面*/boolean hasTarget();/*** 跳转到目标页面,结合hasTarget使用*/void toTarget();/*** 跳转到主页*/void toMain();/*** 关闭键盘*/void hideKeyboard();
}

我们在登录页实现接口,然后模拟下登录操作

点击登录

    public MutableLiveData<UserInfo> getLiveData() {return liveData;}//点击按钮触发的方法,仅用于模拟public void loginClick(View v, RequestLoginBean requestLoginBean, String password) {int id = v.getId();if (id == R.id.login_submit) {if (StringUtil.isEmpty(requestLoginBean.getUsername())) {baseView.showToast( "请填写用户名");return;}if (StringUtil.isEmpty(password)) {baseView.showToast(  "请填写密码");return;}try {requestLoginBean.setPassword(MD5Util.md5Encode(password));} catch (Exception e) {e.printStackTrace();baseView.showToast("密码加密异常");}
//            iRepository.login(requestLoginBean, liveData);//模拟登录情况baseView.showLoading("正在登录,请稍后...");UserAccountHelper.setToken("this is token !!!");UserAccountHelper.setRefreshToken("this is refresh_token !!!");UserInfo userInfo = new UserInfo() {{setId("1");setAvatar("https://img2.baidu.com/it/u=2948556484,2204941832&fm=253&fmt=auto&app=120&f=JPEG?w=655&h=436");setEmail("fzkf3318@163.com");setName("张三");setPhone("15210230000");setRealName("张韶涵");setRoleName("演员");setSex(1);}};new Handler(Looper.getMainLooper()).postDelayed(() -> {baseView.hideLoading();liveData.setValue(userInfo);}, 3000);}}

LoginActivity中监听liveData

mViewModel.getLiveData().observe(this, userInfo -> mViewModel.loginCallback(userInfo, binding.userEdit.getText().toString()));//mViewModel中public void loginCallback(UserInfo userInfo, String userName) {//存储登录信息和登录状态UserAccountHelper.saveLoginState(userInfo, true);//这里只是判断本地账号和上次账号是否为同一个,如果不是同一个则不能继续之前操作,则需要返回App首页刷新,并且同事判断下当前app是不是只有当前登录页一个页面if (TextUtils.isEmpty(userName) || !userName.equals(UserAccountHelper.getAccount()) ||AppManager.getAppManager().getActivityStack().size() == 1) {UserAccountHelper.saveAccount(userName);//打开MainActivitybaseView.toMain();return;}//存储本地登录的账号UserAccountHelper.saveAccount(userName);if (baseView.hasTarget()) {baseView.toTarget();return;}baseView.toLast();}

现在完善一下LoginActivity

 @SuppressLint("UnsafeIntentLaunch")@Overridepublic void toLast() {showToast("登录成功!");setResult(RESULT_OK, getIntent().putExtras(bundle));finish();}@Overridepublic boolean hasTarget() {String targetActivity = bundle.getString(ConstantsHelper.TARGET_ACTIVITY);if (TextUtils.isEmpty(targetActivity)) {return false;}try {//是否报错,不报错说明目标页面存在Class.forName(targetActivity);return true;} catch (ClassNotFoundException e) {return false;}}@Overridepublic void toTarget() {String targetActivity = bundle.getString(ConstantsHelper.TARGET_ACTIVITY);if (TextUtils.isEmpty(targetActivity)) {toLast();return;}try {//是否报错,不报错说明目标页面存在Intent intent = new Intent(this, Class.forName(targetActivity));intent.putExtras(bundle);startActivity(intent);finish();} catch (ClassNotFoundException e) {toLast();}}@Overridepublic void toMain() {showToast("登录成功!");AppManager.getAppManager().finishAllActivity();startActivity(errorService.getMainActivity());}

编写案例测试效果

编写一个页面

@NeedLogin(enable = true)
@AndroidEntryPoint
public class TargetActivity extends BaseActivity<EmptyViewModel, ActivityTargetBinding> {public final static String ARGS = "ARGS";@Overrideprotected int getLayoutId() {return R.layout.activity_target;}@Overridepublic String setTitleBar() {return "测试登录拦截";}@Overridepublic void initView(Bundle savedInstanceState) {binding.buttonLogin.setOnClickListener(v-> errorService.toLogin(this));}@Overridepublic void initData(Bundle bundle) {String args = bundle.getString(ARGS);binding.tvArgs.setText(TextUtils.isEmpty(args) ? "暂无参数" : args);}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data></data><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".activity.TargetActivity"><TextViewandroid:id="@+id/tv_args"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="@color/auto_color"android:textSize="@dimen/font_18"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><Buttonandroid:id="@+id/button_login"android:text="前往登录"android:textColor="@color/auto_color"android:textSize="@dimen/font_18"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toBottomOf="@+id/tv_args"android:layout_width="wrap_content"android:layout_height="wrap_content"/></androidx.constraintlayout.widget.ConstraintLayout>
</layout>

效果图在这里插入图片描述

完结

代码地址
https://github.com/fzkf9225/mvvm-componnent-master/blob/master/app/src/main/java/com/casic/titan/demo/activity/TargetActivity.java

相关文章:

Android 通过自定义注解实现Activity间跳转时登录路由的自动拦截

应用场景 在Android 中部分软件需要登录才能使用&#xff0c;但是有的页面又不需要登录&#xff0c;Android不同于Web可以直接拦截重定向路由&#xff0c;因此如果在Android中如果需要检测是否登录&#xff0c;如果没登录跳转登录的话就需要再每个页面中判断&#xff0c;当然也…...

安全开发指南

1. 准备工作与培训 安全文化与意识&#xff1a;建立并强化组织的安全文化&#xff0c;对所有成员进行安全意识培训。安全策略与标准&#xff1a;制定明确的安全开发策略、标准和流程&#xff0c;包括代码审查、安全测试、事件响应等。工具与技术选择&#xff1a;选择合适的开发…...

【word脚注】双栏设置word脚注,脚注仅位于左栏,右栏不留白

【word脚注】双栏设置word脚注&#xff0c;脚注仅位于左栏&#xff0c;右栏不留白 调整前效果解决方法调整后效果参考文献 调整前效果 调整前&#xff1a;脚注位于左下角&#xff0c;但右栏与左栏内容对其&#xff0c;未填充右下角的空白区域 解决方法 备份源文件复制脚注内…...

ROS学习笔记(三):VSCode集成开发环境快速安装,以及常用扩展插件配置

文章目录 前言VSCode集成开发环境1 安装VSCode2 VSCode扩展插件2.1 VSCode扩展插件模块介绍2.1 常用扩展插件配置一、语言支持类插件二、智能辅助类插件三、科学计算与数据分析类插件四、ROS开发相关插件 3 总结相关链接 前言 关于Ubuntu与ROS的常规安装&#xff0c;可以看这几…...

论文精读--Two-Stream Convolutional Networks for Action Recognition in Videos

对于单张图片&#xff0c;丢进卷积和全连接层直接得出分类结果就行 但对于视频&#xff0c;早期的一些工作把视频中的一些关键帧抽取出来&#xff0c;把一个个帧通过网络&#xff0c;最后把结果合并&#xff0c;或者把帧叠起来&#xff0c;一起丢进网络。在网络中进行early fu…...

JAVA姓氏头像情侣头像家庭头像签名头像谐音顽埂头像设计小程序头像大全系统小程序源码

姓氏头像到谐音梗&#xff0c;打造你的专属头像大全系统 &#x1f3a8;✨ &#x1f468;‍&#x1f469;‍&#x1f467;‍&#x1f466; 家庭头像&#xff1a;记录温馨瞬间 在这个充满爱的时代&#xff0c;用一张家庭头像来记录你和家人的美好瞬间吧&#xff01;我们的“姓氏…...

UE5.4.3 Replay 重播回放系统

工程的配置文件DefaultEngine.ini中需要加入 +NetDriverDefinitions=(DefName=“DemoNetDriver”,DriverClassName=“/Script/Engine.DemoNetDriver”,DriverClassNameFallback=“/Script/Engine.DemoNetDriver”) 此步骤将启用并加载DemoNetDriver .ini添加示例 [/Script/En…...

深入掌握 Protobuf 与 RPC 的高效结合:实现C++工程中的高效通信

目录 一、Protobuf与RPC框架的通信流程概述二、Protobuf与RPC在C中的实际应用2.1 定义 .proto 文件2.2 编译 .proto 文件生成C代码2.3 实现服务器端逻辑2.4 实现客户端逻辑2.5 使用CMake构建工程2.6 编译与运行2.7 关键组件解析2.8 序列化与反序列化的实现 三、关键实现与解析四…...

录屏软件大比拼:四款必备工具助你轻松录制精彩瞬间!

哎呀&#xff0c;说到电脑录屏这事儿&#xff0c;我这个办公室小文员可是深有体会啊&#xff01;平时工作里&#xff0c;经常需要录个会议啊、做个教程啊&#xff0c;或者分享个操作技巧给同事们看。市面上的录屏软件多得数不清&#xff0c;但我最常用的几款工具。今天就来跟大…...

计算机毕业设计宠物领养网站我的发布领养领养用户信息/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序

目录 1.课题背景 2.课题意义 ‌ 3.技术介绍 4.技术性需求 4.1后端服务‌&#xff1a; 4.2 前端展示‌ 5.数据库设计‌&#xff1a; 6.系统性能‌&#xff1a; 7.安全性‌&#xff1a; 8. 功能介绍&#xff1a; 9. 部分代码 1.课题背景 近年来&#xff0c;随着宠物饲养数量…...

用示波器测动态滞回线

大学物理&#xff08;下&#xff09;实验-中南民族大学通信工程2022级 手动逐个处理数据较为麻烦且还要绘图&#xff0c;故想到用pythonmatplotlib来计算结果并数据可视化。 代码实现 import matplotlib.pyplot as plt# 样品一磁化曲线 X [0, 0.2, 0.4, 0.6, 0.8, 1, 1.5, 2.…...

【JDK动态代理】JDK动态代理:为何只能代理接口和接口实现类

在Java开发中&#xff0c;JDK动态代理是一种非常有用的技术&#xff0c;它允许开发者在不修改目标类代码的情况下&#xff0c;为目标类添加额外的功能。然而&#xff0c;JDK动态代理的使用有一些限制&#xff0c;特别是它只能代理接口和接口实现类。本文将深入探讨这一限制的原…...

MFC工控项目实例二十一型号选择界面删除参数按钮禁用切换

承接专栏《MFC工控项目实例二十手动测试界面模拟量输入实时显示》 对于禁止使用的删除、参数按钮&#xff0c;在选中列表控件选项时切换为能够使用。 1、在TypDlg.h文件中添加代码 #include "ShadeButtonST.h" #include "BtnST.h" class CTypDlg : publi…...

前端框架对比和选择指南

前端框架对比和选择指南 随着 Web 开发技术的快速发展&#xff0c;前端框架已经成为了现代 Web 开发的核心工具之一。它们为开发人员提供了快速构建高效、交互性强的应用的基础。当前流行的前端框架主要包括 React.js、Vue.js 和 Angular.js。在这篇技术博客中&#xff0c;我们…...

人工智能价格战——如何降低成本让人工智能更易于普及

十年前&#xff0c;开发人工智能 (AI) 是只有大公司和资金充足的研究机构才能负担得起的事情。必要的硬件、软件和数据存储成本非常高。但从那时起&#xff0c;情况发生了很大变化。一切始于 2012 年的 AlexNet&#xff0c;这是一种深度学习模型&#xff0c;展示了神经网络的真…...

企业间图文档发放:如何在保障安全的同时提升效率?

不管是大型企业&#xff0c;还是小型创业公司&#xff0c;不论企业规模大小&#xff0c;每天都会有大量的图文档发放&#xff0c;对内传输协作和对外发送使用&#xff0c;数据的生产也是企业业务生产力的体现之一。 伴随着业务范围的不断扩大&#xff0c;企业与客户、合作伙伴之…...

深入解析 ConcurrentHashMap:从 JDK 1.7 到 JDK 1.8

✨探索Java基础 ConcurrentHashMap✨ 引言 ConcurrentHashMap 是 Java 中一个线程安全的高效 Map 集合。它在多线程环境下提供了高性能的数据访问和修改能力。本文将详细探讨 ConcurrentHashMap 在 JDK 1.7 和 JDK 1.8 中的不同实现方式&#xff0c;以及它们各自的优缺点。 …...

VS code user setting 与 workspace setting 的区别

VS code user setting 与 workspace setting 的区别 引言正文引言 相信有不少开始接触 VS code 的小伙伴会有疑问,user setting 与 workspace setting 有什么区别呢?这里我们来说明一下 正文 首先,当我们使用 Ctrl + Shift + P 打开搜索输入 setting 后,可以弹出 4 个se…...

XPath基础知识点讲解——用于在XML中查找信息的语言

1. 什么是XPath&#xff1f; XPath&#xff08;XML Path Language&#xff09;是用于在XML&#xff08;Extensible Markup Language&#xff09;文档中查找信息的语言。它可以通过路径表达式来选择XML文档中的节点&#xff0c;类似于如何在文件系统中使用路径查找文件。XPath是…...

Visual Studio 2022

VS&#xff08;Visual Studio&#xff09;是一款由微软开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;用于开发应用程序、网站以及移动应用等。VS的历史可以追溯到1997年&#xff0c;当时发布了第一个版本的VS。以下是VS的一些重要历史里程碑&#xff1a; Visual …...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...