android 关于先登录成功后再进入目标界面的思考

文章讨论了如何优化任务逻辑,特别是CallUnit的实现,移除嵌套任务,以及提供一个简洁且符合业务场景的登录验证解决方案。作者还介绍了多种处理登录场景的思路,包括使用拦截器和Intent管理,最终提出自定义CallUnit数据模型以满足复杂的前置条件检查。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

另外收到部分朋友的反馈,任务逻辑处理的不够简洁。特此修改了第二版的实现。核心代码如下

ps:当时设计的一个初衷,是考虑到前置条件中可能会嵌套目标任务。但是现在想了很久,仍然没有想到可能的业务场景。既然技术是为业务存在,所以就取消了嵌套任务。如果有朋友有这样的场景,请告诉我。

/**

  • Created by jinyabo on 13/12/2017.
  • 如果CallUnit验证模型中没有嵌套的验证模型,则可以直接使用SingleCall即可
    */

public class SingleCall {

CallUnit callUnit = new CallUnit();

public SingleCall addAction(Action action){
clear();
callUnit.setAction(action);
return this;
}

public SingleCall addValid(Valid valid){
//只添加无效的,验证不通过的。
if(valid.check()){
return this;
}
callUnit.addValid(valid);
return this;
}

public void doCall(){

//如果上一条valid难没有通过,就直接返回
if(callUnit.getLastValid() != null && !callUnit.getLastValid().check() ){
return;
}

//执行action
if(callUnit.getValidQueue().size() == 0 && callUnit.getAction() != null){
callUnit.getAction().call();
//清空
clear();
}else{
//执行验证。
Valid valid = callUnit.getValidQueue().poll();
callUnit.setLastValid(valid);
valid.doValid();
}

}

public void clear(){
callUnit.getValidQueue().clear();
callUnit.setAction(null);
callUnit.setLastValid(null);
}

// 单一全局访问点
public static SingleCall getInstance() {
return SingletonHolder.mInstance;
}

// 静态内部类,第一次加载Singleton类时不会初始化mInstance,
// 当调用getInstance()时才会初始化
private static class SingletonHolder {
private static SingleCall mInstance = new SingleCall();
}
}

另外笔者本人也根据自己平时的业务需求,总结了如下几种应用场景。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里总结下,这样做的好处。

1、完全支持上面所有的情形。不用做特殊判断。

2、图中黄色区域,都在主界面所在的上下文中执行。逻辑就在当前界面,不会到无关界面中处理。做到了职责清晰。

3、调用起来更加简单。

如果介绍不清楚,请直接看代码。真的是比较简单的。

----------------------------这是分隔线--------------------------

项目中经常有遇到一个典型的需求,就是在用户在需要进入A界面的时候,需要先判断用户是否登录,如果没有登录,则需要先进入登录界面,如果登录成功了,再直接跳转到A界面。

需求定义

所以这里有两个需求: 1、自动跳转到登录界面 2、登录成功后再自动跳转到目标A界面

如果我们直接判断用户有没有登录,提醒用户登录。也没有让用户登录成功后再直接跳转到目标界面,这样的用户体验恐怕是不能满足一个高逼格程序员的要求。那么,我们来思考下,如何才能更加优雅的完成这个工作呢?

当然,在开始之前,我们可以先了解下其他人都是怎么做的,毕竟我们可以站在巨人的肩膀上才能看得更远。

思考可行的方案

首先我们第一个想到的解决方式,就是拦截器。如果我们在进入A界面的时候,可以在操作之前加入一个拦截器的话,岂不是可以做到在进入A界面前的判断呢?

在google之后,找到两个方案。

A、 Android拦截器 (可以点击查看)

此方案通过注解。在进入目标界面A时,判断是否有指定的拦截器,如果有,则检验是否满足拦截器要求,不满足,则执行拦截器的处理,处理完成后,通过onActivityResult最后触发invoke的回调方法。

此方案和我们需求略有不同,那么说下此方案存在的缺点: 1、用了继承的方式,来插入invoke的回调方法。由于java的单继承的特性,如果工程中已经有基类的情况,调整起来比较麻烦。侵入性太高。

2、此方案中,在没有登录的情况下,其实已经进入了目标A页面。相应的初始化都已经执行了。如果没有登录成功,这样工作其实是白做了。如果目标A界面要登录才能进入的话,此方案不符合要求的。

B、我们直接使用路由框架,参考下阿里的ARouter方案,可以看到,我们可以在固定路由上面插入拦截器。这里有一篇文章介绍 阿里ARouter拦截器使用及源码解析

看了文章后,发现拦截器实现的非常优雅,但是依然不是我们想要的。因为这个拦截器执行完后,马上会执行目标方法。中间并不会等待。所以我们根本没有办法去执行我们的登录操作。 所以pass了。

我们再回过头来思考,拦截器似乎并不能直接完成我们的需求,因为我们需要插入一个验证行为后(例如进入登录界面),还要执行相应的操作后,保证这个验证行为通过后,才能真正进入到我们的目标界面。

其实如果我们只是单纯的完成这个功能的话,可能大家最容易想到的就是,在进入登录界面的时候,在intent中装载一个目标target的intent.如果登录成功了,就判断是否有目标target,如果有,就跳转到目标target.

