原來Activity跳轉還可以這么舒暢

原創(chuàng)博客,如有轉載,請注明出處,非常感謝。

(前置說明,我這里所說的POJO,就是大家認為的POJO去掉了getter/setter)
這里給大家?guī)淼氖且粋€開源項目,托管在github上的:SmartKey,喜歡的同學請給個星星鼓勵一下,非常感謝。祝愿大家寫代碼寫得越來越舒暢,下班越來越準時。

在開源世界索取了這么多年,終于第一次往開源界添點小小的磚瓦,甭提有多高興了,先預覽一下demo代碼感受一下,你見過這樣startActivity的嗎?不寫key,不寫Intent,不寫putExtra,不寫XXXActivity.class;不寫key,不寫Intent,不寫putExtra,不寫XXXActivity.class;不寫key,不寫Intent,不寫putExtra,不寫XXXActivity.class;重要的事情我要說三遍,別攔我:

我有一個Activity,名字叫ForResultActivity,跳轉到他的時候是這樣調(diào)用的:

// Demo on how to elegantly passing and receiving extras with intent.
SmartTargets.toForResultActivityATarget()
        .params(ForResultReqIBuilder
                .newBuilder()
                .title(App.getStr(R.string.input_something))
                .label(App.getStr(R.string.this_is_label))
                .hint(App.getStr(R.string.this_is_hint)))
        .goForResult(activity, REQ_CODE_FOR_RESULT);

在目標ForResultActivity里獲取傳過來的參數(shù)(其實是ForResultVM類里,因為Demo里用了最簡單原始的MVVM模式)

// Getting values in this very easy way
ForResultReq req = ForResultReqIBuilder.getSmart(activity.getIntent());

** 套路就是SmartTargets出發(fā),to目標,帶參數(shù),走起!一個鏈條一氣呵成。 **
以上代碼里,SmartTargets類是自動生成的,F(xiàn)orResultReqIBuilder類也是自動生成的?。?!你只需要關注你的業(yè)務數(shù)據(jù),參數(shù)究竟怎么放進Intent 的,Intent是哪里創(chuàng)建的,extras的key怎么管理的,目標Activity的class什么時候放進Intent的,或者action,category什么時候放進Intent的,extras取出來又是怎么取的,有完沒完啊,這么多問題!?。『昧?,在這里,這些東西通通不需要關注,真的,你只需要關注你的業(yè)務數(shù)據(jù),并且,對于已有的代碼已有的key管理,你可以保留,這個庫直接與原有代碼兼容,無痛升級有木有!

好了,啰嗦了這么久,咱們詳細說說這個SmartKey吧,首先得從我們最初是怎么進行Activity跳轉說起,先講點歷史,憶苦思甜嘛,必須的。相信大家一定走過類似的路。
皇上,您還記得那年大明湖畔的夏雨荷嗎?哦,不好意思,大家還記得最初學Android開發(fā)的時候怎么啟動一個新的Activity嗎?來,上代碼:

Intent in = new Intent(this, ForResultActivity.class);
in.putExtra("title", App.getStr(R.string.input_something));
in.putExtra("label", App.getStr(R.string.this_is_label));
in.putExtra("hint", App.getStr(R.string.this_is_hint));
startActivityForResult(in, REQ_CODE_FOR_RESULT);

大家還想回到那個年代么?那個年代我想回,但是我不想再寫這樣的代碼了
putExtra這樣的模板代碼能不能不寫?
extra的key能不能不寫?看到這樣的“Magic Number/String”我就發(fā)毛,香菇,藍瘦。
就算寫,這些key從哪里找阿?每次去目標Activity翻么?萬一我拷貝的時候拷漏了一個字母怎么辦?好害怕啊。我真試過一個"nickName"和"nickname"這樣的拼寫問題,浪費了不少時間,不要笑,說的就是你。
于是來了第一個升級版(putExtra還是寫,畢竟通過Intent傳參你只有這么一條路可走):
在ForResultActivity的最頭部,我寫了以下的代碼:

public static final String EXTRA_TITLE = "title";
public static final String EXTRA_LABEL = "label";
public static final String EXTRA_HINT = "hint";

然后啟動ForResultActivity的時候變成了:

