CC框架實踐(1):實現登陸成功再進入目標界面功能

在掘金上看到這篇文章:android 關於先登陸成功後再進入目標界面的思考,做者對實現登陸成功後再跳轉到目標界面功能做了比較詳細的分析,對比了一些已有的實現方案並指出存在的問題。最終,做者實現了一個可同時添加多個條件判斷攔截的方案,思路很新穎。java

這篇文章的閱讀量和喜歡數都不少,看來你們對這個需求的關注度很高,這裏將咱們在使用 CC框架 過程當中實現這個功能的方案跟你們分享一下。android

快速瞭解CC

  • 是一套基於組件總線的組件化實施方案
  • 一靜一動,開發時運行2個app,業務環境始終是完整的:
    • 靜:主App (經過跨App的方式調用單組件App內的組件)
    • 動:正在開發中的單組件App (經過跨App的方式調用主App內的組件)
  • 支持漸進式組件化改造
    • 解耦只是過程,而不是前提

CC框架基因中自帶支持組件層面的AOP

在定義組件時,實現IComponent.onCall(cc)方法,並根據cc中的參數來執行組件中的具體邏輯(如:頁面跳轉等)。git

能夠在調用具體邏輯以前對該功能進行AOP實現,例如:登陸、頁面數據預加載等github

用CC框架實現必須先登陸再進入目標頁面功能

目標頁面所在的組件在執行頁面跳轉前調用登陸組件(用戶中心組件)獲取用戶信息,若未登陸則登陸後返回用戶信息。app

這裏有2個點:
1. 若用戶已登陸,則直接返回用戶信息,同步方式實現便可
2. 若用戶未登陸,則跳轉到登陸頁面,須要執行完登陸操做(或取消)後才能得到結果,使用異步方式實現。
複製代碼

以打開訂單列表頁面前須要登陸爲例:框架

  1. 先定義用戶組件,提供一個強制獲取用戶登陸信息的功能,若未登陸則打開登陸界面,並在用戶登陸後返回登陸結果(取消登陸也是一種結果)
//用戶中心組件類
public class UserComponent implements IComponent {
    @Override
    public String getName() {
        return "demo.component.user";
    }

    @Override
    public boolean onCall(CC cc) {
        String actionName = cc.getActionName();
        // ... 
        // 強制獲取用戶信息,若未登陸則跳轉到登陸,並將登陸結果返回
        if ("forceGetLoginUser".equals(actionName)) {
            if (!TextUtils.isEmpty(Global.loginUserName)) {
                //已登陸同步實現,直接調用CC.sendCCResult(...)並返回返回false
                CCResult result = CCResult.success(Global.KEY_USERNAME, Global.loginUserName);
                CC.sendCCResult(cc.getCallId(), result);
                return false;
            }
            //未登陸,打開登陸界面,在登陸完成後再回調結果,異步實現
            Context context = cc.getContext();
            Intent intent = new Intent(context, LoginActivity.class);
            if (!(context instanceof Activity)) {
                //調用方沒有設置context或app間組件跳轉,context爲application
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            //將cc的callId傳給Activity,登陸完成後經過這個callId來回傳結果
            intent.putExtra("callId", cc.getCallId());
            context.startActivity(intent);
            //異步實現,不當即調用CC.sendCCResult,返回true
            return true;
        }
        //...
        return false;
    }

}
複製代碼
  1. 模擬的登陸頁面:點擊按鈕模擬登陸,直接返回文本框中的信息做爲登陸成功的信息,若未登陸直接返回,則視爲取消登陸
/** * 模擬登陸頁面 */
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText editText;
    private String callId;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.id.activity_login);
        callId = intent.getStringExtra("callId");
        //init views
    }

    @Override
    public void onClick(View v) {
        //模擬登陸:點擊按鈕獲取文本框內容並做爲用戶登陸信息返回
        String username = editText.getText().toString().trim();
        if (TextUtils.isEmpty(username)) {
            Toast.makeText(this, R.string.demo_b_username_hint, Toast.LENGTH_SHORT).show();
        } else {
            //登陸成功,返回
            Global.loginUserName = username;
            finish();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //判斷是否爲CC調用打開本頁面
        if (callId != null) {
            CCResult result;
            if (TextUtils.isEmpty(Global.loginUserName)) {
                result = CCResult.error("login canceled");
            } else {
                result = CCResult.success(Global.KEY_USERNAME, Global.loginUserName);
            }
            //爲確保無論登陸成功與否都會調用CC.sendCCResult,在onDestroy方法中調用
            CC.sendCCResult(callId, result);
        }
    }
}
複製代碼
  1. 在訂單組件中進行登陸驗證:登陸成功,則跳轉到訂單列表頁;登陸失敗,則返回調用失敗的結果
//訂單組件
public class OrderComponent implements IComponent {
    @Override
    public String getName() {
        return "demo.component.order";
    }

    @Override
    public boolean onCall(CC cc) {
        CCResult result = CC.obtainBuilder("demo.component.user")
                .setActionName("forceGetLoginUser")
                .build()
                .call();
        CCResult ccResult;
        // 根據登陸狀態決定是否打開頁面
        // 這裏也能夠添加更多的前置判斷邏輯
        if (result.isSuccess()) {
            ccResult = CCResult.success();
            //登陸成功,打開目標頁面
            startOrderListActivity(cc);
        } else {
            //登陸失敗,返回失敗信息
            ccResult = result;
        }
        //調用方不須要得到額外的信息,只須要知道調用狀態
        //因此這個組件採用同步實現:同步調用CC.sendCCResult(...) 而且返回false
        CC.sendCCResult(cc.getCallId(), ccResult);
        return false;
    }

    private void startOrderListActivity(CC cc) {
        Context context = cc.getContext();
        Intent intent = new Intent(context, OrderListActivity.class);
        if (!(context instanceof Activity)) {
            // context maybe an application object if caller dose not setContext
            // or call across apps
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        context.startActivity(intent);
    }
}
複製代碼

至此,打開訂單頁面必須登陸的功能已所有完成。異步

這樣實現的好處

  1. 登陸組件只管登陸自身的邏輯,跟其它邏輯徹底不耦合
  2. 調用訂單組件的地方無需添加額外的代碼
  3. 能夠添加任意的前置條件判斷
  4. 登陸條件的判斷可用於任意組件而無需修改登陸組件的邏輯
  5. 支持跨app組件調用時的前置條件判斷

瞭解更多關於CC框架的信息

Github源碼 ,持續維護更新中, 歡迎watch、fork、star、pr、提issueide

系列文章

CC:可關聯生命週期的android組件化開發框架組件化

CC框架實踐(1):實現登陸成功再進入目標界面功能post

CC框架實踐(2):Fragment和View的組件化

CC框架實踐(3): 讓jsBridge更優雅

相關文章
相關標籤/搜索