Intent intent = new Intent(this,LoginActivity.class);
Intent target = new Intent(this,OrderDetailActivity.class);
intent.putExtra(“target”,target);
startActivity(intent);

这种方式做起来非常直接,也可理解,但是最明显的问题就是,会导致登录界面多了很多与自己无关的业务判断。那我们继续google看看,有没有类似的做法,并且实现优雅一点的呢?

Android 登录判断器,登录成功后帮你准确跳转到目标activity 这篇的访问量比较大,似乎是个比较靠谱的方法。我们来大概分析下它的做法。

public static void interceptor(Context ctx, String target, Bundle bundle, Intent intent) {
if (target != null && target.length() > 0) {
LoginCarrier invoker = new LoginCarrier(target, bundle);
if (getLogin()) {
invoker.invoke(ctx);
} else {
if (intent == null) {
intent = new Intent(ctx, LoginActivity.class);
}
login(ctx, invoker, intent);
}
} else {
Toast.makeText(ctx, “没有activity可以跳转”, 300).show();
}
}

private static void login(Context context, LoginCarrier invoker, Intent intent) {
intent.putExtra(mINVOKER, invoker);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
context.startActivity(intent);
}

我们看上面的核心代码就是,封装一个LoginCarrier。如果没有登录,则把这个LoginCarrier传入到登录界面。登录成功后,触发invoke()方法。本质上和我们上面的想法差不多。

看完之后,还是觉得实现上不够完美,总觉得有些缺点。例如

1、在登录界面还是侵入了过多的逻辑(这似乎不可避免,但是否可以简洁些呢)

2、扩展性比较差。比方说我要购买某个礼品,需要登录,然后再跳转到充值界面充值完成后再回来。

那到底有没有更好的实现方案呢,谷歌后,发现暂时没有找到可靠的方案了,所以说靠天靠地,不如靠自己,既然找不到合适的方案,那就好好思考下,自己动手来干了。

首先,我们再回过头考虑我们的需求,我们需要执行一个目标方法。但是目标方法需要一个前置的条件满足才能执行,并且这个前置条件可能不只一个,还有就是这个前置条件并不是马上就能完成的。

那我们根据需求抽象出来的数据模型应该是。

public class CallUnit {
//目标行为
private Action action;
//先进先出验证模型
private Queue validQueue = new ArrayDeque<>();
//上一个执行的valid
private Valid lastValid;

}

那么目标行为action就是一个执行体。负责执行目标方法。

public interface Action {
void call();
}

验证操作validQueue保存一个验证队列,Valid的验证模型是

public interface Valid {

/**

  • 是否满足检验器的要求,如果不满足的话,则执行doValid()方法。如果满足,则执行目标action.call
  • @return
    */
    boolean check();
    //去执行验证前置行为,例如跳转到登录界面。(但并未完成验证。)
    void doValid();
    }

那么整个逻辑用一幅图表达出来,会比较清楚。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来根据图,来讲解代码实现。

第一步,我们需要构造一个CallUnit单元。例如,我们需要跳转到折扣界面,前置是我们必须要登录,并且要有折扣码。

所以这里,我们有两个验证模型,一个是登录,一个是拿到折扣。

public class DiscountValid implements Valid {
private Context context;

public DiscountValid(Context context) {
this.context = context;
}

/**
*

  • @return
    */
    @Override
    public boolean check() {
    return UserConfigCache.isDiscount(context);
    }

/**

  • if check() return false. then doValid was called
    */
    @Override
    public void doValid() {
    DiscountActivity.start((Activity) context);
    }
    }

public class LoginValid implements Valid {
private Context context;

public LoginValid(Context context) {
this.context = context;
}

/**

  • check whether it login in or not
  • @return
    */
    @Override
    public boolean check() {
    return UserConfigCache.isLogin(context);
    }

/**

  • if check() return false. then doValid was called
    */
    @Override
    public void doValid() {
    LoginActivity.start((Activity) context);
    }
    }

然后我们需要构造一个执行体。直接在当前的Activity里面实现Action接口即可。例如我们在MainActivity中实现。

@Override
public void call() {
//这是我们的目标行为
OrderDetailActivity.startActivity(MainActivity.this, “1234”);
}

接下来,我们就可以构造一个CallUnit对象并进行执行了。

CallUnit.newInstance(MainActivity.this)
.addValid(new LoginValid(MainActivity.this))
.addValid(new DiscountValid(MainActivity.this))
.doCall();

我们来看看doCall到底做了什么?

public void doCall(){
ActionManager.instance().postCallUnit(this);
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

推荐学习资料

  • Android进阶学习全套手册

  • Android对标阿里P7学习视频

  • BAT TMD大厂Android高频面试题

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

推荐学习资料

  • Android进阶学习全套手册

    [外链图片转存中…(img-rIRUHqnc-1713017018771)]

  • Android对标阿里P7学习视频

    [外链图片转存中…(img-csNMz3wL-1713017018772)]

  • BAT TMD大厂Android高频面试题

[外链图片转存中…(img-PP22fjKZ-1713017018772)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值