Intent in = new Intent(this, ForResultActivity.class);
in.putExtra(ForResultActivity.EXTRA_TITLE, App.getStr(R.string.input_something));
in.putExtra(ForResultActivity.EXTRA_LABEL, App.getStr(R.string.this_is_label));
in.putExtra(ForResultActivity.EXTRA_HINT, App.getStr(R.string.this_is_hint));
startActivityForResult(in, REQ_CODE_FOR_RESULT);

拼寫錯誤問題解決了,隨著項目的擴大,問題又來了,我在MyActivity,YourActivity,HisActivity等等幾個Activity都用到同樣的key,我每個Activity都抄一次public static final String EXTRA_XXX嗎?相信沒誰這么笨的。還有,有些activity的啟動是通過action的,天啊,這些通過action跳轉的隱式Intent傳參key應該放哪里?于是,又一個升級版,這次是集中管理extra的key:

public class MyExtraKeys {
    public static final String EXTRA_TITLE = "title";
    public static final String EXTRA_LABEL = "label";
    public static final String EXTRA_HINT = "hint";
    // 更多省略
}

key的問題解決的差不多了,隱式action的問題,這個也好解決,參照前面的MyExtraKeys的做法,我寫了一個MyActionUtils類,因為跟上面接近,就不復述了,無非是通過一個相對友好的,容易調(diào)用的字段對應到action。
下一步,我相信是很多高級點的工程師喜歡的做法,就是把跳轉的方法定義成一個靜態(tài)的方法,并且把參數(shù)組裝都放在目標Activity上面,有多種方法的時候,寫多個類似的方法:

public static void toForResultActivity(Context from, String title, String label, String hint) {
    Intent in = new Intent(from, ForResultActivity.class);
    in.putExtra(MyExtraKeys.EXTRA_TITLE, title);
    in.putExtra(MyExtraKeys.EXTRA_LABEL, label);
    in.putExtra(MyExtraKeys.EXTRA_HINT, hint);
    if(!(from instanceof Activity)) {
        in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    }
    from.startActivity(in);
}
// 如果還有其他,繼續(xù)寫

一般情況,到這一步,大家也就滿意了,然而,對于我,我還是覺得我高興的太早,因為我的項目終于大到一定程度了,并且也不止我一個人寫,由于經(jīng)過一段時間的積累,也由于對隊友的約束不嚴,技術也在變化,剛才解決的是參數(shù)傳進來問題,但是還是有各種取出的方法散落在各處,這個時候哪怕一丁點的改動,都需要小心翼翼,什么時候掉進自己挖的坑被埋了都不清楚,于是重構提上日程,既然這些傳來傳去的參數(shù)已經(jīng)散落在了各自發(fā)揮作用的角落,我能不能先把他們集中起來作為重構的第一階段呢?
于是,有一個升級版的參數(shù)傳遞方案出來了,把參數(shù)打包起來傳遞:

public class ForResultExtras implements Parcelable {
    private String title;
    private String label;
    private String hint;
    
    // getters and setters ...
    // Parcelable implementation methods ...
}

這種方式使用就統(tǒng)一了,不再有那么多的key了,因為都是一個類傳過來,每個組件都只接收一個自定義的參數(shù),于是MyConstants里面關于參數(shù)的key只剩下了:

        public static final String EXTRA_KEY = "extra"; // 作為最通用的了

