{"id":13848743,"url":"https://github.com/gdpancheng/LoonAndroid","last_synced_at":"2025-07-12T13:32:35.863Z","repository":{"id":14777153,"uuid":"17498865","full_name":"gdpancheng/LoonAndroid","owner":"gdpancheng","description":" 整个框架式不同于androidannotations，Roboguice等ioc框架，这是一个类似spring的实现方式。在整应用的生命周期中找到切入点，然后对activity的生命周期进行拦截，然后插入自己的功能。","archived":false,"fork":false,"pushed_at":"2017-04-18T06:48:59.000Z","size":16475,"stargazers_count":575,"open_issues_count":10,"forks_count":348,"subscribers_count":62,"default_branch":"master","last_synced_at":"2024-08-05T19:35:57.679Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gdpancheng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-03-07T01:26:46.000Z","updated_at":"2024-04-14T11:25:43.000Z","dependencies_parsed_at":"2022-07-23T11:16:23.587Z","dependency_job_id":null,"html_url":"https://github.com/gdpancheng/LoonAndroid","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gdpancheng%2FLoonAndroid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gdpancheng%2FLoonAndroid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gdpancheng%2FLoonAndroid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gdpancheng%2FLoonAndroid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gdpancheng","download_url":"https://codeload.github.com/gdpancheng/LoonAndroid/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225825268,"owners_count":17529905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-04T19:00:56.725Z","updated_at":"2024-11-22T00:31:22.017Z","avatar_url":"https://github.com/gdpancheng.png","language":"Java","funding_links":[],"categories":["Java","Libs"],"sub_categories":["\u003cA NAME=\"Framework\"\u003e\u003c/A\u003eFramework"],"readme":"\n##第三个版本 LoonAndroid 3.0 和第一个版本完全不同 感兴趣的可以移步 \n[3.0 版本请点击这里（Please click here）](https://github.com/gdpancheng/LoonAndroid3)\n\n框架的说明\n===================================\n如果你想看ui方面的东西，这里没有，想要看牛逼的效果这里也没有。这只是纯实现功能的框架，它的目标是节省代码量，降低耦合，让代码层次看起来更清晰。整个框架一部分是网上的，一部分是我改的，为了适应我的编码习惯，还有一部分像orm完全是网上的组件。在此感谢那些朋友们。\n整个框架式的初衷是为了偷懒，之前都是一个功能一个jar，做项目的时候拉进去，这样对于我来说依然还是比较麻烦。最后就导致我把所有的jar做成了一个工具集合包。\n有很多框架都含有这个工具集合里的功能，这些不一定都好用，因为这是根据我个人使用喜欢来实现的，如果你们有自己的想法，可以自己把架包解压了以后，源码拉出来改动下。\n目前很多框架都用到了注解，除了androidannotations没有入侵我们应用的代码以外，其他的基本上都有，要么是必须继承框架里面的activity,要么是必须在activity的oncreat里面调用某个方法。\n整个框架式不同于androidannotations，Roboguice等ioc框架，这是一个类似spring的实现方式。在整应用的生命周期中找到切入点，然后对activity的生命周期进行拦截，然后插入自己的功能。\n\n如果需要混淆 \n第一步 你要先引入你得架包\n-libraryjars   libs/android-support-v4.jar\n-libraryjars   libs/loonandroid.jar\n第二步 你要保证注解在代码优化的时候不能被删除掉\n-keepattributes Signature\n-keepattributes *Annotation*\n第三步 support4 要排除掉\n-dontwarn android.support.v4.**    \n-keep class android.support.v4.** { *; }  \n-keep interface android.support.v4.app.** { *; }  \n-keep public class * extends android.support.v4.**  \n-keep public class * extends android.app.Fragment\n第四步 只要使用了注解的包名 全部排除掉\n-dontwarn xxx.**    \n-keep class xxx.** { *; }  \n其中XXX替换成你使用了注解的包名\n第五步 保证R不被混淆\n-keep class **.R$* {  \n*;  \n}\n即OK\n\n\n框架的主要功能\n-----------------------------------\n其中分为以下几种：\n* 1自动注入框架（只需要继承框架内的application既可）\n* 2图片加载框架（多重缓存，自动回收，最大限度保证内存的安全性）\n* 3网络请求模块（继承了基本上现在所有的http请求）\n* 4 eventbus（集成一个开源的框架）\n* 5验证框架（集成开源框架）\n* 6 json解析（支持解析成集合或者对象）\n* 7 数据库（不知道是哪位写的 忘记了）\n* 8 多线程断点下载（自动判断是否支持多线程，判断是否是重定向）\n* 9 自动更新模块\n* 10 一系列工具类\n\n一 自动注入框架\n-----------------------------------\n### 1 无需继承任何BaseActivity\n\n举例：普通activity\n\n\t\tpublic class FourActivity extends Activity {\n\t\t　　\n\t\t\tView xx;\n\t\t\n\t\t\t@Override\n\t\t\tprotected void onCreate(Bundle savedInstanceState) {\n\t\t\t\tsuper.onCreate(savedInstanceState);\n\t\t\t\tsetContentView(R.layout.activity_main4);\n\t\t\t\txx = find......;\n\t\t\t\t//---------------------------------------------------------\n\t\t\t\t组件的初始化\n\t\t\t\t//---------------------------------------------------------\n\t\t\t}\n\t\t}\n这其中我们会耗费大量的代码或者重复性的去些一些代码。特别是布局比较复杂的情况下。\n\n如果用框架\n\t\t\n\t\t@InjectLayer(R.layout.activity_main3)\n\t\tpublic class ThirdActivity extends Activity {\n\t\t\t@InjectView\n\t\t\tView xx;\n\t\t}\n\n即可\n　　\n像软件的说明页面，就是单纯的展示一个布局，那么就是\n\n\t\t@InjectLayer(R.layout.activity_main3)\n\t\tpublic class ThirdActivity extends Activity {\n\t\t}\n\t\t\n即可\n　　\n\t\t整个ioc框架不需要你继承任何的acitivity，这样就保证了不会在你的代码结构层次上造成影响，因为有的时候你需要自己的BaseActivity来实现你公用的功能。\n　　\n### 2 支持子父布局\n　　\n　　如下图\n\t\n这种情况下，对于一般的框架来说，做法有以下几种：\n*  ActivityGroup  一般的ioc框架都需要继承框架内的activity，activitygroup会让很多框架用不了，现在ActivityGroup也是不提倡的了。\n*  BaseActivity 一般的Ioc框架会需要你的BaseActivity 去继承框架内的activity\n*  中间用fragment 这样的情况也一样，你的FragmentActivity必须继承它的activity才能实现ioc框架功能。\n对于这个框架来说很容易实现\n\n1 ActivityGroup  你不需要继承任何activity 和普通activity 实现方式（如上面的例子）\n\n2 BaseActivity \n\n见代码：\n\n首先是BaseActivity\n　　\n\t\t@InjectPLayer(R.layout.activity_com)\n\t\tpublic class BaseActivity extends Activity {}\n\t\t\n其中R.layout.activity_com是包括上下导航的布局，中间是一个view子activity只需要这么写即可\n\n\t\t@InjectLayer(value = R.layout.activity_main, parent = R.id.common)\n\t\tpublic class MainActivity extends BaseActivity {}\n\t\t\n当然 又会有问题了，那么我上下导航里面的点击事件怎么绑定，怎么去初始化，\n难道要每一个子activity都要去写吗？\n当然不需要\n\n\t\t@InjectPLayer(R.layout.activity_com)\n\t\tpublic class BaseActivity extends Activity {\n\t\t@InjectInit\n\t\tprivate void init() {\n\t\t\tMeApplication.logger.s(\"公共类的初始化\");\n\t\t}\n\n\t\t// 这里是第一种交互事件注入方式（单击）\n\t\t@InjectMethod(@InjectListener(ids = { R.id.top, R.id.bottom }, listeners = { OnClick.class }))\n\t\tprivate void click2(View view) {\n\t\t\tHandler_TextStyle handler_TextStyle = new Handler_TextStyle();\n\t\t\tswitch (view.getId()) {\n\t\t\t\tcase R.id.top:\n\t\t\t\t\thandler_TextStyle.setString(\"点击了顶部按钮(在基类中统一注册,也可以单独注册)\");\n\t\t\t\t\thandler_TextStyle.setBackgroundColor(Color.RED, 3, 5);\n\t\t\t\t\tToast.makeText(this, handler_TextStyle.getSpannableString(), Toast.LENGTH_LONG).show();\n\t\t\t\t\tbreak;\n\t\t\t\tcase R.id.bottom:\n\t\t\t\t\thandler_TextStyle.setString(\"点击了底部按钮(在基类中统一注册,也可以单独注册)\");\n\t\t\t\t\thandler_TextStyle.setBackgroundColor(Color.RED, 3, 5);\n\t\t\t\t\tToast.makeText(this, handler_TextStyle.getSpannableString(), Toast.LENGTH_LONG).show();\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n如上 其中@InjectInit注解表示不管是在子activity还是父activity 都是在布局初始化完成以后才会调用，其先后顺序是\n\t\t\n\t\t父布局layout-\u003e子布局layout-\u003e父布局ioc和事件绑定-\u003e子布局事件绑定。\n\n父activity 中可以对所有的公用组件和事件进行初始化和绑定\n还没完，又会有另一个问题，如果我某个页面下导航的a按钮和其他页面底部a按钮的功能不一样 要单独设置怎么办。\n那么我们可以在子布局进行@InjectMethod和@InjectView进行事件绑定和组件注入，它们会覆盖父类中相同id的组件的操作\n以下是view注入的方法说明：\n### @InjectPLayer \n表示是Activity的setContentView\n\t\t\n\t\t@InjectLayer(value = R.layout.activity_main2, parent = R.id.common, isFull = true, isTitle = true)\n\n其中需要哪个参数就用哪个，value 是必须的 如果只有layout可以这么写@InjectPLayer(R.layout.activity_com)。\n其中value 表示layout,parent表示它在父布局中所对应组件的id 如上图中 中间显示区域的view的id。Isfull是否全屏，默认为false.isTitle 是否有标题，默认false;\n\n### @InjectView\n\n自动注入view注解。\n### 基本写法：\n\t\t\n\t\t@InjectView\n\t\tTextView test;\n\n其中test表示它在xml中对应的Id为test\n\t\t\n\t\t@InjectView(R.id.next2)\n\t\tTextView test;\n\n表示它在xml中对应的Id为next2\n\n### 高级写法：\n\t\t\n\t\t@InjectView(binders = { @InjectBinder(method = \"click\", listeners = { OnClick.class, OnLongClick.class }) })\n\t\tButton next, next3, next4;\n\n其中表示对id为next，next3，next4进行注解，其中binders 表示绑定了以下事件，binders 是个数组，也就是说可以用多个InjectBinder绑定多个事件，也可以用listeners = { OnClick.class, OnLongClick.class }来表示对组件注入了点击事件和长按事件\n\t\t\n\t\t@InjectView(value = R.id.next2, binders = { @InjectBinder(method = \"click\", listeners = { OnClick.class }) })\n\t\tButton button;\n\n对于变量名和组件id不一致的view则需要设置value\nClick 表示那些注入的事件触发以后所调用的方法，其必须在当前类内。\n// 支持由参数和无参数 即click(View view)或者click() 当然click名字必须对于变量注解中的method = \"click\"\n\n\t\tprivate void click(View view) {\n\t\t\tswitch (view.getId()) {\n\t\t\t\tcase R.id.next:\n\t\t\t\tstartActivity(new Intent(this, ThirdActivity.class));\n\t\t\t\tbreak;\n\t\t\t\t...\n\t\t\t}\n\t\t}\n\n### @InjectResource\n\n\t\t@InjectResource\n\t\tString action_settings;\n\n\t\t@InjectResource\n\t\tDrawable ic_launcher;\n\nInjectResource支持string和drawable的注解\n### @InjectMethod\n// 底部导航栏 子类覆盖父类\n\n\t\t@InjectMethod(@InjectListener(ids = { R.id.bottom }, listeners = { OnClick.class, OnLongClick.class }))\n\t\tprivate void click3(View view) {\n\t\t\tHandler_TextStyle handler_TextStyle = new Handler_TextStyle();\n\t\t\thandler_TextStyle.setString(\"点击了底部按钮 子类覆盖了父类\");\n\t\t\thandler_TextStyle.setBackgroundColor(Color.RED, 3, 5);\n\t\t\tToast.makeText(this, handler_TextStyle.getSpannableString(), Toast.LENGTH_LONG).show();\n\t\t}\n\n@InjectMethod是当我们对一个组件只需要触发而不需要find出来的时候用到。\nids 表示绑定哪些id，listeners 表示绑定哪些事件 这两个参数都是数组\n\n\n当然 如果嫌注解字段太长，可以自己修改。这个是整个view的注入。\n\n### @InjectInit\n\t\t@InjectInit\n\t\tvoid init() {\n\t\t\tMeApplication.logger.s(\"子类的初始化\");\n\t\t\ttest.setText(\"初始化完成，第一个页面\");\n\t\t}\n\n这个注解你在activity中添加到任何一个方法名上，那么，当所有的layout和所有的view以及事件绑定完毕以后，会第一个调用含有这个注解的方法。它相当于oncreat\n\n\t\t注意：框架注解了整个activity的生命周期， @InjectOnNewIntent，@InjectPause，@InjectResume，\n\t\t@InjectRestart，@InjectStart，@InjectStop 其中OnDestroy无注解。\n\t\t如果Activity中有含有这些注解的方法 那么不同生命周期下回自动调用这些方法\n\n二：Fragment的自动注入\n-----------------------------------\n\t\t@Override\n\t\tpublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n\t\t\tthis.inflater = inflater;\n\t\t\tView rootView = inflater.inflate(R.layout.activity_left, container, false);\n\t\t\tHandler_Inject.injectView(this, rootView);\n\t\t\treturn rootView;\n\t\t}\n\n\t\t只需要在onCreateView里面调用Handler_Inject.injectView(this, rootView);\n\t\t即可\n\n\n\t\t在fragment中除了activity的生命周期注解和@InjectLayer注解无法使用外，组件绑定和事件绑定都可以使用，@InjectBefore也可以使用\n\n\t\t@InjectBefore 是在组件初始化之前调用\n\n三：图片下载框架\n-----------------------------------\n\t\t这个是图片框架重写了好多次了，总是有点问题，里面基本上每一段代码都有注释，还有一些bug，\n\t\t因为项目中用的还是这次重写之前的。\n\t\t如果大家发现问题，记得告诉我框架中调用的方法名和参数基本上都不会变，避免替换jar导致需要改动大部分代码。\n\n整个图片下载的逻辑是这样的：\n\n* 1 根据url和view去调用图片下载的方法\n* 2 从缓存去拿bitmap\n* 3 如果bitmap不为空 判断是否针对这个url有单独的配置 没有则使用全局配置加载图片\n* 4 如果bitmap为空 则开启线程，放到本地线程池中，然后从本地文件读取\n* 5 如果文件存在，则转为bitmap放到缓存，然后重复2，然后9\n* 6 如果文件不存在，则开启线程放到网络线程池中去下载文件\n* 7 下载成功则放到本地sdcard 然后把文件转为bitmap放到缓存，然后重复2，然后9\n* 8 下载不成功，然后重复2，然后9\n* 9 如果bitmap不为空 判断是否针对这个url有单独的配置 没有则使用全局配置加载这张图片 如果bitmap为空 则显示失败的默认图\n\n具体的流程 可以参考源码\n\n\n### 缓存分为三层\n\n\t\t第一层是LruCache（原理去百度）\n\t\t第二层是LinkedHashMap\n\t\t第三层是 view标记\n\n\t\t1 当LruCache中的图片超过了规定了内存，那么从LruCache移除一个使用最少的，放到LinkedHashMap中\n\t\t2 当每一张图片的url对应一个count，一旦加载一张图片，那么这个url的count加1\n\t\t3 自定义AsyImageView继承ImageView，重写了onDetachedFromWindow方法，一旦\n\t\t\tAsyImageView从当前视图移除掉会调用onDetachedFromWindow该方法，此刻该图片所对应的url数目count减1\n\t\t4 因为listview中的imageview如果用了ViewHolder那么第3条就不适合了，此刻每一个imagview的hashCode对应一个url,\n\t\t\t一旦imagview更换了一个新的url,那么该imagview的hashcode上一个的引用将被移除，\n\t\t\t那么上一次显示的url所对应的count将减1\n\t\t5 当LinkedHashMap超过了规定限制的时候，那么遍历所有的count一旦count为0 则移除回收\n\n### 图片下载使用\n\n一：必须条件\n\n\t\t必须在配置文件中添加配置，来打开图片下载引擎的初始化，为了减少启动时间，默认关闭。\n\t\t#开启框架内置的图片下载 如果不设置 则无法使用框架类的图片下载\n\t\timageload_open=true\n\n\t\t二：使用方法\n\n### 1 普通图片下载\n\n\t\tImageDownloader.download(\"网络和本地图片链接\",mAsyImageView);\n\t\t\n如果需要配置bitmap的高宽\n\n第一种方式：\n\n\t\t在xml布局文件中对AsyImageView的高宽进行设置\n\n第二种方式：\n\n全局图片配置，所有图片显示默认用此配置\n\n\n\t\tGlobalConfig globalConfig = GlobalConfig.getInstance();\n\t\tglobalConfig.setMaxWidth(w);\n\t\t\n\t\t\n来设置\n\n第三种\n\n\t\tSingleConfig config = new SingleConfig();\n\t\tconfig ....设置宽高\n\t\tImageDownloader.download(\"网络和本地图片链接\",mAsyImageView,config )\n\n其中优先级\n\n### 第三种 \u003e 第一种 \u003e 第二种\n\n\t\t\t其中GlobalConfig  支持的设置有高宽的设置，内存缓存的大小，默认图片，\n\t\t\t下载失败的图片，最大缓存数目，线程池，缓存类型，显示控制，listview得滑动监听，图片加载动画\n\t\t\t其中SingleConfig 支持的设置有高宽的设置，默认图片，下载失败的图片，下载进度，显示控制，加载动画\n\n其中SingleConfig 优先于GlobalConfig  \n\n### 支持配置文件配置：\n\n\n\t\tmAsyImageView.setTemplate(\"one\");\n\t\tImageDownloader.download(\"url\",mAsyImageView);\n\n其中one在配置文件里面配置，这样 不管在任何地方，只要AsyImageView.setTemplate(\"one\");就可以使用名称为one的配置了。\n\n支持本地文件加载调用接口不变。\n\n需要进度显示的：\n\n\t\tSingleConfig config = new SingleConfig();\n\t\tconfig.setDisplayer(new DisplayerLister() {\n\t\t\t@Override\n\t\t\tpublic void startLoader(AsyImageView imageView) {\n\t\t\t    super.startLoader(imageView);\n\t\t\t}\n\t\t\t@Override\n\t\t\tpublic Bitmap finishLoader(Bitmap bitmap, AsyImageView imageView) {\n\t\t\t\tpin_progress_1.setVisibility(View.GONE);\n\t\t\t\treturn bitmap;\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void progressLoader(int progress, AsyImageView imageView) {\n\t\t\t\tpin_progress_1.setProgress(progress);\n\t\t\t    super.progressLoader(progress, imageView);\n\t\t\t}\n\t\t});\n\t\tImageDownloader.download(\"url\",photo,config);\n\t\t\n其中url的服务器必须支持获取文件长度\n\n需要显示动画的：\n如果是单独某一个图片\n\n\t\tSingleConfig config = new SingleConfig();\n\t\tconfig.setDisplayerAnimation(new FadeInAnimation());\n\n如果是全局的\n\n\t\tGlobalConfig config = new GlobalConfig();\n\t\tconfig.setDisplayerAnimation(new FadeInAnimation());\n\n其中FadeInAnimation是框架自带的一个渐变的动画\n如果需要自定义 实现DisplayerAnimation接口即可\n\n\n### 2 listview中图片下载\n\n\n\t\t只要在listview的注解@InjectView(isasy=true)中添加了isasy=true(默认为false)\n\t\t那么系统会自动给你注入OnScrollListener滚动事件，以便实现图片飞行停止才加载,缓慢拖动加载的功能。如果你要实现自己的OnScrollListener\n\n\n如下\n\n\t\t@InjectBefore\n\t\tvoid test(){\n\t\t\t//@InjectView(isasy=true)表示这个listview里面有网络图片下载，并且需要实现滑动停止才加载的功能\n\t\t\t//@InjectView(isasy=true)框架会给listview自动注入OnScrollListener,如果你自己也要滚动监听\n\t\t\t//那么请在此配置，如下\n\t\t\tGlobalConfig config = GlobalConfig.getInstance();\n\t\t\tconfig.setOnScrollLoaderListener(new MyOnScrollListener());\n\t\t\tSystem.out.println(\"before\");\n\t\t}\n\t\t//必须继承框架内的滚动监听\n\t\tclass MyOnScrollListener extends OnScrollLoaderListener{\n\t\t@Override\n        public void onScrollListener(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {\n\t\t\tApplicationBean.logger.s(\"滚动监听:\"+firstVisibleItem);\n\t\t}\n\n\t\t@Override\n        public void onScrollStateChange(AbsListView view, int scrollState) {\n\t\t\tApplicationBean.logger.s(\"滚动状态\");\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n@InjectBefore 表示在组件初始化以前开始调用，因为滚动监听必须在listview被初始化之前赋值，否则无效 将默认使用框架内的滚动监听\n\n\n### 3 无需显示的图片下载\n\n\n\t\tImageDownloader.download(\"url\", new LoaderLister() {\n\t\t\t@Override\n\t\t\tpublic void finishLoader(String url, File file) {\n\t\t\t\tSystem.out.println(\"下载完成\"+file.getPath());\n\t\t\t}\n\t\t\t@Override\n\t\t\tpublic void failLoader(String url) {\n\t\t\t\tSystem.out.println(\"下载失败\");\n\t\t\t}\n\t\t});\n\t\t\n\t\t\n如果需要下载进度\n\n\n\t\tImageDownloader.download(\"url\", new LoaderLister() {\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void startLoader(String url) {\n\t\t\t\tSystem.out.println(\"开始下载\");\n\t\t\t    super.startLoader(url);\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void finishLoader(String url, File file) {\n\t\t\t\tSystem.out.println(\"下载完成\"+file.getPath());\n\t\t\t}\n\t\t\t\n\t\t\t@Override\n\t\t\tpublic void progressLoader(int progress) {\n\t\t\t\tSystem.out.println(\"下载进度\"+progress);\n\t\t\t    super.progressLoader(progress);\n\t\t\t}\n\t\t});\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgdpancheng%2FLoonAndroid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgdpancheng%2FLoonAndroid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgdpancheng%2FLoonAndroid/lists"}