这篇文章没有高深的技术,只为实现简单需求。
在手机应用设计中,常常会碰到需要登录之后才能实现下一步操作这个需求。比如商城类应用,逛商城时,不需要登录,在购买商品时,如果用户尚未处于登录状态,则需要先登录然后进行购买。
So,问题来了。在用户点击了购买按钮时,需要进入下订单页,在进入之前,我们会判断用户是否处于登录状态,如果已登录,则直接进入,如果未登录,则进行登录。那么登录之后是直接进入下订单的页面还是返回当前页在点一次进入呢?
这里我们可以屡屡登录需求:
- 一般的用户登录行为,在成功处关闭当前页进入主页;
- 需要与用户账号相关的操作,需要进行登录,返回当前页;
- 需要与用户账号相关的操作,需要进行登录,直接进入下一页。
针对需求1,我们可以用如下代码实现:
private void loginSuccessCallback(){
Intent i = new Intent(this,MainActivity.class);
this.startActivity(i);
this.finish();
}
因为在同一个应用中不可能写两个登录页(一般登录一个,其他需求一个),所以,针对需求2,我们就会在需求1的代码处增加逻辑:
private void loginSuccessCallback(){
//其他逻辑省略。。。
//增加判断是否进入主页的逻辑
final boolean stepIntoMainPageOnly = getIntent().getBooleanExtra(Constants.stepIntoMainPageOnly, false);
if(stepIntoMainPageOnly){
Intent i = new Intent(this,MainActivity.class);
this.startActivity(i);
}
this.finish();
}
上述代码只要调起登录页面时,传入参数Constants.stepIntoMainPageOnly
为true
,则进入主页(当然也可以是设置密码之类的页面),为false
则仅仅关闭登录页,即登录成功返回当前页(需求2)。
如果只为实现需求1、2时,上面的代码完全可以满足,但是如果一个事情让用户重复做两次(上述购买需要登录时,如果返回当前页,用户需要点击两次购买,第一次判断未登录进入登录,第二次为登录成功后返回当前页,再次点击方可购买),那用户体验可不是一般的差了。
所以,需求3出来了。
Android
为需求3提供了完美的解决方案,下面是当前页调起登录页的逻辑:
Intent i = new Intent(this, LoginActivity.class);
this.startActivityForResult(i,Constants.REQUEST_CODE_LOGIN);
我们修改下登录成功处的代码逻辑
private void loginSuccessCallback(){
//其他逻辑省略。。。
//增加判断是否进入主页的逻辑
final boolean stepIntoMainPageOnly = getIntent().getBooleanExtra(Constants.stepIntoMainPageOnly, false);
if(stepIntoMainPageOnly){
Intent i = new Intent(this,MainActivity.class);
this.startActivity(i);
}
this.setResult(Constants.RESULT_CODE_LOGIN_SUCCESS);
this.finish();
}
然后调起登录的页面写添加如下逻辑:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if( requestCode==Constants.REQUEST_CODE_LOGIN && resultCode==Constants.RESULT_CODE_LOGIN_SUCCESS){
//TODO stop into next page.
}
}
上述代码可以完成需求3的需求。
我们来看看当前页(A)、登录页(L)和下一页(N)的流转关系如下
- A页判断需要用户登录 -> L页
- L页登录成功 -> 返回A页
- A页 -> 跳转 N页
A、L、N的流程
A->L->A->N
这个流程完全正确,但是为什么3个页面的流转必须要走回头路呢?就不能实现A->L->N的流转吗?
答案是肯定的。
我们先分析下,如果,从A页不经过L页进入N页,我们知道A的下一页是N,然后N又需要的参数,我们直接从A传给N。上述有两个关键点:
- N是目标
- N接收参数
如果L页知道A的目标及N的参数,那就不用回到A而直接从L进入N了。
那怎么才能让L知道A的目标是N呢?
天才的想法瞬间出现:
//调起登录
Intent i = new Intent(this,LoginActivity.class);
i.putExtra(Constants.TARGET_N,Constants.TARGET_N_VALUE);
i.putExtra(xxx, xxx);//N需要的参数
this.startActivity(this, i);
//登录成功
private void loginSuccessCallback(){
//其他逻辑省略。。。
//增加判断是否进入主页的逻辑
final boolean stepIntoMainPageOnly = getIntent().getBooleanExtra(Constants.stepIntoMainPageOnly, false);
if(stepIntoMainPageOnly){
Intent i = new Intent(this,MainActivity.class);
this.startActivity(this, i);
}else if(getIntent().getIntExtra(Constants.TARGET_N,-1) == Constants.TARGET_N_VALUE){
Intent i = new Intent(this, N.class);
i.putExtra(xxx, xxx);//N需要的参数
this.startActivity(i);
}
this.finish();
}
大功告成!
但是,如果有很多个类似的A!是不是将会导致L越来越臃肿呢?
如果,我们可以把N.class
和xxx
参数封装一层呢?
先考虑可行性,N.class
为Class<T>
类型数据,根据Class定义可知:
public final class Class<T> implements Serializable, AnnotatedElement, GenericDeclaration, Type
Class
实现Serializable
接口,可以进行参数的序列化传递!!
目前为止,结果已经很明显了,A可以将N.class
及其他数据封装成可序列化的对象,将该对象传递至L中,在L中登录成功后,再将N.class
从可序列化的对象中提取出来作为Intent
中的class
参数。
public static class Target<T extends Serializable> implements Parcelable {
public Class<? extends AppCompatActivity> target;
public T arguments;
public Target() {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(this.target);
dest.writeSerializable(this.arguments);
}
protected Target(Parcel in) {
this.target = (Class<? extends AppCompatActivity>) in.readSerializable();
this.arguments = (T) in.readSerializable();
}
public static final Creator<Target> CREATOR = new Creator<Target>() {
@Override
public Target createFromParcel(Parcel source) {
return new Target(source);
}
@Override
public Target[] newArray(int size) {
return new Target[size];
}
};
}
登录逻辑
private void loginSuccessCallback(){
final Target t = getIntent().getParcelableExtra(Constants.LOGIN_TARGET);
if( t==null ){
//普通登录,直接跳主页
}else{
Intent i = new Intent(this, t.target);
intent.putExtra(Constants.PARCELABLE_ARGUMENTS, target.arguments);
this.startActivity(i);
}
this.finish();
}
到此,需求3已经被至少两种方式实现了(当然还有其他方式),不能说哪种方式最好,看实际情况来自由选择,能实现需求的方法都是好方法,当然,没有最好,只有更好。
最后
第一次在简书上写文章,写的很乱,希望以后会比这个更好。当然也希望有些技术性的文章被自己以原创的方式发表出来。