然而,這個方案有天生的問題,既然取出參數(shù)的方法原來已經(jīng)散落各處了,現(xiàn)在要集中起來容易么?特別是我得寫多少個類似的Parcelable框架性代碼的實現(xiàn)???每個集中的類都必須寫網(wǎng)parcel里寫數(shù)據(jù)和讀數(shù)據(jù)的方法,還幾乎一樣的,還要讀寫順序一致。當然了,這些都是小問題了,github上搜索一下parceler你就知道了,有人幫你寫好了包裝,你只要寫POJO就行,剩余的框架代碼就不需要操心了。然而,集中起來這個問題沒辦法解決啊,與framework組件、第三方組件不能改的代碼怎么打交道???這個方案還沒真正使用一次,就直接被斃掉了,難道就無解了么?不可能?。。〉亲约鹤鲋笆遣皇菃枂枂“陀袥]有什么好方案先呢?還真給我找到了一個非常不錯的方案:
就是這個文章:用最優(yōu)雅的方式startActivity
具體就不列出來了,大家自己點開看看,學習一下,人家寫的很好,當然,如果他的方案真的解決了我的問題,那么就沒有這篇文章了,我寫這篇文章是因為他的方案并不能完成我需要解決的問題而已,不是說他寫的不好,相反,我覺得相當好也給我不少啟發(fā),我的寫的方案SmartKey也多少受到他的一些影響,當然,跟他的方案可以說完全不同,先說說為我用上面那個文章說的AutoGo的經(jīng)驗吧,這個庫第一眼看到我就眼前一亮,以為終于找到完美的解決方案了,然后翻看源碼,不錯,著手引入到我的項目里,好了,不到三個鐘,我發(fā)現(xiàn)很多跟我項目八字不合的問題了,簡單說來解決不了的問題有以下,改成疑問的語氣來寫吧:

  1. 我原有的代碼怎么辦?我已經(jīng)有上百個activity了,與原有方式能共存么?也就是說,我有些extra的獲取是散落在各處的,一下子要集中并且取到字段里不容易,由于項目緊,一下子抽不出時間全改怎么辦?其實時間是借口,主要問題是原邏輯非常復雜,貿(mào)然修改風險大,能緩一下,新寫的跳轉進來的代碼用新的方式寫,但是目標activity不改動行么?這個問題沒解決。
  2. 跳轉到安卓framework提供的組件,或者第三方庫提供的組件,他們的key我改不了,他們的類也是現(xiàn)成的,所以也生成不了方法鏈,怎么辦?這個問題沒解決。
  3. 有些activity我需要用action來跳轉,但我也想要用這個便利的方法鏈該怎么辦?一樣解決不了,因為他的注解需要寫在目標Activity上,用action本來就是為了不明確知道目標Activity的隱式情況的。
  4. 有些activity的跳轉,事先是不知道activity類名的,是根據(jù)服務器返回或其他配置值定的,我還是想用這個方法鏈怎么辦?還是沒有解決方法,因為跳轉鏈條的開頭就在目標Activity。
  5. AutoGo有代管SharedPreferences的方法,但是不靈活,每個字段必須要注解,并且調(diào)用AutoGo.save和AutoGo.restore方法的時候,對應對象的所有被托管的SharedPreferences都會被保存或者獲取,我能只保存更改了的那個么?或者只獲取我想要的那個么?畢竟多余的執(zhí)行都是浪費資源啊。其實Intent也有同樣的問題,需要把全部用到的需要傳遞字段注解,并且基本上幾個Activity有同樣參數(shù)的時候,必須寫幾份,也就是說寫的代碼不能復用。
  6. 因為SharedPreferences并沒有集中管理,散落在各個使用的角落,key重復了怎么辦?有方法自動檢測出來么?答案是沒辦法知道,因為誰也不知道你的key重復是場景需要還是錯誤。

好吧,自己試試能不能造個輪子,這個輪子需要解決以上所有問題,并且至少要和AutoGo一樣用的順暢,不但Activity的跳轉,SharedPreferences的問題也要一并解決了。
于是針對上面的問題,擼起袖子Code,先提前說一說SmartKey的使用套路:
SmartTargets開始,然后調(diào)用to目標Activity/Service,然后調(diào)用params方法放參數(shù),這個params方法使用的參數(shù)類是自動生成的IBuilder類,方法鏈式調(diào)用非常舒暢,然后調(diào)用對應的go、goForResult、goWithAction方法或者start方法或者bind方法結尾,整個過程一條鏈,一氣呵成。

  1. 另外設計一個入口,不再依賴目標Activity上面做改動,這樣就避免了改動時必須在跳轉開始和目標上都同時要做的問題了,那么,另外的入口通過什么東西來生成比較方便呢?AndroidManifest文件是所有Activity都需要在這里注冊的,好,我就從這里入手去生成對應的跳轉代碼!然后對于extra的問題,我另外用一個POJO來處理這個問題,看代碼:
