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

news2024/11/17 9:38:07

应用场景

在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生命周期方法中进行检测

    @Override
    protected 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

    @Override
    protected 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);
            //打开MainActivity
            baseView.toMain();
            return;
        }
        //存储本地登录的账号
        UserAccountHelper.saveAccount(userName);
        if (baseView.hasTarget()) {
            baseView.toTarget();
            return;
        }
        baseView.toLast();
    }

现在完善一下LoginActivity

 @SuppressLint("UnsafeIntentLaunch")
    @Override
    public void toLast() {
        showToast("登录成功!");
        setResult(RESULT_OK, getIntent().putExtras(bundle));
        finish();
    }

    @Override
    public 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;
        }
    }

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

    @Override
    public 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";

    @Override
    protected int getLayoutId() {
        return R.layout.activity_target;
    }

    @Override
    public String setTitleBar() {
        return "测试登录拦截";
    }

    @Override
    public void initView(Bundle savedInstanceState) {
        binding.buttonLogin.setOnClickListener(v-> errorService.toLogin(this));
    }

    @Override
    public 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.ConstraintLayout
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".activity.TargetActivity">

        <TextView
            android: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" />
        <Button
            android: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2169866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不会写SD WebUI 的负面提示词?用这几款Embedding模型一键搞定!效果好到爆炸!

文章目录 一、Embedding 模型简介二、负面提示词 Embedding三、Embedding 资源下载四、Embedding 安装与使用关于AI绘画技术储备零基础AI绘画学习资源介绍&#x1f449;stable diffusion新手0基础入门PDF&#x1f448;&#x1f449;AI绘画必备工具&#x1f448;&#x1f449;AI…

MySQL重点,面试题

一、 聚合函数 分类 COUNT&#xff1a;统计行数量SUM&#xff1a;获取单个列的合计值AVG&#xff1a;计算某个列的平均值MAX&#xff1a;计算列的最大值MIN&#xff1a;计算列的最小值 二、SQL关键字 分页&#xff1a;limit SELECT * FROM student limit 100,6; 倒序 desc s…

数据结构 ——— 移除 nums 数组中的 val 元素(快慢指针)

目录 题目要求 代码实现&#xff08;快慢指针&#xff09; 题目要求 编写函数&#xff0c;给你一个数组 nums 和一个值 val&#xff0c;你需要在 nums 数组 原地 移除所有数值等于 val 的元素&#xff0c;并且返回移除后数组的新长度 不能使用额外的数组空间&#xff0c;要…

11.全面学习面向对象技术

面向对象开发 相关概念 对象&#xff1a;由数据及其操作所构成的封装体&#xff0c;是系统中用来描述客观事务的一个实体&#xff0c;是构成系统的一个基本单位。一个对象通常可以由对象名、属性和方法3个部分组成。类&#xff1a;现实世界中实体的形式化描述&#xff0c;类…

MySQL_插入、更新和删除数据

课 程 推 荐我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448;入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448;虚 拟 环 境 搭 建 &#xff1a;&#x1…

如何禁止电脑蓝牙?五个有效方法教给你!小白必看!

在生活和工作中&#xff0c;蓝牙是一种非常方便的无线技术&#xff0c;可以连接鼠标、键盘、耳机等设备。 然而&#xff0c;蓝牙同时也是信息泄露的潜在渠道&#xff0c;特别是在公共场所或公司内部环境中&#xff0c;可能会带来安全隐患。 想要保护隐私或防止电脑与未经授权…

基于YOLOv8目标检测与chef-transformer(T5)从图像创建食谱

前言 在本文中&#xff0c;将演示如何使用从Roboflow获得的开源产品数据来训练我的YOLOv8模型&#xff0c;然后将其与从Hugging Face获得的chef-transformer&#xff08;T5&#xff09;模型集成。应用程序的主要目标是将检测到的对象参数化地发送到语言模型&#xff0c;并在NL…

第05-3节:加载流程原理介绍(Done)

我的后端学习大纲 我的Linux学习大纲 本节目标 1.能够说出交互式Shell与非交互式Shell2.能够说出登录Shell与非登录Shell环境 1.1.Shell工作环境介绍 用户进入linux系统就会初始化Shell环境, 这个环境会加载全局配置文件和用户个人配置文件中环境变量.每个脚本文件都有自己的…

STM32嵌入式编程学习到提高:【4】UART串口打印

------------------------------------------------------------------------------------------------------------------------- 工程文件&#xff1a;放在百度云盘里&#xff0c;需要的自行下载&#xff01;&#xff01;&#xff01; 链接: https://pan.baidu.com/s/14gRne…

