[
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# IntelliJ\n*.iml\n.idea/workspace.xml\n.idea/tasks.xml\n.idea/gradle.xml\n.idea/dictionaries\n.idea/libraries\n\n# Keystore files\n# Uncomment the following line if you do not want to check your keystore files in.\n#*.jks\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n# Google Services (e.g. APIs or Firebase)\ngoogle-services.json\n\n# Freeline\nfreeline.py\nfreeline/\nfreeline_project_description.json\n\n\n# 补充的内容\n*.iws\n.idea/\n"
  },
  {
    "path": "README.md",
    "content": "### 如何延迟执行目标行为\n\n例如我们有时候会有这样的需求，那就是在执行目标行为时候，需要执行前置的一些行为。而这些前置行为，需要用户参与才能完成，或者这些前置\n行为要跳转到另外一个未知上下文中执行。\n\n典型应用场景：\n\n![](./screen/delay_action.png)\n\n\n那么我们如何实现这种需求呢？请教参我的博客分析[android 登录成功后再跳转到目标界面的思考](http://www.jianshu.com/p/1d0180ec64fb)\n\n\n\n### 添加依赖\n\n```\ncompile 'com.abbott.delayaction:libaction:1.0.1'\n\n```\n\n\n\n### 1、基本执行流程图如下\n\n![](http://upload-images.jianshu.io/upload_images/2159256-91dedfb30a1c140c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/700)\n\n### 2、演示图如下\n\n只需要进行登录的验证\n\n![](./screen/action-login.gif)\n\n需同时进行登录和优惠券的验证\n\n![](./screen/action-login-dis.gif)\n\n### 3、代码调用如下\n\n调用目标方法\n```\n\n SingleCall.getInstance()\n                        .addAction(MainActivity.this)\n                        .addValid(new LoginValid(MainActivity.this))\n                        .addValid(new DiscountValid(MainActivity.this))\n                        .doCall();\n\n```\n\n完成valid检验后，再执行即可。\n```\nSingleCall.getInstance().doCall();\n\n```\n\n当然每个对应的验证模型需要自己去完成，例如LoginValid的模型\n\n```\npackage com.goodluck.abbott.valid;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.goodluck.abbott.LoginActivity;\nimport com.goodluck.abbott.UserConfigCache;\nimport com.toptechs.libaction.action.Valid;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\npublic class LoginValid implements Valid {\n    private Context context;\n\n    public LoginValid(Context context) {\n        this.context = context;\n    }\n\n    /**\n     * check whether it login in or not\n     * @return\n     */\n    @Override\n    public boolean check() {\n        return UserConfigCache.isLogin(context);\n    }\n\n\n    /**\n     * if check() return false. then doValid was called\n     */\n    @Override\n    public void doValid() {\n         LoginActivity.start((Activity) context);\n    }\n}\n```\n\n\n\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.2\"\n    defaultConfig {\n        applicationId \"com.goodluck.action\"\n        minSdkVersion 15\n        targetSdkVersion 25\n        versionCode 1\n        versionName \"1.0\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n    compile 'com.android.support:appcompat-v7:25.3.1'\n    compile 'com.android.support.constraint:constraint-layout:1.0.2'\n    testCompile 'junit:junit:4.12'\n    compile project(':libaction')\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/zhangfei/Library/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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/androidTest/java/com/goodluck/abbott/ExampleInstrumentedTest.java",
    "content": "package com.goodluck.abbott;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.goodluck.Interceptor\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.goodluck.abbott\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\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        <activity android:name=\".LoginActivity\" />\n        <activity android:name=\".OrderDetailActivity\"></activity>\n        <activity android:name=\".DiscountActivity\"></activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/DiscountActivity.java",
    "content": "package com.goodluck.abbott;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\n\nimport com.toptechs.libaction.action.SingleCall;\n\n/**\n * get discount\n */\n\npublic class DiscountActivity extends AppCompatActivity {\n    public static final int REQUEST_CODE_LOGIN = 1000;\n\n    public static void startActivityForResult(Activity activity, int requestCode) {\n        Intent intent = new Intent(activity, DiscountActivity.class);\n        activity.startActivityForResult(intent, requestCode);\n    }\n\n    public static void start(Activity activity) {\n        Intent intent = new Intent(activity, DiscountActivity.class);\n        activity.startActivity(intent);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_discount_activivty);\n        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n\n                UserConfigCache.setDiscount(DiscountActivity.this, true);\n\n                //这里继续\n                SingleCall.getInstance().doCall();\n\n                finish();\n            }\n        });\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/LoginActivity.java",
    "content": "package com.goodluck.abbott;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\nimport android.widget.Toast;\n\nimport com.toptechs.libaction.action.SingleCall;\n\n\npublic class LoginActivity extends AppCompatActivity {\n    public static final int REQUEST_CODE_LOGIN = 1000;\n\n    public static void startActivityForResult(Activity activity, int requestCode) {\n        Intent intent = new Intent(activity, LoginActivity.class);\n        activity.startActivityForResult(intent, requestCode);\n    }\n\n    public static void start(Activity activity) {\n        Intent intent = new Intent(activity, LoginActivity.class);\n        activity.startActivity(intent);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_login_activivty);\n        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Toast.makeText(LoginActivity.this,\"登录成功\",Toast.LENGTH_SHORT).show();\n                UserConfigCache.setLogin(LoginActivity.this, true);\n                //这里继续\n                SingleCall.getInstance().doCall();\n                finish();\n            }\n        });\n    }\n\n    @Override\n    protected void onDestroy() {\n        super.onDestroy();\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/MainActivity.java",
    "content": "package com.goodluck.abbott;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.view.View;\n\nimport com.goodluck.abbott.valid.DiscountValid;\nimport com.goodluck.abbott.valid.LoginValid;\nimport com.toptechs.libaction.action.Action;\nimport com.toptechs.libaction.action.SingleCall;\n\npublic class MainActivity extends AppCompatActivity implements Action {\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n\n        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n\n\n                SingleCall.getInstance()\n                        .addAction(MainActivity.this)\n                        .addValid(new LoginValid(MainActivity.this))\n                        .doCall();\n\n\n            }\n        });\n\n        findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n\n\n\n                SingleCall.getInstance()\n                        .addAction(MainActivity.this)\n                        .addValid(new LoginValid(MainActivity.this))\n                        .addValid(new DiscountValid(MainActivity.this))\n                        .doCall();\n\n            }\n        });\n\n        findViewById(R.id.logout).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                UserConfigCache.setLogin(MainActivity.this, false);\n\n\n            }\n        });\n        findViewById(R.id.logoutDis).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                UserConfigCache.setDiscount(MainActivity.this, false);\n            }\n        });\n    }\n\n\n    @Override\n    public void call() {\n        OrderDetailActivity.startActivity(MainActivity.this, \"1234\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/OrderDetailActivity.java",
    "content": "package com.goodluck.abbott;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.widget.TextView;\n\npublic class OrderDetailActivity extends AppCompatActivity {\n    private static final String EXTRA_ORDER_ID = \"orderId\";\n\n    private TextView mOrderInfoText;\n    private String mOrderId;\n\n\n\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n\n    }\n\n    public static void startActivity(Context context, String orderId) {\n        Intent intent = new Intent(context, OrderDetailActivity.class);\n        intent.putExtra(EXTRA_ORDER_ID, orderId);\n        context.startActivity(intent);\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_order_detail);\n\n        mOrderId = getIntent().getStringExtra(EXTRA_ORDER_ID);\n        mOrderInfoText = (TextView) findViewById(R.id.orderInfo);\n    }\n\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/UserConfigCache.java",
    "content": "package com.goodluck.abbott;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n\n/**\n * Created by zhangfei on 2017/3/31.\n */\n\npublic class UserConfigCache {\n    private static final String PREFERENCE_FILE = \"user_config_cache\";\n\n    private static SharedPreferences getPreference(Context context){\n        return context.getSharedPreferences(PREFERENCE_FILE, Context.MODE_PRIVATE);\n    }\n\n    private static final String IS_LOGIN = \"is_login\";\n    private static final String DISCOUNT = \"discount\";//折扣\n\n    public static boolean isLogin(Context context){\n        return getPreference(context).getBoolean(IS_LOGIN, false);\n    }\n    public static void setLogin(Context context, boolean logged) {\n        getPreference(context).edit().putBoolean(IS_LOGIN, logged).apply();\n    }\n\n\n    public static boolean isDiscount(Context context){\n        return getPreference(context).getBoolean(DISCOUNT, false);\n    }\n    public static void setDiscount(Context context, boolean dis) {\n        getPreference(context).edit().putBoolean(DISCOUNT, dis).apply();\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/valid/DiscountValid.java",
    "content": "package com.goodluck.abbott.valid;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.goodluck.abbott.DiscountActivity;\nimport com.goodluck.abbott.UserConfigCache;\nimport com.toptechs.libaction.action.Valid;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\npublic class DiscountValid implements Valid {\n    private Context context;\n\n    public DiscountValid(Context context) {\n        this.context = context;\n    }\n\n    /**\n     *\n     * @return\n     */\n    @Override\n    public boolean check() {\n        return UserConfigCache.isDiscount(context);\n    }\n\n\n    /**\n     * if check() return false. then doValid was called\n     */\n    @Override\n    public void doValid() {\n         DiscountActivity.start((Activity) context);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/valid/LoginValid.java",
    "content": "package com.goodluck.abbott.valid;\n\nimport android.app.Activity;\nimport android.content.Context;\n\nimport com.goodluck.abbott.LoginActivity;\nimport com.goodluck.abbott.UserConfigCache;\nimport com.toptechs.libaction.action.Valid;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\npublic class LoginValid implements Valid {\n    private Context context;\n\n    public LoginValid(Context context) {\n        this.context = context;\n    }\n\n    /**\n     * check whether it login in or not\n     * @return\n     */\n    @Override\n    public boolean check() {\n        return UserConfigCache.isLogin(context);\n    }\n\n\n    /**\n     * if check() return false. then doValid was called\n     */\n    @Override\n    public void doValid() {\n         LoginActivity.start((Activity) context);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/goodluck/abbott/valid/RightValid.java",
    "content": "package com.goodluck.abbott.valid;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\nimport com.toptechs.libaction.action.ActionManager;\nimport com.toptechs.libaction.action.Valid;\n\n\n/**\n * Created by jinyabo on 8/12/2017.\n *\n * 根据传入的数据，判断是否的对应界面的权限操作。\n */\n\npublic class RightValid implements Valid {\n\n    String right;\n    String page;\n    Context context;\n\n    public RightValid(Context context, String right, String page) {\n        this.right = right;\n        this.page = page;\n        this.context = context;\n    }\n\n    @Override\n    public boolean check() {\n        if(right.equals(\"2\") && page.equals(\"order\")){\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public void doValid() {\n        Toast.makeText(context, String.format(\"没有%s界面的权限\",page),Toast.LENGTH_SHORT).show();\n        right = \"2\";\n        page = \"order\";\n\n        Toast.makeText(context, String.format(\"获得%s界面的权限\",page),Toast.LENGTH_SHORT).show();\n        ActionManager.instance().checkValid();\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/activity_discount_activivty.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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    android:gravity=\"center\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"This is discount activity.\" />\n\n    <Button\n        android:id=\"@+id/button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:text=\"get discount\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_login_activivty.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout 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    android:gravity=\"center\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"This is login activity.\" />\n\n    <Button\n        android:id=\"@+id/button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:text=\"登录\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.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=\"match_parent\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\"\n    tools:context=\"com.goodluck.abbott.MainActivity\">\n\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"这是订单详情页入口\" />\n\n    <Button\n        android:id=\"@+id/button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:text=\"打开订单(登录)\"\n        android:textSize=\"20sp\" />\n\n\n    <Button\n        android:id=\"@+id/button1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:text=\"打开订单详情(登录 and 优惠)\"\n        android:textSize=\"20sp\" />\n\n    <Button\n        android:id=\"@+id/logout\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:text=\"退出登录状态\"\n        android:textSize=\"20sp\" />\n\n    <Button\n        android:id=\"@+id/logoutDis\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"10dp\"\n        android:text=\"退出优惠状态\"\n        android:textSize=\"20sp\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_order_detail.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout 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    tools:context=\"com.goodluck.abbott.OrderDetailActivity\">\n\n    <TextView\n        android:id=\"@+id/orderInfo\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:text=\"This is order detail page\"\n        android:textSize=\"30sp\" />\n</RelativeLayout>\n"
  },
  {
    "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/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">delayAction</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</resources>\n"
  },
  {
    "path": "app/src/test/java/com/goodluck/abbott/ExampleUnitTest.java",
    "content": "package com.goodluck.abbott;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\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.0'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'\n        //比1.2版本多一个gradle字样\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'\n\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": "#Fri Dec 08 17:48:34 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# 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: -Xmx1024m -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\n#Fri Dec 08 17:48:26 CST 2017\n#systemProp.http.proxyHost=127.0.0.1\norg.gradle.jvmargs=-Xmx1536m\n#systemProp.http.proxyPort=1080\n"
  },
  {
    "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": "libaction/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "libaction/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'com.jfrog.bintray'\n\nandroid {\n    compileSdkVersion 26\n    buildToolsVersion \"26.0.2\"\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 26\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n    compile 'com.android.support:appcompat-v7:26.+'\n    compile 'com.android.support.constraint:constraint-layout:1.0.2'\n    testCompile 'junit:junit:4.12'\n}\n\n\ndef siteUrl = 'https://github.com/jinyb09017/delayActionDemo'      // 项目的主页\ndef gitUrl = 'https://github.com/jinyb09017/delayActionDemo.git'   // Git仓库的url\ngroup = \"com.abbott.delayaction\"                                        // Maven Group ID for the artifact，一般填你唯一的包名\nversion = \"1.0.1\"\ninstall {\n    repositories.mavenInstaller {\n        // This generates POM.xml with proper parameters\n        pom {\n            project {\n                packaging 'aar'\n                // Add your description here\n                description 'target method delay'\n                name 'libaction' \t//项目描述\n                url siteUrl\n                // Set your license\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'jinyb'\t\t//填写的一些基本信息\n                        name 'jinyabo'\n                        email 'jyb_96@sina.com'\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n//解决doc报错问题\ntasks.withType(Javadoc) {\n    options.addStringOption('Xdoclint:none', '-quiet')\n    options.addStringOption('encoding', 'UTF-8')\n    options.addStringOption('charSet', 'UTF-8')\n}\n\nartifacts {\n    archives sourcesJar\n//    archives sourcesJar\n}\n\n//对于support依赖生成doc的解决的方案\nandroid.libraryVariants.all { variant ->\n    println variant.javaCompile.classpath.files\n    if(variant.name == 'release') { //我们只需 release 的 javadoc\n        task(\"generate${variant.name.capitalize()}Javadoc\", type: Javadoc) {\n            // title = ''\n            // description = ''\n            source = variant.javaCompile.source\n            classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath())\n            options {\n                encoding \"utf-8\"\n                links \"http://docs.oracle.com/javase/7/docs/api/\"\n                linksOffline \"http://d.android.com/reference\", \"${android.sdkDirectory}/docs/reference\"\n\n            }\n\n            exclude '**/BuildConfig.java'\n            exclude '**/R.java'\n        }\n        task(\"javadoc${variant.name.capitalize()}Jar\", type: Jar, dependsOn: \"generate${variant.name.capitalize()}Javadoc\") {\n            classifier = 'javadoc'\n            from tasks.getByName(\"generate${variant.name.capitalize()}Javadoc\").destinationDir\n\n        }\n        artifacts {\n            archives tasks.getByName(\"javadoc${variant.name.capitalize()}Jar\")\n        }\n    }\n}\n\n\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n    configurations = ['archives']\n    pkg {\n        repo = \"maven\"\n        name = \"delayaction\"\t//发布到JCenter上的项目名字\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}\n\n//请进入指定目录进行操作\n//gradle install\n//gradle install -xjavadoc\n//gradle bintrayUpload"
  },
  {
    "path": "libaction/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/jinyabo/Library/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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "libaction/src/androidTest/java/com/toptechs/libaction/ExampleInstrumentedTest.java",
    "content": "package com.toptechs.libaction;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport android.support.test.runner.AndroidJUnit4;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\nimport static org.junit.Assert.*;\n\n/**\n * Instrumentation test, which will execute on an Android device.\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\n@RunWith(AndroidJUnit4.class)\npublic class ExampleInstrumentedTest {\n    @Test\n    public void useAppContext() throws Exception {\n        // Context of the app under test.\n        Context appContext = InstrumentationRegistry.getTargetContext();\n\n        assertEquals(\"com.toptechs.libaction.test\", appContext.getPackageName());\n    }\n}\n"
  },
  {
    "path": "libaction/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.toptechs.libaction\">\n\n\n    <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n    <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n\n\n    <!--ava?--> <application\n        android:allowBackup=\"true\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\">\n        <activity android:name=\".MainActivity\"></activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/MainActivity.java",
    "content": "package com.toptechs.libaction;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\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"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/action/Action.java",
    "content": "package com.toptechs.libaction.action;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\npublic interface Action {\n    void call();\n}\n"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/action/ActionManager.java",
    "content": "package com.toptechs.libaction.action;\n\n\nimport com.toptechs.libaction.annotation.Interceptor;\nimport com.toptechs.libaction.exp.ValidException;\n\nimport java.lang.reflect.Method;\nimport java.util.Queue;\nimport java.util.Stack;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\n\n@Deprecated\npublic class ActionManager {\n\n    static ActionManager instance = new ActionManager();\n\n    public static ActionManager instance() {\n\n        return instance;\n    }\n\n    Stack<CallUnit> delaysActions = new Stack<>();\n\n    /**\n     * 根据条件判断，是否要执行一个action\n     *\n     * @param callUnit\n     */\n    public void postCallUnit(CallUnit callUnit) {\n\n        //清除所有的actions\n        delaysActions.clear();\n        //执行check\n        callUnit.check();\n        //如果全部满足，则直接跳转目标方法\n        if (callUnit.getValidQueue().size() == 0) {\n            callUnit.getAction().call();\n        } else {\n            //加入到延迟执行体中来\n            delaysActions.push(callUnit);\n\n            Valid valid = callUnit.getValidQueue().peek();\n            callUnit.setLastValid(valid);\n            //是否会有后置任务\n            valid.doValid();\n\n        }\n    }\n\n\n    /**\n     * 通过反射注解来组装(但是这个前提是无参的构造方法才行)\n     *\n     * @param action\n     */\n    public void postCallUnit(Action action) {\n        Class clz = action.getClass();\n        try {\n            Method method = clz.getMethod(\"call\");\n            Interceptor interceptor = method.getAnnotation(Interceptor.class);\n            Class<? extends Valid>[] clzArray = interceptor.value();\n            CallUnit callUnit = new CallUnit(action);\n            for (Class cla : clzArray) {\n                callUnit.addValid((Valid) cla.newInstance());\n            }\n\n            postCallUnit(callUnit);\n        } catch (NoSuchMethodException e) {\n            e.printStackTrace();\n        } catch (InstantiationException e) {\n            e.printStackTrace();\n        } catch (IllegalAccessException e) {\n            e.printStackTrace();\n        }\n    }\n\n\n    /**\n     * 重新检查\n     */\n    public void checkValid() {\n\n        if (delaysActions.size() > 0) {\n            CallUnit callUnit = delaysActions.peek();\n\n            if (callUnit.getLastValid().check() == false) {\n                throw new ValidException(String.format(\"you must pass through the %s,and then reCall()\", callUnit.getLastValid().getClass().toString()));\n\n            }\n\n            if (callUnit != null) {\n                Queue<Valid> validQueue = callUnit.getValidQueue();\n\n                validQueue.remove(callUnit.getLastValid());\n                //valid已经执行完了，则表示此delay已经检验完了--执行目标方法\n                if (validQueue.size() == 0) {\n                    callUnit.getAction().call();\n                    //把这个任务移出\n                    delaysActions.remove(callUnit);\n                } else {\n\n                    Valid valid = callUnit.getValidQueue().peek();\n                    callUnit.setLastValid(valid);\n                    //是否会有后置任务\n                    valid.doValid();\n                }\n            }\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/action/CallUnit.java",
    "content": "package com.toptechs.libaction.action;\n\nimport java.util.ArrayDeque;\nimport java.util.Queue;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\n/**\n * 一个执行单元。\n * 包括一个执行目标体和一个检验队列。检验队列用来保证所有的前置条件。当所有的前置条件都通过后，才能进行执行单元。\n */\npublic class CallUnit {\n    //目标行为\n    private Action action;\n    //先进先出验证模型\n    private Queue<Valid> validQueue = new ArrayDeque<>();\n    //上一个执行的valid\n    private Valid lastValid;\n\n\n    public Valid getLastValid() {\n        return lastValid;\n    }\n\n    public void setLastValid(Valid lastValid) {\n        this.lastValid = lastValid;\n    }\n\n    public Action getAction() {\n        return action;\n    }\n\n    public void setAction(Action action) {\n        this.action = action;\n    }\n\n\n    public CallUnit() {\n    }\n\n    public CallUnit(Action action) {\n        this.action = action;\n    }\n\n    public static CallUnit newInstance(Action action){\n        return new CallUnit(action);\n    }\n\n    public CallUnit addValid(Valid valid) {\n        validQueue.add(valid);\n        return this;\n    }\n\n    public Queue<Valid> getValidQueue() {\n        return validQueue;\n    }\n\n    //检查valid.如果已经满足要求，则移出来队列\n    public void check() {\n        for (Valid valid : validQueue) {\n            if (valid.check()) {\n                validQueue.remove(valid);\n            }\n        }\n    }\n\n    /**\n     * start\n     */\n    public void doCall(){\n        ActionManager.instance().postCallUnit(this);\n    }\n\n\n}\n"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/action/SingleCall.java",
    "content": "package com.toptechs.libaction.action;\n\n/**\n * Created by jinyabo on 13/12/2017.\n *\n * 如果CallUnit验证模型中没有嵌套的验证模型，则可以直接使用SingleCall即可\n */\n\npublic class SingleCall {\n\n    CallUnit callUnit = new CallUnit();\n\n    public SingleCall addAction(Action action){\n        clear();\n        callUnit.setAction(action);\n        return this;\n    }\n\n\n    public SingleCall addValid(Valid valid){\n        //只添加无效的，验证不通过的。\n        if(valid.check()){\n            return this;\n        }\n        callUnit.addValid(valid);\n        return this;\n    }\n\n    public void doCall(){\n\n        //如果上一条valid难没有通过，是不允许再发起call的\n        if(callUnit.getLastValid() != null && !callUnit.getLastValid().check() ){\n            return;\n        }\n\n        //执行action\n        if(callUnit.getValidQueue().size() == 0 && callUnit.getAction() != null){\n            callUnit.getAction().call();\n            //清空\n            clear();\n        }else{\n            //执行验证。\n            Valid valid = callUnit.getValidQueue().poll();\n            callUnit.setLastValid(valid);\n            valid.doValid();\n        }\n\n    }\n\n    public void clear(){\n        callUnit.getValidQueue().clear();\n        callUnit.setAction(null);\n        callUnit.setLastValid(null);\n    }\n\n\n    // 单一全局访问点\n    public static SingleCall getInstance() {\n        return SingletonHolder.mInstance;\n    }\n\n    // 静态内部类，第一次加载Singleton类时不会初始化mInstance，\n    // 当调用getInstance()时才会初始化\n    private static class SingletonHolder {\n        private static SingleCall mInstance = new SingleCall();\n    }\n}\n"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/action/Valid.java",
    "content": "package com.toptechs.libaction.action;\n\n/**\n * Created by jinyabo on 8/12/2017.\n */\n\npublic interface Valid {\n\n    /**\n     * 是否满足检验器的要求，如果不满足的话，则执行doAction方法。如果满足，则执行目标action\n     * @return\n     */\n    boolean check();\n\n    void doValid();\n}\n"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/annotation/Interceptor.java",
    "content": "package com.toptechs.libaction.annotation;\n\n\nimport com.toptechs.libaction.action.Valid;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 这里只能用于无参数的valid模型。\n */\n\n\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface Interceptor {\n\n    Class<? extends Valid>[] value() default {};\n\n}\n"
  },
  {
    "path": "libaction/src/main/java/com/toptechs/libaction/exp/ValidException.java",
    "content": "package com.toptechs.libaction.exp;\n\n/**\n * Created by jinyabo on 10/12/2017.\n */\n\npublic class ValidException extends RuntimeException {\n\n    public ValidException() {\n    }\n\n    public ValidException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "libaction/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.constraint.ConstraintLayout 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    tools:context=\"com.toptechs.libaction.MainActivity\">\n\n</android.support.constraint.ConstraintLayout>\n"
  },
  {
    "path": "libaction/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">LibAction</string>\n</resources>\n"
  },
  {
    "path": "libaction/src/test/java/com/toptechs/libaction/ExampleUnitTest.java",
    "content": "package com.toptechs.libaction;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, which will execute on the development machine (host).\n *\n * @see <a href=\"http://d.android.com/tools/testing\">Testing documentation</a>\n */\npublic class ExampleUnitTest {\n    @Test\n    public void addition_isCorrect() throws Exception {\n        assertEquals(4, 2 + 2);\n    }\n}"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = \"delayActionDemo\"\ninclude ':app', ':libaction'\n"
  }
]