@SmartManifest(manifestPath = "app/src/main/AndroidManifest.xml")
public class App extends Application {
    // App的其他代碼,
}

根據(jù)上面代碼,我可以生成一個SmartTargets的類,里面有所有Activity和Service的入口,每當要跳轉或者啟動Service的時候,就從SmartTargets出發(fā),一直點到目標,另外,再設計了兩個toNotDeterminedActivityTarget和toNotDeterminedServiceTarget方法給SmartTargets類,這樣,無論怎樣的Activity和Service都可以過去了。
對于POJO,以一直作為例子的ForResultActivity為例,我寫了兩個,一個是為了請求過來的時候傳遞參數(shù)的,一個是為了onActivityResult用的,兩個類代碼如下:

@SmartIntent
public class ForResultReq {
    public String title;
    public String label;
    public String hint;
}
@SmartIntent
public class ForResultRes {
    public String input;
    public String input2;
}

然后根據(jù)這兩個類,APT工具自動生成兩個對應的類,F(xiàn)orResultReqIBuilder和ForResultResIBuilder,使用方式就簡單了,注意到兩個類的注解么?對,只要加上這樣的注解,代碼就會自動生成,跳轉代碼(重復一次開頭那段代碼,_):

SmartTargets.toForResultActivityATarget()
        .params(ForResultReqIBuilder
                .newBuilder()
                .title(App.getStr(R.string.input_something))
                .label(App.getStr(R.string.this_is_label))
                .hint(App.getStr(R.string.this_is_hint)))
        .goForResult(activity, REQ_CODE_FOR_RESULT);

接收參數(shù)代碼:

ForResultReq req = ForResultReqIBuilder.getSmart(activity.getIntent());

在ForResultActivity的返回時,這樣返回:

BackResult
        .newBackResult()
        .params(ForResultResIBuilder
                .newBuilder()
                .input(input)
                .input2(input2))
        .finishWithResult(activity);

BackResult是我設計的另外一個助手類,專門為了在activity返回參數(shù)的時候用的,非常的簡單舒暢,上面的IBuilder類生成后的代碼,看一個吧,連他的接口和父類一并列出了(去掉了注釋,請直接看SmartKey):

// 接口,已經(jīng)寫好,不需要關注
public interface IntentKeyMapper {
    Intent buildIntent();
}
// 父類,已經(jīng)寫好,有一些比較方便的共用方法可以直接使用,在生成的IBuilder類里使用
public abstract class BaseIntentKeyMapper<B, S> implements IntentKeyMapper {
    protected S smart;
    public S getSmart() {
        return smart;
    }
    public B replaceSmart(@NonNull S smart) {
        if(smart == null)
            throw new RuntimeException("Smart wrapper object should not be null.");

        this.smart = smart;
        return (B) this;
    }
    public abstract B fillFromSource(Intent source);
    public B fillFromSource(Bundle source) {
        if (source == null) return (B) this;
        return fillFromSource(new Intent().putExtras(source));
    }
    public Bundle buildBundle() {
        return buildIntent().getExtras();
    }
}
// 然后就是生成的類了
// req
public final class ForResultReqIBuilder extends BaseIntentKeyMapper<ForResultReqIBuilder, ForResultReq> {
  public ForResultReqIBuilder() {
    smart = new ForResultReq();
  }
  public static ForResultReqIBuilder newBuilder() {
    return new ForResultReqIBuilder();
  }
  public static ForResultReqIBuilder newBuilder(ForResultReq fromSource) {
    return new ForResultReqIBuilder().replaceSmart(fromSource);
  }
  public static ForResultReq getSmart(Intent source) {
    return new ForResultReqIBuilder().fillFromSource(source).getSmart();
  }
  public static ForResultReq getSmart(Bundle source) {
    return new ForResultReqIBuilder().fillFromSource(source).getSmart();
  }
  @Override
  public Intent buildIntent() {
    Intent in = new Intent();
    in.putExtra("title", smart.title);
    in.putExtra("label", smart.label);
    in.putExtra("hint", smart.hint);
    return in;
  }
  public ForResultReqIBuilder fillFromSource(Intent source) {
    if (source == null) { return this; }
    smart.title = source.getStringExtra("title");
    smart.label = source.getStringExtra("label");
    smart.hint = source.getStringExtra("hint");
    return this;
  }
  public ForResultReqIBuilder title(String value) {
    smart.title = value;
    return this;
  }
  public ForResultReqIBuilder label(String value) {
    smart.label = value;
    return this;
  }
  public ForResultReqIBuilder hint(String value) {
    smart.hint = value;
    return this;
  }
}
// res
public final class ForResultResIBuilder extends BaseIntentKeyMapper<ForResultResIBuilder, ForResultRes> {
  public ForResultResIBuilder() {
    smart = new ForResultRes();
  }
  public static ForResultResIBuilder newBuilder() {
    return new ForResultResIBuilder();
  }
  public static ForResultResIBuilder newBuilder(ForResultRes fromSource) {
    return new ForResultResIBuilder().replaceSmart(fromSource);
  }
  public static ForResultRes getSmart(Intent source) {
    return new ForResultResIBuilder().fillFromSource(source).getSmart();
  }
  public static ForResultRes getSmart(Bundle source) {
    return new ForResultResIBuilder().fillFromSource(source).getSmart();
  }
  public Intent buildIntent() {
    Intent in = new Intent();
    in.putExtra("input", smart.input);
    in.putExtra("input2", smart.input2);
    return in;
  }
  public ForResultResIBuilder fillFromSource(Intent source) {
    if (source == null) { return this; }
    smart.input = source.getStringExtra("input");
    smart.input2 = source.getStringExtra("input2");
    return this;
  }
  public ForResultResIBuilder input(String value) {
    smart.input = value;
    return this;
  }
  public ForResultResIBuilder input2(String value) {
    smart.input2 = value;
    return this;
  }
}