2万字长文助你快速入门AIGC:包含底层原理、应用场景、热门工具、行业现状…

最近大家热议的ChatGPT和AI绘画工具的底层技术原理是什么&#xff1f;是如何发展到现在的&#xff1f;有哪些应用场景、热门工具&#xff1f;AIGC产业上下游有哪些公司&#xff1f;作为普通用户&#xff0c;我们还能接触哪些应用AI技术打造的商业解决方案&#xff1f;…… 我们…

RK 方案VOP 显示接口的链接关系以及DTS如何配置

这图显示各vp 支持情况 如下图VP0 支持DSI0 DSI1 EDP LVDS HDMI 显示接口&#xff0c;如果我们一方案需要点MIPI 屏 和HDMI out, 如果VP0 链接MIPI DSI0 那么VP0 就不能再选择了&#xff0c;只能VP1 链接HDMI out 了。因为VP2不至此HDMI&#xff0c;所有就只有选择VP1 链接HDMI…

随记——机器学习

前言 本来有个500块钱的单子&#xff0c;用机器学习做一个不知道什么鸟的识别&#xff0c;正好有数据集&#xff0c;跑个小项目&#xff0c;过一下机器学习图像识别的流程&#xff0c;用很短的时间记录下来..... 一、数据预处理 将数据集分为训练集和测试集&#xff0c;直接…

【HarmonyOS】SaveButton保存图片

SaveButton组件把图片显示到相册中的方法demo&#xff0c;支持组件截图、url网络图片、base64格式图片。注意事项&#xff1a; 1、不支持自定义SaveButton样式。 2、下载按钮被遮挡一部分&#xff0c;也无法保存到相册。 import photoAccessHelper from ohos.file.photoAcces…

使用 pypdf 给 PDF 添加目录书签

""" dir.txt的形式 第1章 计算机系统基础知识 1 1.1 嵌入式计算机系统概述 1 1.2 数据表示 4 1.2.1 进位计数制及转换 4 1.2.2 数值型数据的表示 6 第2章 嵌入式系统硬件基础知识 56 2.1 数字电路基础 56 2.1.1 信号特征 56 2.1.2 组合逻辑电路和时序逻辑电路 5…

为什么现在的网站设计大多都非常简洁,越来越扁平化

网站设计趋向简洁和扁平化&#xff0c;反映了现代设计理念的转变和技术的进步。以下是对这一现象的具体分析&#xff1a; 用户体验优先&#xff1a;用户更倾向于简单直接的界面&#xff0c;这有助于快速找到所需信息。扁平化设计通过减少视觉干扰&#xff0c;使得内容更加突出…

哪些因素会影响六西格玛效果的显现时间?

在探讨哪些因素会影响六西格玛效果的显现时间时&#xff0c;我们不得不深入剖析六西格玛管理方法的本质及其在企业中的实施过程。六西格玛作为一种旨在通过减少缺陷和变异来提高产品和服务质量的策略&#xff0c;其成功实施并非一蹴而就&#xff0c;而是受到多种复杂因素的共同…

Llama 系列简介与 Llama3 预训练模型推理

1. Llama 系列简介 1.1 Llama1 由 Meta AI 发布&#xff0c;包含 7B、13B、33B 和 65B 四种参数规模的开源基座语言模型 数据集&#xff1a;模型训练数据集使用的都是开源的数据集&#xff0c;总共 1.4T token 模型结构&#xff1a;原始的 Transformer 由编码器&#xff08…

Git 与远程分支

90.远程仓库和分支 我们经常需要对远程仓库里的分支进行更新。 ‍ 当从远程库 clone 时&#xff0c;默认情况下&#xff0c;只会拉取 master ​分支&#xff0c;并且会将本地的 master 分支和远程的 master 分支关联起来&#xff1a; $ git branch * master‍ ‍ 推送本地…

什么是分布式缓存,它是如何工作的?

嗨&#xff0c;你好啊&#xff0c;我是猿java 在日常开发中&#xff0c;我们经常会使用到缓存&#xff0c;当数据集较小时&#xff0c;通常将所有缓存数据保存在一台服务器上就足够了&#xff0c;但是当数据集较大时&#xff0c;我们需要将缓存数据分布在多个服务器上&#xf…

无线领夹麦克风怎么挑选?选购麦克风需要注意的五大选购陷阱!

无线领夹麦克风只所以成为现在自媒体行业的主流拾音设备&#xff0c;很大程度取决于它的轻巧的设计以及便携性。相较于传统的手持麦克风&#xff0c;领夹麦在使用时无需手持&#xff0c;直接佩戴在衣领上即可使用&#xff0c;腾出的双手可以更好的投入到录制当中&#xff0c;在…