LoonAndroid 3.0

Loonandroid是一个注解框架,不涉及任何UI效果,目的是一个功能一个方法,以方法为最小颗粒度对功能进行拆解。把功能傻瓜化,简单化,去掉重复性的代码,隐藏复杂的实现。以便团队合作或者后期修改变得简单。说框架是夸大了,主要是因为我比较喜欢偷懒,对于一个码农来说,能够偷懒,并且在不影响项目质量的情况下,是不容易的。


很多朋友看到注解就就要吐槽,会影响性能什么的。注解,确实会影响性能。通过注解自动注入,反射会让程序变慢50~100毫秒左右,从体验感基本感觉不出来.硬件性能好的手机可以忽略,经过测试无需太大的担心。我是做外包的,初衷是在不影响项目质量的前提下减少我的工作量,而且BUG其他人改起来相对比较容易,本工具专属外包码农,如果你想做精细,很在意性能数据,请看看就好。


LoonAndroid 3 是LoonAndroid改良版,之前的版本存在内存无法释放的问题。增加了一些新的功能,让开发变得非主流。

特别声明:
版本3x框架还未在实际生产中验证,目前只拥有demo和我改造的一个项目,请小心谨慎,如有使用,请告知我,我会跟踪相应BUG以及性能,以做到及时修复。
o2oDemo这个是我根据别人项目改写的,没改写完,没改动界面,没有改动工具类,只改动了activity和adapter以及网络请求

release 3.0

1、基本功能

  • InLayer注解
  • InPlayer 注解
  • Activity生命周期注解
  • InView注解
  • InSource注解
  • InAll注解
  • 后台进程注解
  • 方法点击事件注解
  • 基类注解
  • 自动Fragment注解
  • 手动Fragment注解

2、适配器功能

  • 无适配器
  • 无参baseAdapter
  • 自定义一adapter
  • 自定义二adapter
  • 自动绑定一adapter
  • 自动绑定二adapter
  • 通用适配器

3、综合功能集合

  • 网络请求模块
  • 输入验证
  • 跨进程通讯
  • Json格式化类
  • 倒计时类

4、傻瓜式下拉刷新

  • Listview
  • Grid
  • 横向Scrollview
  • 纵向Scrollview
  • 横向ViewPage
  • 纵向ViewPage
  • WebView

5、自定义模块类

  • 自定义模块XML中使用
  • 自定义模块变量使用

6、傻瓜式组件类

  • 获取图片组件
  • 登录组件

使用

  1. 在项目的Application中进行初始化
  2. 在assets目录下面mvc.properties的配置设置如下
  3. 引入loonandroid最新版jar以及依赖包dex.jar
  1. public class App extends Application {
  2. @Override
  3. public void onCreate() {
  4. app = this;
  5. Ioc.getIoc().init(this);
  6. super.onCreate();
  7. }
  8. }
  1. #---------------------------框架基础配置-----------------------------
  2. #配置当前屏幕基于哪个分辨率开发 框架里面所有缩放比例全部来源于此 默认 480 800
  3. standard_w=720
  4. standard_h=1280
  5. #-------------------------设置只允许加载到框架中的包名---------------
  6. #如果不设置,那么默认遍历Manifest中的package,多个可以以逗号隔开
  7. permit=com.android.demo,com.loonandroid.pc.plug
  8. #--------------------------设置不允许解析的包名------------------
  9. #如果不设置,那么默认遍历Manifest中的package,多个可以以逗号隔开
  10. limit=com.example.loonandroid2.R

示例

1 为你去掉繁琐的findViewById

平时我们这么写

  1. public class MyActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_demo);
  6. findViewById();
  7. }
  8. void findViewById(){
  9. .....
  10. .....
  11. .....
  12. .....
  13. };
  14. }