注意,以上所有代碼都不需要你寫,你只要寫你的POJO和使用他們,上面的兩個POJO我起名字一個叫ForResultReq, 另外一個是ForResultRes,帶上Req和Res的目的是為了自己看方便,表明一個是為了傳遞數(shù)據(jù)用的,一個是為返回數(shù)據(jù)用,參照HTTP請求的做法而已,這里POJO類的起名沒有任何要求,只要是Java類,直接使用public字段,對于android,一般情況下,還是這樣更省CPU時間和內(nèi)存資源,能省就省吧,對于一般的POJO,并不存在問題。對于遺留key問題,如果目標activity不想改,那么簡單,直接把對應字段標注一下,說明key是啥就行了,比如:

// 標注的字段
@Key(Intent.EXTRA_TEXT)
    public String text;
// 對應生成的代碼
in.putExtra("android.intent.extra.TEXT", smart.text);
smart.text = source.getStringExtra("android.intent.extra.TEXT");

這樣一來目標activity可以不做任何修改,入口可以是全新的了。

  1. 對于framework或者第三方庫的兼容問題,跟前面遺留的key管理一樣,只需要一個標注@Key(系統(tǒng)或庫提供的key),就這樣愉快的兼容了。
  2. 還是在第1點上說的,你的Action都會在manifest上面聲明,所以@SmartManifest(manifestPath = "app/src/main/AndroidManifest.xml")可以知道這些所有信息,直接生成了對應的goWithAction/goForResultWithAction方法。
  3. NotDeterminedActivityTarge和NotDeterminedServiceTarget兩個類專門處理這樣的問題,出發(fā)點也是SmartTargets,有對應的toNotDeterminedActivityTarge/NotDeterminedServiceTarget方法。
    5和6. 對于SharedPreferences,集中管理,并且使用一個POJO類進行配置,java的字段不允許重復,有重復字段直接編譯不通過?。。【瓦@樣,key重復的問題一定不會出現(xiàn),并且每個字段有各自的get/set方法,get就是從SharedPreferences獲取,set就是保存到SharedPreferences,至于key,忘掉吧,我會另外寫一個博客文章專門介紹SharedPreferences的管理,相關的博客文章即將完成了。

說了這么多,咱么開始具體看看SmartKey提供了什么和怎么用吧。由于本人試了一大圈,注冊了一大堆帳號,還是未能發(fā)布到mavencentral,所以,用起來有點麻煩,需要大家拷貝代碼進項目,有成功發(fā)布上mavencentral或者jcenter的朋友可以教我一下,非常感謝。
使用方法如下:

