在掘金上看到這篇文章:android 關於先登陸成功後再進入目標界面的思考,做者對實現登陸成功後再跳轉到目標界面功能做了比較詳細的分析,對比了一些已有的實現方案並指出存在的問題。最終,做者實現了一個可同時添加多個條件判斷攔截的方案,思路很新穎。java
這篇文章的閱讀量和喜歡數都不少,看來你們對這個需求的關注度很高,這裏將咱們在使用 CC框架 過程當中實現這個功能的方案跟你們分享一下。android
在定義組件時,實現IComponent.onCall(cc)方法,並根據cc中的參數來執行組件中的具體邏輯(如:頁面跳轉等)。git
能夠在調用具體邏輯以前對該功能進行AOP實現,例如:登陸、頁面數據預加載等github
目標頁面所在的組件在執行頁面跳轉前調用登陸組件(用戶中心組件)獲取用戶信息,若未登陸則登陸後返回用戶信息。app
這裏有2個點:
1. 若用戶已登陸,則直接返回用戶信息,同步方式實現便可
2. 若用戶未登陸,則跳轉到登陸頁面,須要執行完登陸操做(或取消)後才能得到結果,使用異步方式實現。
複製代碼
以打開訂單列表頁面前須要登陸爲例:框架
//用戶中心組件類
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;
}
}
複製代碼
/** * 模擬登陸頁面 */
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);
}
}
}
複製代碼
//訂單組件
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);
}
}
複製代碼
至此,打開訂單頁面必須登陸的功能已所有完成。異步
Github源碼 ,持續維護更新中, 歡迎watch、fork、star、pr、提issueide