现在我们这么写

  1. @InLayer(R.layout.welcome)
  2. public class WelcomeActivity extends Activity {
  3. // ----------------------------------------------
  4. // View
  5. @InAll
  6. Views v;
  7. static class Views {
  8. public ViewFlow flow;
  9. public CircleFlowIndicator circle;
  10. }
  11. }

2 获取照片

以前我们这么写

  1. 点击事件
  2. public void onClick(View v) {
  3. switch (v.getId()) {
  4. case R.id.camera:
  5. Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  6. // 下面这句指定调用相机拍照后的照片存储的路径
  7. intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), Constant.save_user_photo)));
  8. startActivityForResult(intentCamera, 2);
  9. bottomPhotoDialog.dismiss();
  10. break;
  11. case R.id.photo:
  12. Intent intent = new Intent(Intent.ACTION_PICK, null);
  13. intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
  14. startActivityForResult(intent, 1);
  15. bottomPhotoDialog.dismiss();
  16. break;
  17. case R.id.cancle:
  18. bottomPhotoDialog.dismiss();
  19. break;
  20. }
  21. }
  22. 裁剪参数
  23. private void startPhoto(Uri url) {
  24. Intent intent = new Intent();
  25. intent.putExtra(Util.IMAGE_URI, url);
  26. intent.putExtra(Util.CROP_IMAGE_WIDTH, 300);
  27. intent.putExtra(Util.CROP_IMAGE_HEIGHT, 300);
  28. intent.putExtra(Util.CIRCLE_CROP, false);
  29. intent.setClass(this, CropActivity.class);
  30. startActivityForResult(intent, 3);
  31. }
  32. activity回调
  33. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  34. switch (requestCode) {
  35. // 如果是直接从相册获取
  36. case 1:
  37. if (data == null) {
  38. return;
  39. }
  40. Uri uri = data.getData();
  41. if (uri != null) {
  42. startPhoto(uri);
  43. }
  44. break;
  45. // 如果是调用相机拍照时
  46. case 2:
  47. picture = new File(Environment.getExternalStorageDirectory() + "/" + Constant.save_user_photo);
  48. if (!picture.exists()) {
  49. return;
  50. }
  51. Uri uri2 = Uri.fromFile(picture);
  52. if (uri2 != null) {
  53. startPhoto(uri2);
  54. }
  55. break;
  56. // 取得裁剪后的图片
  57. case 3:
  58. if (data != null) {
  59. bitmap = BitmapFactory.decodeFile(data.getStringExtra(Util.CROP_IMAGE_PATH));
  60. user_photo.setImageBitmap(bitmap);
  61. upload_head(data.getStringExtra(Util.CROP_IMAGE_PATH));
  62. }
  63. break;
  64. default:
  65. break;
  66. }
  67. super.onActivityResult(requestCode, resultCode, data);
  68. }

现在我们这么写

  1. @InLayer(R.layout.activity_getphoto)
  2. public abstract class GetPhotoActivity extends Activity implements PluginPhoto {
  3. @InAll
  4. Views test;
  5. class Views {
  6. ImageView iv_photo;
  7. @InBinder(listener = OnClick.class, method = "click")
  8. Button bt_photo, bt_camera;
  9. }
  10. private void click(View v) {
  11. switch (v.getId()) {
  12. case R.id.bt_photo:
  13. //从相册获取图片
  14. PhotoConfig config = new PhotoConfig();
  15. config.aspectX = 1;
  16. config.aspectY = 2;
  17. config.outputX = 200;
  18. config.outputY = 400;
  19. photo(config);
  20. break;
  21. case R.id.bt_camera:
  22. //从相机获取图片
  23. camera();
  24. break;
  25. }
  26. }
  27. @Override
  28. public void callBack(Object... args) {
  29. Toast.makeText(this, "图片路径:"+args[1], Toast.LENGTH_SHORT).show();
  30. System.out.println("-----------------------------");
  31. test.iv_photo.setImageBitmap((Bitmap)args[0]);
  32. }
  33. }

3 登录

