這篇文章的實(shí)現(xiàn)略有侵入性,但不妨礙你對(duì)這方面的思考宴猾,更好的實(shí)現(xiàn)可以參考另外一篇文章酌住。
在A(yíng)pp項(xiàng)目中有一些Activity是需要登錄成功后才能進(jìn)去的,比如訂單詳情頁(yè)刃麸,因?yàn)橛唵问歉~號(hào)掛鉤的醒叁,登錄的賬號(hào)一般會(huì)有個(gè)ID,需要帶著ID和訂單號(hào)去查訂單信息泊业。
很多剛開(kāi)始做App的同學(xué)會(huì)認(rèn)為應(yīng)該在進(jìn)入訂單詳情頁(yè)前先確保登錄成功把沼,也就是說(shuō)把登錄判斷和發(fā)起登錄都是進(jìn)入訂單詳情頁(yè)前搞定,的確這么做沒(méi)有問(wèn)題吁伺,但是恐怕體力活會(huì)很多吧饮睬,如果能理解攔截器的原理就可以簡(jiǎn)化我們的工作量。
@InterceptWith(LoginInterceptor.class)
public class OrderDetailActivity extends InterceptorActivity {
private static final String EXTRA_ORDER_ID = "orderId";
private TextView mOrderInfoText;
private String mOrderId;
public static void startActivity(Context context, String orderId) {
Intent intent = new Intent(context, OrderDetailActivity.class);
intent.putExtra(EXTRA_ORDER_ID, orderId);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order_detail);
mOrderId = getIntent().getStringExtra(EXTRA_ORDER_ID);
mOrderInfoText = (TextView) findViewById(R.id.orderInfo);
}
@Override
protected void invoked() {
super.invoked();
mOrderInfoText.setText("訂單信息(order id: " + mOrderId + ")");
// 根據(jù)orderId請(qǐng)求完整的訂單信息
}
}
看到以上訂單詳情頁(yè)只要在A(yíng)citvity class之上加上一個(gè)登錄校驗(yàn)的注解然后并在invoke()回調(diào)里執(zhí)行跟登錄相關(guān)的接口查詢(xún)及初始化頁(yè)面即可篮奄,這樣就不用關(guān)注登錄的實(shí)現(xiàn)細(xì)節(jié)捆愁,一定程度上解耦了你的業(yè)務(wù)實(shí)現(xiàn)割去。
下面我們說(shuō)說(shuō)實(shí)現(xiàn)方式,當(dāng)然這里的Interceptor并不是純粹利用Java的語(yǔ)言的動(dòng)態(tài)代理昼丑,這只是一種模仿呻逆,依附Activity的生命周期完成的:
- 定義Annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface InterceptWith {
/**
* @return a Interceptor class array (must have a constructor without parameters inside)
*/
Class<? extends Interceptor>[] value();
}
注:如果對(duì)Annotation不是很了解最好查閱下相關(guān)資料稍微了解下,這里就不過(guò)啰嗦了菩帝。
- 定義Interceptor父類(lèi)的基本的結(jié)構(gòu):
public abstract class Interceptor {
/**
* Request code used to start activity for result.
*
* @return request code
*/
public abstract int getRequestCode();
/**
* Check interceptor's condition is meet or no.
*
* @param context Android context
* @return condition is meet or no
*/
public abstract boolean isSatisfied(Context context);
/**
* if condition was not satisfied, it'll be called to acquire resource or permission and so on.
*
* @param activity see {@link Activity}
*/
public abstract void process(Activity activity);
}
注:以上是每個(gè)攔截器需要實(shí)現(xiàn)的抽象父類(lèi)咖城,以下以登錄校驗(yàn)的攔截器舉例:
public class LoginInterceptor extends Interceptor {
@Override
public int getRequestCode() {
return LoginActivity.REQUEST_CODE_LOGIN;
}
@Override
public boolean isSatisfied(Context context) {
return UserConfigCache.isLogin(context);
}
@Override
public void process(Activity activity) {
LoginActivity.startActivityForResult(activity, getRequestCode());
}
}
- 有攔截檢測(cè)功能的Activity:
public class InterceptorActivity extends AppCompatActivity {
private List<Interceptor> mInterceptors = new ArrayList<>();
/**
* Called only when all interceptors verified OK,
* so do your work here which all interceptors are passed.
*/
protected void invoked() {
}
@Override
protected void onStart() {
super.onStart();
if (mInterceptors.size() == 0) {
scanInterceptors();
verifyInterceptors();
}
}
private void scanInterceptors() {
mInterceptors.clear();
InterceptWith annotation = getClass().getAnnotation(InterceptWith.class);
if (annotation != null) {
Class<? extends Interceptor>[] classes = annotation.value();
for (Class<? extends Interceptor> clazz : classes) {
try {
mInterceptors.add(clazz.newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private void verifyInterceptors() {
if (mInterceptors.isEmpty()) {
return;
}
for (int i = 0; i < mInterceptors.size(); i++) {
Interceptor interceptor = mInterceptors.get(i);
if (interceptor.isSatisfied(this)) {
if (i == mInterceptors.size() - 1) {
invoked();
break;
}
} else {
interceptor.process(this);
break;
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (Interceptor interceptor : mInterceptors) {
if (interceptor.getRequestCode() == requestCode) {
if (resultCode == RESULT_OK) {
verifyInterceptors();
break;
} else if (resultCode == RESULT_CANCELED) {
finish();
break;
}
}
}
}
}
注:
主要通過(guò)在onStart()進(jìn)行對(duì)配置的攔截器進(jìn)行檢查,一旦有攔截器不滿(mǎn)足條件就跳轉(zhuǎn)對(duì)應(yīng)的頁(yè)面(如登錄頁(yè)面)請(qǐng)求資源胁附,當(dāng)資源請(qǐng)求獲取到后(登錄成功后)到了ActivityResult再校驗(yàn)其他攔截器酒繁,如果配置了多個(gè)攔截器則當(dāng)所有的攔截器都被滿(mǎn)足條件后會(huì)觸發(fā)invoked()回調(diào)函數(shù)執(zhí)行, 所以需要類(lèi)似登錄成功才能執(zhí)行的代碼就放在invoked()里好了。
當(dāng)然配置多個(gè)攔截器也很方便:
@InterceptWith({FirstInterceptor.class, SecondInterceptor.class, ThirdInterceptor.class})
public class XXXActivity extends InterceptorActivity
- 以上代碼除了LoginInterceptor.java是按業(yè)務(wù)定義的攔截器控妻,其余都可以作為common模塊里的代碼或者library中的代碼州袒,完整Demo源碼請(qǐng)參考Android Interceptor.