第一步,去SmartKey下載源代碼。
第二步,拷貝annotation、apt和sdks三個模塊到你的項目里
第三步,在根項目的build.gradle添加以下配置到dependencies配置項內(nèi):

        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

第四步,在你的項目下對應的那個主模塊的build.gradle下添加以下配置,具體參考下載的代碼的app模塊:

// 這句放在前面
apply plugin: 'com.neenbedankt.android-apt'
// 這三句放在dependencies配置項內(nèi)
compile project(':annotation')
compile project(':sdks')
apt project(':apt')

配置就完成了,rebuild一下代碼系統(tǒng)就會調(diào)用apt工具生成對應的代碼。更多內(nèi)容請參照源碼中的app模塊,這個模塊是一個怎樣使用這個庫的demo。

下面是具體的使用說明:
annotation模塊共有7個注解
@Code注解
這個注解有兩個用途,一個用于管理SharedPreferences的時候,有些泛型需要管理的時候標注,另外一個用途是用于標注那些由于繼承結構比較復雜,apt工具由于不在android環(huán)境下運行,所以并不容易正確生成的代碼,例如使用android系統(tǒng)自帶的分享功能時,有uri這么一個字段,這個字段用來表示多個文件的路徑,類型是ArrayList<Uri>,由于apt工具并不知道uri實現(xiàn)了Parcelable接口,所以生成的代碼并不是最好的,可以這樣來直接指定生成的代碼:

@Key(Intent.EXTRA_STREAM)
@Code(get = "getParcelableArrayListExtra(%1$s)", set = "putParcelableArrayListExtra(%1$s, %2$s)")
public ArrayList<Uri> uri;

上面get表示獲取的時候用的代碼,%1$s是key的占位符,apt會使用真實的key展開
set表示放進Intent時用的代碼,%1$s繼續(xù)是key的占位符,%2$s是值的占位符,apt會自動匹配真實的值,注意的是,get和set兩個值必須同時存在apt才會使用他們,生成代碼如下:

smart.uri = source.getParcelableArrayListExtra("android.intent.extra.STREAM");
in.putParcelableArrayListExtra("android.intent.extra.STREAM", smart.uri);

詳細例子請參考SmartKey的app模塊里面的share包下面的MultiFileShare類,這個類用來描述使用系統(tǒng)自帶Intent分享多個圖片功能。

@Key注解
這個注解用于指定字段使用的key,一般情況下,新代碼根本就不用關注key的問題,這個時候key這個注解就不必要了,當然,如果有遺留代碼,又不想改,或者是framework內(nèi)的比如使用android提供的Intent分享內(nèi)容,或者使用第三方的庫人家的key已經(jīng)固定了,又或者你就是覺得自己制定的key更好聽(起個好字段名不就得了么,默認是直接使用字段名_),就可以用到這個注解了,例如這個用到framework里面現(xiàn)成改不了的key:

// POJO中的用法:
@Key(Intent.EXTRA_EMAIL)
public String[] email;
// 對應生成的代碼:
smart.email = (String[]) IntentValueGetter.getValue(source, "android.intent.extra.EMAIL", java.lang.String[].class);
in.putExtra("android.intent.extra.EMAIL", smart.email);

@Required注解
這個注解純粹給自己看的,在POJO的字段上標識一下,表明這個字段不應該為空,對于這個注解,SmartKey現(xiàn)階段并不會做任何的處理,目前僅僅為自己看代碼服務的。

@SmartIntent注解
用這個注解標注過的POJO類,apt工具會自動掃描所有字段,生成對應的IBuilder類,用于傳遞數(shù)據(jù)到目標組件或者從目標組件返回值,屬于核心注解,使用SmartKey必用的注解之一,例如前面說到的ForResultReq和ForResultRes類,由于添加了這個注解,所以apt工具為他們生成了ForResultReqIBuilder和ForResultResIBuilder類,直接用這兩個builder就可以非常方便的使用方法鏈傳遞數(shù)據(jù)了。