以前这么写

  1. public class LoginActivity extends Acitivity {
  2. TextView login_bt, register;
  3. EditText user_name, user_password, user_code;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.login);
  8. login_bt = (TextView) findViewById(R.id.login_bt);
  9. register = (TextView) findViewById(R.id.register);
  10. user_name = (EditText) findViewById(R.id.user_name);
  11. user_password = (EditText) findViewById(R.id.user_password);
  12. user_code = (EditText) findViewById(R.id.user_code);
  13. }
  14. /**
  15. * 网络请求回调
  16. */
  17. AjaxCallBack callBack = new AjaxCallBack() {
  18. @Override
  19. public void callBack(ResponseEntity status) {
  20. progressDimss();
  21. switch (status.getStatus()) {
  22. case FastHttp.result_ok:
  23. HashMap<String, Object> data = JsonUtil.initJson(status.getContentAsString());
  24. if (data.get("status").toString().equals("0")) {
  25. showToast(data.get("data").toString());
  26. } else {
  27. App.app.setData("user_id", data.get("data").toString());
  28. startActivity(new Intent(LoginActivity.this, MainActivity.class));
  29. overridePendingTransition(0, 0);
  30. finish();
  31. }
  32. break;
  33. default:
  34. showToast("连接失败,请检查网络后重试");
  35. break;
  36. }
  37. }
  38. @Override
  39. public boolean stop() {
  40. return false;
  41. }
  42. };
  43. public void click(View v) {
  44. switch (v.getId()) {
  45. case R.id.login_bt:
  46. hideSoft(user_name);
  47. hideSoft(user_password);
  48. String name = user_name.getText().toString().trim();
  49. String password = user_password.getText().toString().trim();
  50. String code = user_code.getText().toString().trim();
  51. if (name.length() == 0) {
  52. showToast("用户名不能为空");
  53. return;
  54. }
  55. if (password.length() == 0) {
  56. showToast("密码不能为空");
  57. return;
  58. }
  59. HashMap<String, String> params = new HashMap<String, String>();
  60. params.put("username", name);
  61. params.put("password", password);
  62. showProgress();
  63. FastHttp.ajax(Constant.url_login, params, callBack);
  64. break;
  65. case R.id.register:
  66. startActivity(new Intent(LoginActivity.this, RegisterActivity.class));
  67. overridePendingTransition(0, 0);
  68. break;
  69. }
  70. }
  71. }

现在这么写

  1. 会自动填入之前的用户名密码 会自动验证 只要调用save()即可存储登录框中信息
  2. 只需要调用AccountEntity datas = getSave();即可获得所有存储的账号信息
  3. @InLayer(R.layout.activity_login)
  4. public abstract class LoginActivity extends Activity implements PluginLogin{
  5. @Override
  6. public void i(LoginConfig config) {
  7. config.init(R.id.ed_number, R.id.ed_password, R.id.ed_submit, R.id.ed_remember);
  8. }
  9. /**
  10. * 当点击登陆按钮,会自动获取输入框内的用户名和密码,对其进行验证
  11. */
  12. @Override
  13. public void onValiResult(View view) {
  14. if (view == null) {
  15. //验证通过
  16. App.app.http.u(this).login("aaa", "bbb");
  17. }else{
  18. //验证失败给出提示语
  19. Toast.makeText(this, "账号密码不能为空", Toast.LENGTH_SHORT).show();
  20. }
  21. }
  22. @InHttp(HttpUrl.LOGIN_KEY)
  23. public void result(ResponseEntity entity){
  24. if (entity.getStatus() == FastHttp.result_net_err) {
  25. Toast.makeText(this, "网络请求失败,请检查网络", Toast.LENGTH_SHORT).show();
  26. return;
  27. }
  28. if (entity.getContentAsString()==null||entity.getContentAsString().length()==0) {
  29. Toast.makeText(this, "网络请求失败,请检查网络", Toast.LENGTH_SHORT).show();
  30. return;
  31. }
  32. //解析返回的数据
  33. HashMap<String, Object> data = Handler_Json.JsonToCollection(entity.getContentAsString());
  34. int status = Integer.valueOf(data.get("status").toString());
  35. if (status == 0) {
  36. Toast.makeText(this, data.get("data").toString(), Toast.LENGTH_SHORT).show();
  37. return;
  38. }
  39. save();
  40. //清除保存的数据
  41. //clear("bbb");清除账号bbb的缓存
  42. //clear();清除所有缓存
  43. }
  44. }

