Android登录拦截器实现方式

我们在使用应用时肯定遇到过这样的情景,打开应用,并不是需要我们登录,你可以浏览应用中的大部分页面,但是当你想看某个详情页的时候,点击后突然跳转到了登录页面,好,我们输入账号密码,点击登录,登录成功,跳转到了我们想看的详情页。

这一切看似很正常,但是有个关键点,就是当我们登录成功后能跳转到相应的详情页,我们正常的思维是登录成功后,在登录页面去做处理,写跳转,但是当你的应用有多个地方需要判断登录,登录成功后要跳转到各不相同的页面的时候,假如你还把跳转至各个页面的逻辑写在登录页面里,那么你的登录页面就会变得复杂起来,维护的成本就会越来越大。

通常的做法是先判断登录与否,如果没有登录,得先去登录,然后从登录页返回后在onActivityResult中再执行相应的跳转

思来想去,参考网上的思路终于找到了一种好的解决方式,就是当我们点击某个按钮需要判断登录的时候我们可以写一个登录判断器来判断是否登录,判断器携带一个登录载体,假如已登录就直接跳转到相应的目标Activity,假如没有登录就跳转到登录页面去登录,同时把登录载体传到登录Activity,登录成功后,在调用登录载体的相应方法直接跳转到目标Activity。好了,大体思路就是这样,下面我们来看看登录判断器到底做了些什么,还有就是什么是登录载体。

首先下面是登录判断器的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.example.tool;  

import com.example.login.LoginActivity;
import com.example.login.MainActivity;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

/**
* 登录判断类
*
* @author bzl
*
*/
public class LoginInterceptor {
public static final String mINVOKER = "INTERCEPTOR_INVOKER";

/**
* 判断处理
*
* @param ctx
* 当前activity的上下文
* @param target
* 目标activity的target
* @param params
* 目标activity所需要的参数
* @param intent
* 目标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();
}
}

/**
* 登录判断
*
* @param ctx
* 当前activity的上下文
* @param target
* 目标activity的target
* @param params
* 目标activity所需要的参数
*/
public static void interceptor(Context ctx, String target, Bundle bundle) {
interceptor(ctx, target, bundle, null);
}

// 这里获取登录状态,具体获取方法看项目具体的判断方法
private static boolean getLogin() {
return MainActivity.is_login;
}

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

不难看出当我们跳转到目标activity的时候只需要在方法里调用interceptor(Context ctx, String target, Bundle bundle)方法就可以具体如下:

1
2
3
4
5
6
7
8
/* 
* 跳转到目标activity页面
*/
public void starIntent(View v) {
Bundle bun = new Bundle();
bun.putString("Type", "login test");
LoginInterceptor.interceptor(this, "com.example.logininterceptor.SecondActivity", bun);
}

这里面需要三个参数依次是,当前activity的上下文,AndroidManifest.xml中目标activity的下自定义的action,还有就是需要传进目标activity的参数我们使用Bundle传递。可以看出来我们登陆成功后跳转使用的事隐式Intent。结合代码来看进入到interceptor方法后,首先把关于目标activity的一些数据存放在登录载体LoginCarrier这个类中,然后判断是否登录,假如没有登录择跳转到登录activity去登陆并且将登录载体传到登录activity,假如已经登录择直接执行登录载体中的invoke();方法跳转到目标activity。好了,看一下登录载体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.example.tool;  

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;

/**
* 登录器载体
*
* @author bzl
*
*/
public class LoginCarrier implements Parcelable {
public String mTargetAction;
public Bundle mbundle;

public LoginCarrier(String target, Bundle bundle) {
mTargetAction = target;
mbundle = bundle;
}

/**
* 目标activity
*
* @param ctx
*/
public void invoke(Context ctx) {
Intent intent = new Intent(mTargetAction);
if (mbundle != null) {
intent.putExtras(mbundle);
}
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
ctx.startActivity(intent);
}

public LoginCarrier(Parcel parcel) {
// 按变量定义的顺序读取
mTargetAction = parcel.readString();
mbundle = parcel.readParcelable(Bundle.class.getClassLoader());
}

@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}

@Override
public void writeToParcel(Parcel parcel, int flags) {
// 按变量定义的顺序写入
parcel.writeString(mTargetAction);
parcel.writeParcelable(mbundle, flags);
}

public static final Parcelable.Creator<LoginCarrier> CREATOR = new Parcelable.Creator<LoginCarrier>() {

@Override
public LoginCarrier createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new LoginCarrier(source);
}

@Override
public LoginCarrier[] newArray(int arg0) {
// TODO Auto-generated method stub
return new LoginCarrier[arg0];
}
};
}

登录器载体代码看着很多,其实仔细看他就是一个通过Parcelable方式序列化的一个实体类。我们来看重点看invoke(Context ctx)方法,很简单就是一个隐式跳转,直接跳转到目标activity,刚才在登录判断器中interceptor方法中判断已经登录的话则调用这个方法跳转到目标activity,没有登录的话跳转到登录界面并将登录器载体传过去,登录做的 东西很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private Handler handler = new Handler() {  
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:// 登录成功
invoker = (LoginCarrier) getIntent().getParcelableExtra(LoginInterceptor.mINVOKER);
invoker.invoke(LoginActivity.this);
finish();
break;

default:
break;
}
};
};

/*
* 点击登录,这个方法模拟登录成功直接发送消息
*/
public void login(View v) {
MainActivity.is_login = true;
/**
*
* do something to login
*/
handler.sendEmptyMessage(0);
}

可以看到在login方法中模拟登录成功后,我们获取登录器载体,同时执行登录载体中的invoke方法跳转到目标activity,然后在目标activity接收需要的参数,这里就不贴代码了。至此登录判断器的使命完成,以后我们就可以不用再将登录成功后的逻辑写到登录页面了。

另外,还有一种需求就是我在当前页面有些操作需要登录后才能进行,比如,收藏,评论功能。我们必须登录成功后才能收藏那么怎么办?很简单,我们可以将interceptor(Context ctx, String target, Bundle bundle, Intent intent)方法中的target传递当前activity的action然后并且在Bundle中携带一个标志,当登录成功后这个标志会回传到当前activity,在当前activity我们可以使用onNewIntent方法来接收刚刚携带的参数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/** 
* 当你登录成功接收到你传递出去的标志后可以做一些当前页面更新操作
*/
@Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
text.setText("终于登录成功 " + intent.getExtras().getString("intentMyself"));
}

/**
* 在这里点击登录后还是跳转到这个页面,当然传值的话会在onNewIntent方法中回传回来
*
* @param v
*/
public void login(View v) {
Bundle bun = new Bundle();
bun.putString("intentMyself", "可以进行收藏的操作了");
LoginInterceptor.interceptor(this, "com.example.logininterceptor.ThirdActivity", bun);
}

是不是也很方便。好了,关于登录判断器的东西差不多就这些,具体内容查看附件。如果大家感觉这个登录判断器有更好的方式或者在这个方式上有拓展的地方欢迎提出大家的想法。

附件下载

参考:Android登录拦截器实现方式
Android 登录判断器,登录成功后帮你准确跳转到目标activity