@SmartManifest注解
這個注解一個模塊只能出現(xiàn)一次,建議放在對應的主模塊,專門用來指定AndroidManifest.xml文件所在的位置,用于生成SmartTargets這個類的,有了這個注解后,apt工具會解析對應的xml文件,把所有activity和service提取出來,生成對應于每一個activity/service的Target描述類,SmartTargets.to方法得到的就是這些生成的Target實例,里面有關于對應activity/service的所有跳轉方式方法,是activity跳轉/service啟動綁定的總入口。

@SmartSharedPreferences注解
這個注解用于集中管理SharedPreferences,具體用法將會用另外一篇文章說明,這里就不詳細展開了。

@SmartTarget注解
這個注解用在Activity/Service類上面,目的有兩個,一是為了代碼閱讀的人更輕易的看到目標activity/service用的是哪個POJO作為參數(shù),第二個目的是在前面@SmartManifest注解下生成的對應的Target下,生成一個獲取對應POJO的IBuilder實例的方法,例如:

@SmartTarget(req="link.anyauto.smartkey.demo.extras.ForResultReq")
public class ForResultActivity extends BaseActivity {
// 其他activity代碼
}
//因為這個注解而生成的代碼(在自動生成的你不需要關注的ForResultActivityATarget類里)
public ForResultReqIBuilder newMapperBuilder() {
    return ForResultReqIBuilder.newBuilder();
}
// 傳參數(shù)的時候可以這樣獲取這個builder
ForResultReqIBuilder builder = SmartTargets.toForResultActivityATarget().newMapperBuilder();

但其實所有activity/service的Target描述類的params方法都不是指定具體Builder類的,可以傳遞任何的IntentKeyMapper的實現(xiàn)類。

sdk模塊下面的一些類的說明:
BackResult類,用于封裝activity結束的時候向調(diào)用者返回值的細節(jié)工作,用法套路:
BackResult.newBackResult()/.newBackResult(resultCode).params(參數(shù)).finishWithResult(activity);
跟前面的activity跳轉一樣樣的:
** BackResult出發(fā),帶上resultCode和參數(shù),走起! **
OnPrepareIntentCallback接口,這個接口基本上不怎么需要,這個接口在activity Target的go相關方法調(diào)用時會被調(diào)用,用于給大家一個最后調(diào)整Intent的機會。
GsonHelper類,用于包裝json與pojo間的相互轉換,如果你需要處理一些非標準格式的日期等字段,需要調(diào)用他的replaceGson方法替換成你應用需要的gson對象。
其他都是一些基礎性代碼,可以完全不關注,當然想知道一些原理,看看還是有用的。

對于未確定的Activity目標,比如根據(jù)服務器返回的內(nèi)容進行跳轉,或者根據(jù)配置進行跳轉時,可以這樣使用,一樣的套路:

SmartTargets.toNotDeterminedActivityTarget()
                .activityClass(clz) // 或者 .action(action).addCategories(cats).addCategory(cat)
                .params(params)
                .go(activity);

關于Activity的跳轉,目前還有一些工作在做,就是引入Activity路由,相關工作正在進行中,為了讓大家可以非常簡單流暢的使用,我會仔細設計,并且融合現(xiàn)有的參數(shù)傳遞方式,我會完善了再commit到github,讓大家的跳轉更加舒暢,特別是多人協(xié)作,根據(jù)服務器內(nèi)容進行跳轉時,使用Activity路由將會更加舒暢。

前面說了這么多,實際用法還是建議大家直接參考app這個模塊吧,對于程序員,show me the code比啥都管用。寫完文章剛好元宵節(jié),祝愿大家元宵快樂,每天準時下班。喜歡的朋友記得在github上給個星星,多謝了。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 7,322評論 0 17
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,001評論 25 709
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 旋風APP是深圳開拍網(wǎng)運營的影視內(nèi)容孵化和藝人成長平臺 ◆產(chǎn)品簡介 旋風App是深圳開拍網(wǎng)科技有限公司(深圳文化所...
    piegroups閱讀 562評論 0 0
  • 實現(xiàn)這樣的效果,所有文字包括返回按鈕都為白色 自定義返回按鈕 記得要寫在上一個頁面上 全局修改UINavigati...
    Arxu閱讀 609評論 0 1

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