4 自动验证输入框

平时我们这么写

  1. String name = user_name.getText().toString().trim();
  2. String email = user_email.getText().toString().trim();
  3. String mobile = user_mobile.getText().toString().trim();
  4. String password = user_password.getText().toString().trim();
  5. if (name.length() == 0) {
  6. showToast("用户名不能为空");
  7. return;
  8. }
  9. if (password.length() == 0) {
  10. showToast("密码不能为空");
  11. return;
  12. }
  13. if (password.length() < 6) {
  14. showToast("密码长度必须大于6位");
  15. return;
  16. }
  17. if (email.length() == 0) {
  18. showToast("邮箱不能为空");
  19. return;
  20. }
  21. if (mobile.length() == 0) {
  22. showToast("手机号码不能为空");
  23. return;
  24. }
  25. if (!deal.isChecked()) {
  26. showToast("请先同意用户协议");
  27. return;
  28. }

现在我们这么写

  1. static class Views {
  2. @InVa(value=VaPassword.class,index=1)
  3. EditText tv_password;
  4. @InVa(value=VaPasswordConfirm.class,index=2)
  5. EditText tv_passwordconfirm;
  6. @InVa(value=VaEmail.class,index=3)
  7. EditText tv_email;
  8. @InVa(value=VaMobile.class,index=4)
  9. EditText tv_mobile;
  10. @InVa(value=VaDate.class,index=5)
  11. EditText tv_data;
  12. @InVa(value=VaWeb.class,index=6)
  13. EditText tv_web;
  14. @InVa(value=VaCard.class,index=7)
  15. EditText tv_card;
  16. @InVa(msg = "不能为空",empty=false,index=8)
  17. EditText tv_notnull;
  18. @InVa(reg=Regex.LET_NUM_UNLINE_REG,msg="请输入字母数字或下划线",empty=false,index=9)
  19. EditText tv_number;
  20. @InBinder(listener=OnClick.class,method="click")
  21. Button bt_onclick;
  22. }
  23. public void click(View view) {
  24. Validator.verify(this);
  25. }
  26. @InVaOK
  27. private void onValidationSucceeded() {
  28. Toast.makeText(this, "验证成功", Toast.LENGTH_SHORT).show();
  29. }
  30. @InVaER
  31. public void onValidationFailed(ValidatorCore core) {
  32. if(TextView.class.isAssignableFrom(core.getView().getClass())){
  33. EditText editText = core.getView();
  34. editText.requestFocus();
  35. editText.setFocusable(true);
  36. editText.setError(core.getMsg());
  37. }
  38. }

5 后台进程

启动以前我们这么写

  1. public class LanunchActivity extends Activity {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. try {
  9. Thread.sleep(3000);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. startActivity(new Intent(WelecomeActivity.this, MenuActivity.class));
  14. finish();
  15. }
  16. }).start();
  17. }
  18. }

启动页现在我们这么写

  1. @InLayer(R.layout.activity_first)
  2. public class WelecomeActivity extends Activity {
  3. @Init@InBack
  4. protected void init() throws InterruptedException {
  5. Thread.sleep(3000);
  6. startActivity(new Intent(WelecomeActivity.this, MenuActivity.class));
  7. finish();
  8. }
  9. }

6 Fragment优化

