打開頁面自動登錄并回來-攔截器

并行的路.png

這篇文章的實現(xiàn)略有侵入性,但不妨礙你對這方面的思考,更好的實現(xiàn)可以參考另外一篇文章

在App項目中有一些Activity是需要登錄成功后才能進去的,比如訂單詳情頁,因為訂單是跟賬號掛鉤的,登錄的賬號一般會有個ID,需要帶著ID和訂單號去查訂單信息。
很多剛開始做App的同學(xué)會認(rèn)為應(yīng)該在進入訂單詳情頁前先確保登錄成功,也就是說把登錄判斷和發(fā)起登錄都是進入訂單詳情頁前搞定,的確這么做沒有問題,但是恐怕體力活會很多吧,如果能理解攔截器的原理就可以簡化我們的工作量。


@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請求完整的訂單信息
    }
}

看到以上訂單詳情頁只要在Acitvity class之上加上一個登錄校驗的注解然后并在invoke()回調(diào)里執(zhí)行跟登錄相關(guān)的接口查詢及初始化頁面即可,這樣就不用關(guān)注登錄的實現(xiàn)細(xì)節(jié),一定程度上解耦了你的業(yè)務(wù)實現(xiàn)。
下面我們說說實現(xiàn)方式,當(dāng)然這里的Interceptor并不是純粹利用Java的語言的動態(tài)代理,這只是一種模仿,依附Activity的生命周期完成的:

  1. 定義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();
}

注:如果對Annotation不是很了解最好查閱下相關(guān)資料稍微了解下,這里就不過啰嗦了。

  1. 定義Interceptor父類的基本的結(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);
}

注:以上是每個攔截器需要實現(xià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());
    }
}
  1. 有攔截檢測功能的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;
                }
            }
        }
    }
}

注:
主要通過在onStart()進行對配置的攔截器進行檢查,一旦有攔截器不滿足條件就跳轉(zhuǎn)對應(yīng)的頁面(如登錄頁面)請求資源,當(dāng)資源請求獲取到后(登錄成功后)到了ActivityResult再校驗其他攔截器,如果配置了多個攔截器則當(dāng)所有的攔截器都被滿足條件后會觸發(fā)invoked()回調(diào)函數(shù)執(zhí)行, 所以需要類似登錄成功才能執(zhí)行的代碼就放在invoked()里好了。
當(dāng)然配置多個攔截器也很方便:

@InterceptWith({FirstInterceptor.class, SecondInterceptor.class, ThirdInterceptor.class})
public class XXXActivity extends InterceptorActivity
  1. 以上代碼除了LoginInterceptor.java是按業(yè)務(wù)定義的攔截器,其余都可以作為common模塊里的代碼或者library中的代碼,完整Demo源碼請參考Android Interceptor.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容