[
  {
    "path": ".gitignore",
    "content": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
  },
  {
    "path": ".idea/.name",
    "content": "TestDetailRxAndroid"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <resourceExtensions />\n    <wildcardResourcePatterns>\n      <entry name=\"!?*.java\" />\n      <entry name=\"!?*.form\" />\n      <entry name=\"!?*.class\" />\n      <entry name=\"!?*.groovy\" />\n      <entry name=\"!?*.scala\" />\n      <entry name=\"!?*.flex\" />\n      <entry name=\"!?*.kt\" />\n      <entry name=\"!?*.clj\" />\n    </wildcardResourcePatterns>\n    <annotationProcessing>\n      <profile default=\"true\" name=\"Default\" enabled=\"true\">\n        <processorPath useClasspath=\"true\" />\n      </profile>\n    </annotationProcessing>\n  </component>\n</project>"
  },
  {
    "path": ".idea/copyright/profiles_settings.xml",
    "content": "<component name=\"CopyrightManager\">\n  <settings default=\"\" />\n</component>"
  },
  {
    "path": ".idea/dictionaries/wangchenlong.xml",
    "content": "<component name=\"ProjectDictionaryState\">\n  <dictionary name=\"wangchenlong\">\n    <words>\n      <w>rxbinding</w>\n      <w>snackbar</w>\n    </words>\n  </dictionary>\n</component>"
  },
  {
    "path": ".idea/encodings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"Encoding\">\n    <file url=\"PROJECT\" charset=\"UTF-8\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/gradle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"GradleSettings\">\n    <option name=\"linkedExternalProjectsSettings\">\n      <GradleProjectSettings>\n        <option name=\"distributionType\" value=\"DEFAULT_WRAPPED\" />\n        <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n        <option name=\"modules\">\n          <set>\n            <option value=\"$PROJECT_DIR$\" />\n            <option value=\"$PROJECT_DIR$/app\" />\n          </set>\n        </option>\n        <option name=\"resolveModulePerSourceSet\" value=\"false\" />\n      </GradleProjectSettings>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EntryPointsManager\">\n    <entry_points version=\"2.0\" />\n  </component>\n  <component name=\"MavenImportPreferences\">\n    <option name=\"generalSettings\">\n      <MavenGeneralSettings>\n        <option name=\"mavenHome\" value=\"Bundled (Maven 3)\" />\n      </MavenGeneralSettings>\n    </option>\n  </component>\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectInspectionProfilesVisibleTreeState\">\n    <entry key=\"Project Default\">\n      <profile-state>\n        <expanded-state>\n          <State>\n            <id />\n          </State>\n          <State>\n            <id>Android &gt; Lint &gt; Correctness</id>\n          </State>\n          <State>\n            <id>C/C++</id>\n          </State>\n          <State>\n            <id>Data flow issuesJava</id>\n          </State>\n          <State>\n            <id>General</id>\n          </State>\n          <State>\n            <id>Java</id>\n          </State>\n          <State>\n            <id>Unused codeC/C++</id>\n          </State>\n        </expanded-state>\n        <selected-state>\n          <State>\n            <id>Android</id>\n          </State>\n        </selected-state>\n      </profile-state>\n    </entry>\n  </component>\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"false\">\n    <OptionsSetting value=\"true\" id=\"Add\" />\n    <OptionsSetting value=\"true\" id=\"Remove\" />\n    <OptionsSetting value=\"true\" id=\"Checkout\" />\n    <OptionsSetting value=\"true\" id=\"Update\" />\n    <OptionsSetting value=\"true\" id=\"Status\" />\n    <OptionsSetting value=\"true\" id=\"Edit\" />\n    <ConfirmationsSetting value=\"0\" id=\"Add\" />\n    <ConfirmationsSetting value=\"0\" id=\"Remove\" />\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_8\" assert-keyword=\"true\" jdk-15=\"true\" project-jdk-name=\"JDK\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n  <component name=\"SvnConfiguration\">\n    <configuration>$USER_HOME$/.subversion</configuration>\n  </component>\n  <component name=\"masterDetails\">\n    <states>\n      <state key=\"ProjectJDKs.UI\">\n        <settings>\n          <last-edited>1.8</last-edited>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n      <state key=\"ScopeChooserConfigurable.UI\">\n        <settings>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n    </states>\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/TestDetailRxAndroid.iml\" filepath=\"$PROJECT_DIR$/TestDetailRxAndroid.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "# TestDetailRxAndroid\n\nRxAndroid的开发完整样例，Created by C.L. Wang\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "plugins {\n    id \"me.tatarka.retrolambda\" version \"3.2.4\"\n}\n\napply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion '25.0.0'\n\n    defaultConfig {\n        applicationId \"org.wangchenlong.testdetailrxandroid\"\n        minSdkVersion 17\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    testCompile 'junit:junit:4.12'\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile 'com.android.support:recyclerview-v7:23.1.1' // RecyclerView\n\n    compile 'com.jakewharton:butterknife:7.0.1' // ButterKnife标注\n    compile 'io.reactivex:rxandroid:1.1.0' // RxAndroid\n    compile 'io.reactivex:rxjava:1.1.0' // 推荐同时加载RxJava\n\n    compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' // Retrofit网络处理\n    compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2' // Retrofit的rx解析库\n    compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' // Retrofit的gson库\n\n    compile 'com.squareup.picasso:picasso:2.5.2' // Picasso网络图片加载\n\n    compile 'com.trello:rxlifecycle:0.4.0' // RxLifecycle管理Rx的生命周期\n    compile 'com.trello:rxlifecycle-components:0.4.0' // RxLifecycle组件\n\n    // RxBinding\n    compile 'com.jakewharton.rxbinding:rxbinding:0.3.0'\n    compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0'\n    compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0'\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/wangchenlong/Installations/android-sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/androidTest/java/org/wangchenlong/testdetailrxandroid/ApplicationTest.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"org.wangchenlong.testdetailrxandroid\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n\n        <activity android:name=\".MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n\n        <!--简单示例-->\n        <activity android:name=\".SimpleActivity\"/>\n\n        <!--更多示例-->\n        <activity android:name=\".MoreActivity\"/>\n\n        <!--Lambda示例-->\n        <activity android:name=\".LambdaActivity\"/>\n\n        <!--网络示例-->\n        <activity android:name=\".NetworkActivity\"/>\n\n        <!--网络示例-详细内容-->\n        <activity android:name=\".NetworkDetailActivity\"/>\n\n        <!--安全示例-详细内容-->\n        <activity android:name=\".SafeActivity\"/>\n\n        <!--RxBinding示例-->\n        <activity\n            android:name=\".BindingActivity\"\n            android:theme=\"@style/AppTheme.NoActionBar\"/>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/BindingActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.design.widget.FloatingActionButton;\nimport android.support.design.widget.Snackbar;\nimport android.support.v7.app.ActionBar;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.Toolbar;\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.EditText;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport com.jakewharton.rxbinding.support.design.widget.RxSnackbar;\nimport com.jakewharton.rxbinding.support.v7.widget.RxToolbar;\nimport com.jakewharton.rxbinding.view.RxView;\nimport com.jakewharton.rxbinding.widget.RxTextView;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\n/**\n * Rx绑定\n * <p>\n * Created by wangchenlong on 16/1/25.\n */\npublic class BindingActivity extends AppCompatActivity {\n    @Bind(R.id.rxbinding_t_toolbar) Toolbar mTToolbar;\n    @Bind(R.id.rxbinding_fab_fab) FloatingActionButton mFabFab;\n\n    @Bind(R.id.rxbinding_et_usual_approach) EditText mEtUsualApproach;\n    @Bind(R.id.rxbinding_et_reactive_approach) EditText mEtReactiveApproach;\n    @Bind(R.id.rxbinding_tv_show) TextView mTvShow;\n\n    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_binding);\n        ButterKnife.bind(this);\n\n        initToolbar(); // 初始化Toolbar\n        initFabButton(); // 初始化Fab按钮\n        initEditText(); // 初始化编辑文本\n    }\n\n    private void initToolbar() {\n        setSupportActionBar(mTToolbar); // 添加Toolbar\n        RxToolbar.itemClicks(mTToolbar).subscribe(this::onToolbarItemClicked);\n    }\n\n    private void onToolbarItemClicked(MenuItem menuItem) {\n        String m = \"点击\\\"\" + menuItem.getTitle() + \"\\\"\";\n        Toast.makeText(this, m, Toast.LENGTH_SHORT).show();\n    }\n\n    @Override public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.menu_rxbinding, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    // 初始化Fab按钮\n    private void initFabButton() {\n        RxView.clicks(mFabFab).subscribe(this::onFabClicked);\n    }\n\n    // 点击Fab按钮\n    private void onFabClicked(Void v) {\n        Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), \"点击Snackbar\", Snackbar.LENGTH_SHORT);\n        snackbar.show();\n        RxSnackbar.dismisses(snackbar).subscribe(this::onSnackbarDismissed);\n    }\n\n    // 销毁Snackbar, event参考{Snackbar}\n    private void onSnackbarDismissed(int event) {\n        String text = \"Snackbar消失代码:\" + event;\n        Toast.makeText(this, text, Toast.LENGTH_SHORT).show();\n    }\n\n    // 初始化编辑文本\n    private void initEditText() {\n        // 正常方式\n        mEtUsualApproach.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override public void onTextChanged(CharSequence s, int start, int before, int count) {\n                mTvShow.setText(s);\n            }\n\n            @Override public void afterTextChanged(Editable s) {\n            }\n        });\n\n        // Rx方式\n        RxTextView.textChanges(mEtReactiveApproach).subscribe(mTvShow::setText);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/LambdaActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\n\n/**\n * Lambda表达式写法\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class LambdaActivity extends Activity {\n\n    @Bind(R.id.simple_tv_text) TextView mTvText;\n\n    final String[] mManyWords = {\"Hello\", \"I\", \"am\", \"your\", \"friend\", \"Spike\"};\n    final List<String> mManyWordList = Arrays.asList(mManyWords);\n\n    @Override protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_simple);\n        ButterKnife.bind(this);\n\n        // 添加字符串, 省略Action的其他方法, 只使用一个onNext.\n        Observable<String> obShow = Observable.just(sayMyName());\n\n        // 先映射, 再设置TextView\n        obShow.observeOn(AndroidSchedulers.mainThread())\n                .map(String::toUpperCase).subscribe(mTvText::setText);\n\n        // 单独显示数组中的每个元素\n        Observable<String> obMap = Observable.from(mManyWords);\n\n        // 映射之后分发\n        obMap.observeOn(AndroidSchedulers.mainThread())\n                .map(String::toUpperCase)\n                .subscribe(this::showToast);\n\n        // 优化过的代码, 直接获取数组, 再分发, 再合并, 再显示toast, Toast顺次执行.\n        Observable.just(mManyWordList)\n                .observeOn(AndroidSchedulers.mainThread())\n                .flatMap(Observable::from)\n                .reduce(this::mergeString)\n                .subscribe(this::showToast);\n//                .subscribe(s -> showToast(s));\n    }\n\n    // 创建字符串\n    private String sayMyName() {\n        return \"Hello, I am your friend, Spike!\";\n    }\n\n    // 显示Toast\n    private void showToast(String s) {\n        Toast.makeText(LambdaActivity.this, s, Toast.LENGTH_SHORT).show();\n    }\n\n    // 合并字符串\n    private String mergeString(String s1, String s2) {\n        return String.format(\"%s %s\", s1, s2);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/MainActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\n\n\n/**\n * 主Activity, 用于跳转各个模块.\n *\n * @author wangchenlong\n */\npublic class MainActivity extends AppCompatActivity {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n    }\n\n    // 跳转简单的页面\n    public void gotoSimpleModule(View view) {\n        startActivity(new Intent(this, SimpleActivity.class));\n    }\n\n    // 跳转复杂的页面\n    public void gotoMoreModule(View view) {\n        startActivity(new Intent(this, MoreActivity.class));\n    }\n\n    // 跳转Lambda的页面\n    public void gotoLambdaModule(View view) {\n        startActivity(new Intent(this, LambdaActivity.class));\n    }\n\n    // 跳转网络的页面\n    public void gotoNetworkModule(View view) {\n        startActivity(new Intent(this, NetworkActivity.class));\n    }\n\n    // 跳转线程安全的页面\n    public void gotoSafeModule(View view) {\n        startActivity(new Intent(this, SafeActivity.class));\n    }\n\n    // 跳转RxBinding的页面\n    public void gotoBindingModule(View view) {\n        startActivity(new Intent(this, BindingActivity.class));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/MoreActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\nimport rx.functions.Action1;\nimport rx.functions.Func1;\nimport rx.functions.Func2;\n\n/**\n * 更多的RxAndroid的使用方法.\n * <p>\n * Created by wangchenlong on 15/12/30.\n */\npublic class MoreActivity extends Activity {\n\n    @Bind(R.id.simple_tv_text) TextView mTvText;\n\n    final String[] mManyWords = {\"Hello\", \"I\", \"am\", \"your\", \"friend\", \"Spike\"};\n    final List<String> mManyWordList = Arrays.asList(mManyWords);\n\n    // Action类似订阅者, 设置TextView\n    private Action1<String> mTextViewAction =\n            new Action1<String>() {\n                @Override public void call(String s) {\n                    mTvText.setText(s);\n                }\n            };\n\n    // Action设置Toast\n    private Action1<String> mToastAction = new Action1<String>() {\n        @Override public void call(String s) {\n            Toast.makeText(MoreActivity.this, s, Toast.LENGTH_SHORT).show();\n        }\n    };\n\n    // 设置映射函数\n    private Func1<List<String>, Observable<String>> mOneLetterFunc =\n            new Func1<List<String>, Observable<String>>() {\n                @Override public Observable<String> call(List<String> strings) {\n                    return Observable.from(strings); // 映射字符串\n                }\n            };\n\n    // 设置大写字母\n    private Func1<String, String> mUpperLetterFunc =\n            new Func1<String, String>() {\n                @Override public String call(String s) {\n                    return s.toUpperCase(); // 大小字母\n                }\n            };\n\n    // 连接字符串\n    private Func2<String, String, String> mMergeStringFunc =\n            new Func2<String, String, String>() {\n                @Override public String call(String s, String s2) {\n                    return String.format(\"%s %s\", s, s2); // 空格连接字符串\n                }\n            };\n\n    // 创建字符串\n    private static String sayMyName() {\n        return \"Hello, I am your friend, Spike!\";\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_simple);\n        ButterKnife.bind(this);\n\n        // 添加字符串, 省略Action的其他方法, 只使用一个onNext.\n        Observable<String> obShow = Observable.just(sayMyName());\n\n        // 先映射, 再设置TextView\n        obShow.observeOn(AndroidSchedulers.mainThread())\n                .map(mUpperLetterFunc).subscribe(mTextViewAction);\n\n        // 单独显示数组中的每个元素\n        Observable<String> obMap = Observable.from(mManyWords);\n\n        // 映射之后分发\n        obMap.observeOn(AndroidSchedulers.mainThread())\n                .map(mUpperLetterFunc).subscribe(mToastAction);\n\n        // 优化过的代码, 直接获取数组, 再分发, 再合并, 再显示toast, Toast顺次执行.\n        Observable.just(mManyWordList)\n                .observeOn(AndroidSchedulers.mainThread())\n                .flatMap(mOneLetterFunc)\n                .reduce(mMergeStringFunc)\n                .subscribe(mToastAction);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/NetworkActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\nimport org.wangchenlong.testdetailrxandroid.networks.UserListAdapter;\nimport org.wangchenlong.testdetailrxandroid.networks.NetworkWrapper;\n\n/**\n * Rx的网络请求方式\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class NetworkActivity extends Activity {\n    @Bind(R.id.network_rv_list) RecyclerView mRvList; // 列表\n\n    @Override protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_network);\n        ButterKnife.bind(this);\n\n        // 设置Layout管理器\n        LinearLayoutManager layoutManager = new LinearLayoutManager(this);\n        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);\n        mRvList.setLayoutManager(layoutManager);\n\n        // 设置适配器\n        UserListAdapter adapter = new UserListAdapter(this::gotoDetailPage);\n        NetworkWrapper.getUsersInto(adapter);  // 加载网络信息\n        mRvList.setAdapter(adapter);\n    }\n\n    // 点击的回调\n    public interface UserClickCallback {\n        void onItemClicked(String name);\n    }\n\n    // 跳转到库详情页面\n    private void gotoDetailPage(String name) {\n        startActivity(NetworkDetailActivity.from(NetworkActivity.this, name));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/NetworkDetailActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.widget.LinearLayoutManager;\nimport android.support.v7.widget.RecyclerView;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport org.wangchenlong.testdetailrxandroid.networks.NetworkWrapper;\nimport org.wangchenlong.testdetailrxandroid.networks.RepoListAdapter;\n\n/**\n * GitHub的库详细页面\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class NetworkDetailActivity extends Activity {\n\n    private static final String USER_KEY = \"network_detail_activity.user\";\n\n    @Bind(R.id.network_rv_list) RecyclerView mRvList;\n\n    public static Intent from(Context context, String username) {\n        Intent intent = new Intent(context, NetworkDetailActivity.class);\n        intent.putExtra(USER_KEY, username);\n        return intent;\n    }\n\n    @Override protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_network);\n        ButterKnife.bind(this);\n\n        // 设置布局\n        LinearLayoutManager manager = new LinearLayoutManager(this);\n        manager.setOrientation(LinearLayoutManager.VERTICAL);\n        mRvList.setLayoutManager(manager);\n\n        // 设置Adapter\n        RepoListAdapter adapter = new RepoListAdapter();\n        NetworkWrapper.getReposInfo(getIntent().getStringExtra(USER_KEY), adapter);\n        mRvList.setAdapter(adapter);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/SafeActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.os.Bundle;\nimport android.util.Log;\nimport android.widget.TextView;\n\nimport com.trello.rxlifecycle.components.support.RxAppCompatActivity;\n\nimport java.util.concurrent.TimeUnit;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\n\n/**\n * Rx的线程安全\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class SafeActivity extends RxAppCompatActivity {\n    private static final String TAG = \"DEBUG-WCL: \" + SafeActivity.class.getSimpleName();\n\n    @Bind(R.id.simple_tv_text) TextView mTvText;\n\n    @Override protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_simple);\n        ButterKnife.bind(this);\n\n        Observable.interval(1, TimeUnit.SECONDS)\n                .observeOn(AndroidSchedulers.mainThread())\n                .compose(bindToLifecycle()) // 管理生命周期, 防止内存泄露\n                .subscribe(this::showTime);\n    }\n\n    private void showTime(Long time) {\n        mTvText.setText(String.valueOf(\"时间计数: \" + time));\n        Log.d(TAG, \"时间计数器: \" + time);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        Log.w(TAG, \"页面关闭!\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/SimpleActivity.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport android.app.Activity;\nimport android.os.Bundle;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\nimport rx.Observable;\nimport rx.Scheduler;\nimport rx.Subscriber;\nimport rx.android.schedulers.AndroidSchedulers;\nimport rx.schedulers.Schedulers;\n\n/**\n * RxJava的基础讲解, 包含一个观察者(Observable), 两个订阅者(Subscriber).\n * <p>\n * Created by wangchenlong on 15/12/30.\n */\npublic class SimpleActivity extends Activity {\n\n    @Bind(R.id.simple_tv_text) TextView mTvText;\n\n    // 观察事件发生\n    private Observable.OnSubscribe<String> mObservableAction = new Observable.OnSubscribe<String>() {\n        @Override public void call(Subscriber<? super String> subscriber) {\n            subscriber.onNext(sayMyName()); // 发送事件\n            subscriber.onCompleted(); // 完成事件\n        }\n    };\n\n    // 订阅者, 接收字符串, 修改控件\n    private Subscriber<String> mTextSubscriber = new Subscriber<String>() {\n        @Override public void onCompleted() {\n        }\n\n        @Override public void onError(Throwable e) {\n        }\n\n        @Override public void onNext(String s) {\n            mTvText.setText(s); // 设置文字\n        }\n    };\n\n    // 订阅者, 接收字符串, 提示信息\n    private Subscriber<String> mToastSubscriber = new Subscriber<String>() {\n        @Override public void onCompleted() {\n        }\n\n        @Override public void onError(Throwable e) {\n        }\n\n        @Override public void onNext(String s) {\n            Toast.makeText(SimpleActivity.this, s, Toast.LENGTH_SHORT).show();\n        }\n    };\n\n    @Override protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_simple);\n        ButterKnife.bind(this);\n\n        // 注册观察活动\n        Observable<String> observable = Observable.create(mObservableAction);\n\n        // 分发订阅信息\n        observable.observeOn(AndroidSchedulers.mainThread()); // 主线程\n\n        observable.subscribe(mTextSubscriber);\n        observable.subscribe(mToastSubscriber);\n    }\n\n    // 创建字符串\n    private String sayMyName() {\n        return \"Hello, I am your friend, Spike!\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/networks/GitHubService.java",
    "content": "package org.wangchenlong.testdetailrxandroid.networks;\n\nimport retrofit.http.GET;\nimport retrofit.http.Path;\nimport rx.Observable;\n\n/**\n * GitHub的服务\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic interface GitHubService {\n    String ENDPOINT = \"https://api.github.com\";\n\n    @GET(\"/users/{user}\") // 获取个人信息\n    Observable<UserListAdapter.GitHubUser> getUserData(@Path(\"user\") String user);\n\n    @GET(\"/users/{user}/repos\") // 获取库, 获取的是数组\n    Observable<RepoListAdapter.GitHubRepo[]> getRepoData(@Path(\"user\") String user);\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/networks/NetworkWrapper.java",
    "content": "package org.wangchenlong.testdetailrxandroid.networks;\n\nimport rx.Observable;\nimport rx.android.schedulers.AndroidSchedulers;\nimport rx.schedulers.Schedulers;\n\n/**\n * 用户获取类\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class NetworkWrapper {\n    private static final String[] mFamousUsers =\n            {\"SpikeKing\", \"JakeWharton\", \"rock3r\", \"Takhion\", \"dextorer\", \"Mariuxtheone\"};\n\n    // 获取用户信息\n    public static void getUsersInto(final UserListAdapter adapter) {\n        GitHubService gitHubService =\n                ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);\n\n        Observable.from(mFamousUsers)\n                .flatMap(gitHubService::getUserData)\n                .subscribeOn(Schedulers.newThread())\n                .observeOn(AndroidSchedulers.mainThread())\n                .subscribe(adapter::addUser);\n    }\n\n    // 获取库信息\n    public static void getReposInfo(final String username, final RepoListAdapter adapter) {\n        GitHubService gitHubService =\n                ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);\n\n        gitHubService.getRepoData(username)\n                .flatMap(Observable::from)\n                .subscribeOn(Schedulers.newThread())\n                .observeOn(AndroidSchedulers.mainThread())\n                .subscribe(adapter::addRepo);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/networks/RepoListAdapter.java",
    "content": "package org.wangchenlong.testdetailrxandroid.networks;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport org.wangchenlong.testdetailrxandroid.R;\n\nimport java.util.ArrayList;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\n/**\n * 库的适配器\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class RepoListAdapter extends RecyclerView.Adapter<RepoListAdapter.RepoViewHolder> {\n\n    private ArrayList<GitHubRepo> mGitHubRepos;  // 数据列表\n\n    public RepoListAdapter() {\n        mGitHubRepos = new ArrayList<>();\n    }\n\n    // 动态修改列表数据\n    public void addRepo(GitHubRepo gitHubRepo) {\n        mGitHubRepos.add(gitHubRepo);\n        notifyItemInserted(mGitHubRepos.size() - 1);  // 更新数据\n    }\n\n    @Override\n    public RepoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View view = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.item_network_repo, parent, false);\n        return new RepoViewHolder(view);\n    }\n\n    @Override public void onBindViewHolder(RepoViewHolder holder, int position) {\n        holder.bindTo(mGitHubRepos.get(position));\n    }\n\n    @Override public int getItemCount() {\n        return mGitHubRepos.size();\n    }\n\n    public static class RepoViewHolder extends RecyclerView.ViewHolder {\n        @Bind(R.id.network_item_iv_repo_name) TextView mIvRepoName;\n        @Bind(R.id.network_item_iv_repo_detail) TextView mIvRepoDetail;\n\n        public RepoViewHolder(View itemView) {\n            super(itemView);\n            ButterKnife.bind(this, itemView);\n        }\n\n        public void bindTo(GitHubRepo gitHubRepo) {\n            mIvRepoName.setText(gitHubRepo.name);\n            mIvRepoDetail.setText(\n                    String.valueOf(\"description: \" + gitHubRepo.description\n                            + \", language: \" + gitHubRepo.language));\n        }\n    }\n\n    public static class GitHubRepo {\n        public String name; // 库的名字\n        public String description; // 描述\n        public String language; // 语言\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/networks/ServiceFactory.java",
    "content": "package org.wangchenlong.testdetailrxandroid.networks;\n\nimport retrofit.GsonConverterFactory;\nimport retrofit.Retrofit;\nimport retrofit.RxJavaCallAdapterFactory;\n\n/**\n * 工厂模式\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class ServiceFactory {\n    public static <T> T createServiceFrom(final Class<T> serviceClass, String endpoint) {\n        Retrofit adapter = new Retrofit.Builder()\n                .baseUrl(endpoint)\n                .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 添加Rx适配器\n                .addConverterFactory(GsonConverterFactory.create()) // 添加Gson转换器\n                .build();\n        return adapter.create(serviceClass);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/wangchenlong/testdetailrxandroid/networks/UserListAdapter.java",
    "content": "package org.wangchenlong.testdetailrxandroid.networks;\n\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.squareup.picasso.Picasso;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport butterknife.Bind;\nimport butterknife.ButterKnife;\n\nimport org.wangchenlong.testdetailrxandroid.NetworkActivity;\nimport org.wangchenlong.testdetailrxandroid.R;\n\n/**\n * 显示列表\n * <p>\n * Created by wangchenlong on 15/12/31.\n */\npublic class UserListAdapter extends RecyclerView.Adapter<UserListAdapter.UserViewHolder> {\n    private List<GitHubUser> mUsers; // 用户名集合\n    private NetworkActivity.UserClickCallback mCallback; // 用户点击项的回调\n\n    public UserListAdapter(NetworkActivity.UserClickCallback callback) {\n        mCallback = callback;\n        mUsers = new ArrayList<>();\n    }\n\n    public void addUser(GitHubUser user) {\n        mUsers.add(user);  // 添加数据\n        notifyItemInserted(mUsers.size() - 1);  // 更新最后一位\n    }\n\n    @Override public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        View item = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.item_network_user, parent, false);\n        return new UserViewHolder(item, mCallback);\n    }\n\n    @Override public void onBindViewHolder(UserViewHolder holder, int position) {\n        holder.bindTo(mUsers.get(position));\n    }\n\n    @Override public int getItemCount() {\n        return mUsers.size();\n    }\n\n    // Adapter的ViewHolder\n    public static class UserViewHolder extends RecyclerView.ViewHolder {\n        @Bind(R.id.network_item_iv_user_picture) ImageView mIvUserPicture;\n        @Bind(R.id.network_item_tv_user_name) TextView mTvUserName;\n        @Bind(R.id.network_item_tv_user_login) TextView mTvUserLogin;\n        @Bind(R.id.network_item_tv_user_page) TextView mTvUserPage;\n\n        public UserViewHolder(View itemView, NetworkActivity.UserClickCallback callback) {\n            super(itemView);\n            ButterKnife.bind(this, itemView);\n            // 绑定点击事件\n            itemView.setOnClickListener(v -> callback.onItemClicked(mTvUserLogin.getText().toString()));\n        }\n\n        // 绑定数据\n        public void bindTo(GitHubUser user) {\n            mTvUserName.setText(user.name);\n            mTvUserLogin.setText(user.login);\n            mTvUserPage.setText(user.repos_url);\n\n            Picasso.with(mIvUserPicture.getContext())\n                    .load(user.avatar_url)\n                    .placeholder(R.drawable.ic_person_black_24dp)\n                    .into(mIvUserPicture);\n        }\n    }\n\n    // 用户类, 名称必须与Json解析相同\n    public static class GitHubUser {\n        public String login;\n        public String avatar_url;\n        public String name;\n        public String repos_url;\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_person_black_24dp.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:viewportHeight=\"24.0\" android:viewportWidth=\"24.0\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_binding.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.design.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\"\n    tools:context=\"org.wangchenlong.testdetailrxandroid.BindingActivity\">\n\n    <android.support.design.widget.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:theme=\"@style/AppTheme.AppBarOverlay\">\n\n        <android.support.v7.widget.Toolbar\n            android:id=\"@+id/rxbinding_t_toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            android:background=\"?attr/colorPrimary\"\n            android:popupTheme=\"@style/AppTheme.PopupOverlay\"\n            tools:targetApi=\"21\"/>\n\n    </android.support.design.widget.AppBarLayout>\n\n    <include layout=\"@layout/content_rxbinding\"/>\n\n    <android.support.design.widget.FloatingActionButton\n        android:id=\"@+id/rxbinding_fab_fab\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/fab_margin\"\n        android:src=\"@android:drawable/ic_dialog_email\"/>\n\n</android.support.design.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n    android:paddingTop=\"@dimen/activity_vertical_margin\"\n    tools:context=\"org.wangchenlong.testdetailrxandroid.MainActivity\">\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"gotoSimpleModule\"\n        android:text=\"@string/test_button_simple\"/>\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"gotoMoreModule\"\n        android:text=\"@string/test_button_more\"/>\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"gotoLambdaModule\"\n        android:text=\"@string/test_button_lambda\"/>\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"gotoNetworkModule\"\n        android:text=\"@string/test_button_network\"/>\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"gotoSafeModule\"\n        android:text=\"@string/test_button_safe\"/>\n\n    <Button\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:onClick=\"gotoBindingModule\"\n        android:text=\"@string/test_button_binding\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_network.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <android.support.v7.widget.RecyclerView\n        android:id=\"@+id/network_rv_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_simple.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"@dimen/activity_margin\">\n\n    <TextView\n        android:id=\"@+id/simple_tv_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:textSize=\"20sp\"\n        tools:text=\"Hello World!\"/>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/content_rxbinding.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n              xmlns:tools=\"http://schemas.android.com/tools\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"match_parent\"\n              android:orientation=\"vertical\"\n              android:padding=\"@dimen/activity_margin\"\n              app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n              tools:context=\"org.wangchenlong.testdetailrxandroid.BindingActivity\"\n              tools:showIn=\"@layout/activity_binding\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/usual_approach\"/>\n\n    <EditText\n        android:id=\"@+id/rxbinding_et_usual_approach\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:hint=\"@null\"/>\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/reactive_approach\"/>\n\n    <EditText\n        android:id=\"@+id/rxbinding_et_reactive_approach\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:hint=\"@null\"/>\n\n    <TextView\n        android:id=\"@+id/rxbinding_tv_show\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"/>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/item_network_repo.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:tools=\"http://schemas.android.com/tools\"\n              android:layout_width=\"match_parent\"\n              android:layout_height=\"wrap_content\"\n              android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/network_item_iv_repo_name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"8dp\"\n        android:textColor=\"@android:color/holo_purple\"\n        android:textSize=\"22sp\"\n        tools:text=\"Repos name\"/>\n\n    <TextView\n        android:id=\"@+id/network_item_iv_repo_detail\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"8dp\"\n        android:textSize=\"14sp\"\n        tools:text=\"Details\"/>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/item_network_user.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <ImageView\n        android:id=\"@+id/network_item_iv_user_picture\"\n        android:layout_width=\"80dp\"\n        android:layout_height=\"80dp\"\n        android:layout_alignParentStart=\"true\"/>\n\n    <TextView\n        android:id=\"@+id/network_item_tv_user_name\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_toEndOf=\"@id/network_item_iv_user_picture\"\n        android:padding=\"8dp\"\n        android:textSize=\"24sp\"\n        tools:text=\"Sample name\"/>\n\n    <TextView\n        android:id=\"@+id/network_item_tv_user_login\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/network_item_tv_user_name\"\n        android:layout_toEndOf=\"@id/network_item_iv_user_picture\"\n        android:padding=\"8dp\"\n        android:textSize=\"18sp\"\n        tools:text=\"Sample login\"/>\n\n    <View\n        android:id=\"@+id/divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_below=\"@id/network_item_tv_user_login\"\n        android:background=\"@android:color/holo_blue_dark\"/>\n\n    <TextView\n        android:id=\"@+id/network_item_tv_user_page\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_below=\"@id/divider\"\n        android:padding=\"8dp\"\n        android:textSize=\"14sp\"\n        tools:text=\"http://github.com/user\"/>\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/menu/menu_rxbinding.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/menu_input_add\"\n        android:icon=\"@android:drawable/ic_input_add\"\n        android:title=\"@string/menu_add\"\n        app:showAsAction=\"ifRoom\"/>\n\n    <item\n        android:id=\"@+id/menu_input_delete\"\n        android:icon=\"@android:drawable/ic_input_delete\"\n        android:title=\"@string/menu_delete\"\n        app:showAsAction=\"ifRoom\"/>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"activity_margin\">16dp</dimen>\n    <dimen name=\"fab_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">TestDetailRxAndroid</string>\n    <string name=\"test_button_simple\">简单使用</string>\n    <string name=\"test_button_more\">更多使用</string>\n    <string name=\"test_button_lambda\">Lambda使用</string>\n    <string name=\"test_button_network\">网络使用</string>\n    <string name=\"test_button_safe\">线程安全</string>\n    <string name=\"test_button_binding\">RxBinding</string>\n\n    <string name=\"usual_approach\">常规方式</string>\n    <string name=\"reactive_approach\">响应方式</string>\n\n    <string name=\"menu_add\">添加</string>\n    <string name=\"menu_delete\">删除</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"AppTheme.AppBarOverlay\" parent=\"ThemeOverlay.AppCompat.Dark.ActionBar\"/>\n\n    <style name=\"AppTheme.PopupOverlay\" parent=\"ThemeOverlay.AppCompat.Light\"/>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-v21/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <style name=\"AppTheme.NoActionBar\">\n        <item name=\"windowActionBar\">false</item>\n        <item name=\"windowNoTitle\">true</item>\n        <item name=\"android:windowDrawsSystemBarBackgrounds\">true</item>\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n    </style>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/test/java/org/wangchenlong/testdetailrxandroid/ExampleUnitTest.java",
    "content": "package org.wangchenlong.testdetailrxandroid;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * To work on unit tests, switch the Test Artifact in the Build Variants view.\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.3.2'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Wed Jun 28 09:46:08 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-3.3-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app'\n"
  }
]