现在我们这么写

  1. @InLayer(value = R.layout.activity_fragment)
  2. public class AutoFragmentActivity extends FragmentActivity {
  3. /**
  4. * {@link InBean}创建了一个Fragment 无需方法onCreateView
  5. */
  6. @InBean
  7. private AutoFragment fragment;
  8. @Init
  9. void init() {
  10. System.out.println(fragment);
  11. startFragmentAdd(fragment);
  12. }
  13. public void startFragmentAdd(Fragment fragment) {
  14. FragmentManager fragmentManager = this.getSupportFragmentManager();
  15. FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
  16. fragmentTransaction.replace(R.id.fl_test, fragment);
  17. fragmentTransaction.commit();
  18. }
  19. }
  20. @InLayer(R.layout.activity_com)
  21. public class AutoFragment extends Fragment {
  22. @InView(binder = @InBinder(listener = OnClick.class, method = "click"))
  23. Button top;
  24. @Init
  25. void init() {
  26. System.out.println("fragment 初始化完毕");
  27. }
  28. @InBack
  29. private void click(View view) {
  30. System.out.println("这里点击以后进入后台进程");
  31. }
  32. @InListener(ids={R.id.top,R.id.bottom},listeners={OnClick.class})
  33. private void l(View view){
  34. Toast.makeText(view.getContext(), "父类中点击了", Toast.LENGTH_SHORT).show();
  35. }
  36. }

还有很多比较有意思的功能

1 跨进程通讯 集成了tinybus 无需在activity和fragment中注册即可食用

2 adapter去掉了很多不需要的代码

3 网络请求可以切换网络核心,框架只负责分发,力求傻瓜化,来适应外包敏捷开发

等等

感谢以下项目

LoonAndroid 1X 已经上线并告诉我的项目

面吧:一个朋友开发的软件,转为程序员面试使用的神器

酷鱼: 新财富集团的APP 资本人的社交圈

宝贝计划:“宝贝计划”是大连地区专注于儿童教育领域的APP。

泵阀通:是由明作网络在移动互联网领域针对泵阀产业推出的跨时代新媒体

大歌星:娱乐K歌应用,把手机成为录间棚,原版伴奏供你选择。

古道网:是一款记录、分享古代道路的手机应用

拍手吧:高品质音乐,独特的游戏,海量电子书,超好玩的应用软件以及社交体验

有问题反馈

在使用中有任何问题,欢迎反馈给我,可以用以下联系方式跟我交流

  • 邮件(gdpancheng#gmail.com, 把#换成@)
  • 微信: gdpancheng
  • weibo: @码农无码

支持

有意也好,无意也罢,至少写了一个东西,有欣喜,也还有汗水,有谩骂,有沮丧,希望你喜欢我的作品,同时也能支持一下。

源码

请移步

开源中国

GitHub

android码农神器 偷懒工具 android懒人框架 LoonAndroid 3 讲解的更多相关文章

  1. Android码农如何一个星期转为iOS码农(不忽悠)

    WeTest 导读 作为一个android客户端开发,如果你不懂点ios开发,怎么好意思说自己是客户端开发呢,本文讲解如何让android开发码农在一个星期上手IOS开发 --<记录自己IOS开 ...

  2. Lombok——一款Java构建工具,“懒人”必备!!(idea版)

    一.简介 Lombok 是一种 Jav 构建工具,可用来帮助开发人员消除 Java 的冗长代码,尤其是对于简单的 Java 对象(POJO).它是通过注解实现这一目的. 二.使用 1.在idea中安装 ...

  3. Android开发者不可或缺的四大工具

    Android开发者不可或缺的四大工具 android以其极强的开放性吸引着世界各地的开发者去开发各种各样的移动应用开发,而各种SDK更是为各个层次的开发者提供了一个可以尽情展示他们专业技能和创造性的 ...

  4. Android 虚拟机Dalvik、Android各种java包功能、Android相关文件类型、应用程序结构分析、ADB

    Android虚拟机Dalvik Dalvik冲击 随着Google 的AndroidSDK 的发布,关于它的API 以及在移动电话领域所带来的预期影响这些方面的讨论不胜枚举.不过,其中的一个话题在J ...

  5. 【原创】初识懒人开发库---ButterKnife

    今天再看别人代码的时候,看到了自己没见过的代码,看起来挺方便的,具体代码如下: @InjectView(R.id.iv_left) ImageView iv_left; @InjectView(R.i ...

  6. 懒人模式开启Android模块自动化Api之旅

    推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 在将业务进行模块化时,避免不了模块页面路由和模块通信, 大多数我 ...

  7. 码农高效率工作必备工具之 StrokesPlus

    鲁迅先生曾经说过:不想偷懒的码农不是好码农. 我今天偏偏就勤奋一下,把压箱底的偷懒神器分享给大家. StrokesPlus(简称S+)是一款非常好用的鼠标手势软件,通过按下鼠标键画手势,或者按快捷键, ...

  8. Android—关于自定义对话框的工具类

    开发中有很多地方会用到自定义对话框,为了避免不必要的城府代码,在此总结出一个工具类. 弹出对话框的地方很多,但是都大同小异,不同无非就是提示内容或者图片不同,下面这个类是将提示内容和图片放到了自定义函 ...

  9. Android高手速成--第二部分 工具库

    主要包括那些不错的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. 一.依赖注入DI 通过依赖注入减少Vie ...

随机推荐

  1. javascript改变背景/字体颜色(Through the javascript to change the background and font color)

    鼠标移动到.移出DIV时修改DIV的颜色: 1.Change the font and Div background color--function <div style="width ...

  2. .NET winform 在listview中添加progressbar

    找了好长时间没找到,后来索性自己写了一个: 首先,在往listview加载数据的事件里添加progressbar: foreach (string d in arr) { ; item = new L ...

  3. C 语言链表操作例程 (待完善)

    #include<stdio.h>#include<malloc.h>#include<conio.h>#include<stdlib.h>#inclu ...

  4. While reading XXX pngcrush caught libpng error: N

    错误一:   While reading /XXX/XXX/XXX/img1.png pngcrush caught libpng error:   Not a PNG filCould not fi ...

  5. 程序被送入后台后,向 iOS 借时间,完成长期任务-备

    12.2.2. 方案 使用UIApplication的beginBackgroundTaskWithExpirationHandler: 实例方法.在你完成任务后,调用UIApplication的en ...

  6. 用root帐号切换其他帐号提示 su: warning: cannot change directory to /home/oracle: Permission denied

    用root帐号切换其他帐号提示: 出错原因: 基本上是根目录或者是/home/oracle目录权限的问题 解决办法: 更改根目录权限为755,并保证对应用户主目录的所属用户和所属组一致和用户名一致. ...

  7. 通过设计让APP变快的6个方法

    我们都知道不管网页还是移动应用,响应速度都是最重要的体验指标之一,并且移动应用的网络环境不稳定,速度的体验显得尤为重要.其实速度优化不仅是程序员的事,设计,也能够让APP变得更快. 1. 后台执行 这 ...

  8. pfsense下的流量管理(转)

    http://www.pppei.net/blog/post/331 在作流量管理时,这些概念很重要,不要迷失.. 这里再对Limiter 的源地址和目的地址做个说明,因为limiter是被应用在La ...

  9. 通过JCONSOLE监控TOMCAT的JVM使用情况

    这个也是要学入一下,JVMr 虚拟机原理不可少. 参考配置URL“: http://blog.163.com/kangle0925@126/blog/static/277581982011527723 ...

  10. Linux环境下使用JFS文件系统

    Linux环境下使用JFS文件系统 JFS是IBM公司为linux系统开发的一个日志文件系统.从IBM的实力及它对Linux的态度来看,JFS应该是未来日志文件系统中最具实力的一个文件系统. JFS提 ...