android码农神器 偷懒工具 android懒人框架 LoonAndroid 3 讲解
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、傻瓜式组件类
- 获取图片组件
- 登录组件
使用
- 在项目的Application中进行初始化
- 在assets目录下面mvc.properties的配置设置如下
- 引入loonandroid最新版jar以及依赖包dex.jar
public class App extends Application {
@Override
public void onCreate() {
app = this;
Ioc.getIoc().init(this);
super.onCreate();
}
}
#---------------------------框架基础配置-----------------------------
#配置当前屏幕基于哪个分辨率开发 框架里面所有缩放比例全部来源于此 默认 480 800
standard_w=720
standard_h=1280
#-------------------------设置只允许加载到框架中的包名---------------
#如果不设置,那么默认遍历Manifest中的package,多个可以以逗号隔开
permit=com.android.demo,com.loonandroid.pc.plug
#--------------------------设置不允许解析的包名------------------
#如果不设置,那么默认遍历Manifest中的package,多个可以以逗号隔开
limit=com.example.loonandroid2.R
示例
1 为你去掉繁琐的findViewById
平时我们这么写
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
findViewById();
}
void findViewById(){
.....
.....
.....
.....
};
}
现在我们这么写
@InLayer(R.layout.welcome)
public class WelcomeActivity extends Activity {
// ----------------------------------------------
// View
@InAll
Views v;
static class Views {
public ViewFlow flow;
public CircleFlowIndicator circle;
}
}
2 获取照片
以前我们这么写
点击事件
public void onClick(View v) {
switch (v.getId()) {
case R.id.camera:
Intent intentCamera = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 下面这句指定调用相机拍照后的照片存储的路径
intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory(), Constant.save_user_photo)));
startActivityForResult(intentCamera, 2);
bottomPhotoDialog.dismiss();
break;
case R.id.photo:
Intent intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intent, 1);
bottomPhotoDialog.dismiss();
break;
case R.id.cancle:
bottomPhotoDialog.dismiss();
break;
}
}
裁剪参数
private void startPhoto(Uri url) {
Intent intent = new Intent();
intent.putExtra(Util.IMAGE_URI, url);
intent.putExtra(Util.CROP_IMAGE_WIDTH, 300);
intent.putExtra(Util.CROP_IMAGE_HEIGHT, 300);
intent.putExtra(Util.CIRCLE_CROP, false);
intent.setClass(this, CropActivity.class);
startActivityForResult(intent, 3);
}
activity回调
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// 如果是直接从相册获取
case 1:
if (data == null) {
return;
}
Uri uri = data.getData();
if (uri != null) {
startPhoto(uri);
}
break;
// 如果是调用相机拍照时
case 2:
picture = new File(Environment.getExternalStorageDirectory() + "/" + Constant.save_user_photo);
if (!picture.exists()) {
return;
}
Uri uri2 = Uri.fromFile(picture);
if (uri2 != null) {
startPhoto(uri2);
}
break;
// 取得裁剪后的图片
case 3:
if (data != null) {
bitmap = BitmapFactory.decodeFile(data.getStringExtra(Util.CROP_IMAGE_PATH));
user_photo.setImageBitmap(bitmap);
upload_head(data.getStringExtra(Util.CROP_IMAGE_PATH));
}
break;
default:
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
现在我们这么写
@InLayer(R.layout.activity_getphoto)
public abstract class GetPhotoActivity extends Activity implements PluginPhoto {
@InAll
Views test;
class Views {
ImageView iv_photo;
@InBinder(listener = OnClick.class, method = "click")
Button bt_photo, bt_camera;
}
private void click(View v) {
switch (v.getId()) {
case R.id.bt_photo:
//从相册获取图片
PhotoConfig config = new PhotoConfig();
config.aspectX = 1;
config.aspectY = 2;
config.outputX = 200;
config.outputY = 400;
photo(config);
break;
case R.id.bt_camera:
//从相机获取图片
camera();
break;
}
}
@Override
public void callBack(Object... args) {
Toast.makeText(this, "图片路径:"+args[1], Toast.LENGTH_SHORT).show();
System.out.println("-----------------------------");
test.iv_photo.setImageBitmap((Bitmap)args[0]);
}
}
3 登录
以前这么写
public class LoginActivity extends Acitivity {
TextView login_bt, register;
EditText user_name, user_password, user_code;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
login_bt = (TextView) findViewById(R.id.login_bt);
register = (TextView) findViewById(R.id.register);
user_name = (EditText) findViewById(R.id.user_name);
user_password = (EditText) findViewById(R.id.user_password);
user_code = (EditText) findViewById(R.id.user_code);
}
/**
* 网络请求回调
*/
AjaxCallBack callBack = new AjaxCallBack() {
@Override
public void callBack(ResponseEntity status) {
progressDimss();
switch (status.getStatus()) {
case FastHttp.result_ok:
HashMap<String, Object> data = JsonUtil.initJson(status.getContentAsString());
if (data.get("status").toString().equals("0")) {
showToast(data.get("data").toString());
} else {
App.app.setData("user_id", data.get("data").toString());
startActivity(new Intent(LoginActivity.this, MainActivity.class));
overridePendingTransition(0, 0);
finish();
}
break;
default:
showToast("连接失败,请检查网络后重试");
break;
}
}
@Override
public boolean stop() {
return false;
}
};
public void click(View v) {
switch (v.getId()) {
case R.id.login_bt:
hideSoft(user_name);
hideSoft(user_password);
String name = user_name.getText().toString().trim();
String password = user_password.getText().toString().trim();
String code = user_code.getText().toString().trim();
if (name.length() == 0) {
showToast("用户名不能为空");
return;
}
if (password.length() == 0) {
showToast("密码不能为空");
return;
}
HashMap<String, String> params = new HashMap<String, String>();
params.put("username", name);
params.put("password", password);
showProgress();
FastHttp.ajax(Constant.url_login, params, callBack);
break;
case R.id.register:
startActivity(new Intent(LoginActivity.this, RegisterActivity.class));
overridePendingTransition(0, 0);
break;
}
}
}
现在这么写
会自动填入之前的用户名密码 会自动验证 只要调用save()即可存储登录框中信息
只需要调用AccountEntity datas = getSave();即可获得所有存储的账号信息
@InLayer(R.layout.activity_login)
public abstract class LoginActivity extends Activity implements PluginLogin{
@Override
public void i(LoginConfig config) {
config.init(R.id.ed_number, R.id.ed_password, R.id.ed_submit, R.id.ed_remember);
}
/**
* 当点击登陆按钮,会自动获取输入框内的用户名和密码,对其进行验证
*/
@Override
public void onValiResult(View view) {
if (view == null) {
//验证通过
App.app.http.u(this).login("aaa", "bbb");
}else{
//验证失败给出提示语
Toast.makeText(this, "账号密码不能为空", Toast.LENGTH_SHORT).show();
}
}
@InHttp(HttpUrl.LOGIN_KEY)
public void result(ResponseEntity entity){
if (entity.getStatus() == FastHttp.result_net_err) {
Toast.makeText(this, "网络请求失败,请检查网络", Toast.LENGTH_SHORT).show();
return;
}
if (entity.getContentAsString()==null||entity.getContentAsString().length()==0) {
Toast.makeText(this, "网络请求失败,请检查网络", Toast.LENGTH_SHORT).show();
return;
}
//解析返回的数据
HashMap<String, Object> data = Handler_Json.JsonToCollection(entity.getContentAsString());
int status = Integer.valueOf(data.get("status").toString());
if (status == 0) {
Toast.makeText(this, data.get("data").toString(), Toast.LENGTH_SHORT).show();
return;
}
save();
//清除保存的数据
//clear("bbb");清除账号bbb的缓存
//clear();清除所有缓存
}
}
4 自动验证输入框
平时我们这么写
String name = user_name.getText().toString().trim();
String email = user_email.getText().toString().trim();
String mobile = user_mobile.getText().toString().trim();
String password = user_password.getText().toString().trim();
if (name.length() == 0) {
showToast("用户名不能为空");
return;
}
if (password.length() == 0) {
showToast("密码不能为空");
return;
}
if (password.length() < 6) {
showToast("密码长度必须大于6位");
return;
}
if (email.length() == 0) {
showToast("邮箱不能为空");
return;
}
if (mobile.length() == 0) {
showToast("手机号码不能为空");
return;
}
if (!deal.isChecked()) {
showToast("请先同意用户协议");
return;
}
现在我们这么写
static class Views {
@InVa(value=VaPassword.class,index=1)
EditText tv_password;
@InVa(value=VaPasswordConfirm.class,index=2)
EditText tv_passwordconfirm;
@InVa(value=VaEmail.class,index=3)
EditText tv_email;
@InVa(value=VaMobile.class,index=4)
EditText tv_mobile;
@InVa(value=VaDate.class,index=5)
EditText tv_data;
@InVa(value=VaWeb.class,index=6)
EditText tv_web;
@InVa(value=VaCard.class,index=7)
EditText tv_card;
@InVa(msg = "不能为空",empty=false,index=8)
EditText tv_notnull;
@InVa(reg=Regex.LET_NUM_UNLINE_REG,msg="请输入字母数字或下划线",empty=false,index=9)
EditText tv_number;
@InBinder(listener=OnClick.class,method="click")
Button bt_onclick;
}
public void click(View view) {
Validator.verify(this);
}
@InVaOK
private void onValidationSucceeded() {
Toast.makeText(this, "验证成功", Toast.LENGTH_SHORT).show();
}
@InVaER
public void onValidationFailed(ValidatorCore core) {
if(TextView.class.isAssignableFrom(core.getView().getClass())){
EditText editText = core.getView();
editText.requestFocus();
editText.setFocusable(true);
editText.setError(core.getMsg());
}
}
5 后台进程
启动以前我们这么写
public class LanunchActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
startActivity(new Intent(WelecomeActivity.this, MenuActivity.class));
finish();
}
}).start();
}
}
启动页现在我们这么写
@InLayer(R.layout.activity_first)
public class WelecomeActivity extends Activity {
@Init@InBack
protected void init() throws InterruptedException {
Thread.sleep(3000);
startActivity(new Intent(WelecomeActivity.this, MenuActivity.class));
finish();
}
}
6 Fragment优化
现在我们这么写
@InLayer(value = R.layout.activity_fragment)
public class AutoFragmentActivity extends FragmentActivity {
/**
* {@link InBean}创建了一个Fragment 无需方法onCreateView
*/
@InBean
private AutoFragment fragment;
@Init
void init() {
System.out.println(fragment);
startFragmentAdd(fragment);
}
public void startFragmentAdd(Fragment fragment) {
FragmentManager fragmentManager = this.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fl_test, fragment);
fragmentTransaction.commit();
}
}
@InLayer(R.layout.activity_com)
public class AutoFragment extends Fragment {
@InView(binder = @InBinder(listener = OnClick.class, method = "click"))
Button top;
@Init
void init() {
System.out.println("fragment 初始化完毕");
}
@InBack
private void click(View view) {
System.out.println("这里点击以后进入后台进程");
}
@InListener(ids={R.id.top,R.id.bottom},listeners={OnClick.class})
private void l(View view){
Toast.makeText(view.getContext(), "父类中点击了", Toast.LENGTH_SHORT).show();
}
}
还有很多比较有意思的功能
1 跨进程通讯 集成了tinybus 无需在activity和fragment中注册即可食用
2 adapter去掉了很多不需要的代码
3 网络请求可以切换网络核心,框架只负责分发,力求傻瓜化,来适应外包敏捷开发
等等
感谢以下项目
LoonAndroid 1X 已经上线并告诉我的项目
面吧:一个朋友开发的软件,转为程序员面试使用的神器
酷鱼: 新财富集团的APP 资本人的社交圈
宝贝计划:“宝贝计划”是大连地区专注于儿童教育领域的APP。
泵阀通:是由明作网络在移动互联网领域针对泵阀产业推出的跨时代新媒体
大歌星:娱乐K歌应用,把手机成为录间棚,原版伴奏供你选择。
古道网:是一款记录、分享古代道路的手机应用
拍手吧:高品质音乐,独特的游戏,海量电子书,超好玩的应用软件以及社交体验
有问题反馈
在使用中有任何问题,欢迎反馈给我,可以用以下联系方式跟我交流
- 邮件(gdpancheng#gmail.com, 把#换成@)
- 微信: gdpancheng
- weibo: @码农无码
支持
有意也好,无意也罢,至少写了一个东西,有欣喜,也还有汗水,有谩骂,有沮丧,希望你喜欢我的作品,同时也能支持一下。
源码
android码农神器 偷懒工具 android懒人框架 LoonAndroid 3 讲解的更多相关文章
- Android码农如何一个星期转为iOS码农(不忽悠)
WeTest 导读 作为一个android客户端开发,如果你不懂点ios开发,怎么好意思说自己是客户端开发呢,本文讲解如何让android开发码农在一个星期上手IOS开发 --<记录自己IOS开 ...
- Lombok——一款Java构建工具,“懒人”必备!!(idea版)
一.简介 Lombok 是一种 Jav 构建工具,可用来帮助开发人员消除 Java 的冗长代码,尤其是对于简单的 Java 对象(POJO).它是通过注解实现这一目的. 二.使用 1.在idea中安装 ...
- Android开发者不可或缺的四大工具
Android开发者不可或缺的四大工具 android以其极强的开放性吸引着世界各地的开发者去开发各种各样的移动应用开发,而各种SDK更是为各个层次的开发者提供了一个可以尽情展示他们专业技能和创造性的 ...
- Android 虚拟机Dalvik、Android各种java包功能、Android相关文件类型、应用程序结构分析、ADB
Android虚拟机Dalvik Dalvik冲击 随着Google 的AndroidSDK 的发布,关于它的API 以及在移动电话领域所带来的预期影响这些方面的讨论不胜枚举.不过,其中的一个话题在J ...
- 【原创】初识懒人开发库---ButterKnife
今天再看别人代码的时候,看到了自己没见过的代码,看起来挺方便的,具体代码如下: @InjectView(R.id.iv_left) ImageView iv_left; @InjectView(R.i ...
- 懒人模式开启Android模块自动化Api之旅
推荐阅读: 滴滴Booster移动App质量优化框架-学习之旅 一 Android 模块Api化演练 不一样视角的Glide剖析(一) 在将业务进行模块化时,避免不了模块页面路由和模块通信, 大多数我 ...
- 码农高效率工作必备工具之 StrokesPlus
鲁迅先生曾经说过:不想偷懒的码农不是好码农. 我今天偏偏就勤奋一下,把压箱底的偷懒神器分享给大家. StrokesPlus(简称S+)是一款非常好用的鼠标手势软件,通过按下鼠标键画手势,或者按快捷键, ...
- Android—关于自定义对话框的工具类
开发中有很多地方会用到自定义对话框,为了避免不必要的城府代码,在此总结出一个工具类. 弹出对话框的地方很多,但是都大同小异,不同无非就是提示内容或者图片不同,下面这个类是将提示内容和图片放到了自定义函 ...
- Android高手速成--第二部分 工具库
主要包括那些不错的开发库,包括依赖注入框架.图片缓存.网络相关.数据库ORM建模.Android公共库.Android 高版本向低版本兼容.多媒体相关及其他. 一.依赖注入DI 通过依赖注入减少Vie ...
随机推荐
- COM 浅谈
ArcObject 是基于 COM(Microsoft Component Object Model),即组件对象模型.虽然ArcGIS的终端用户不用理解什么是COM,但是作为基于ArcObject的 ...
- linux下登录出现-bash-3.2#解决办法
1:下载 安装 csh yum install csh 2:再切换即可
- MFC 创建选项卡
1.创建三个选项卡Dialog窗体,ID分别改为porpTest1.porpTest2.porpTest3 2.创建三个选项卡类,类名分别为CPropTest1.CPropTest2.CPropTes ...
- [Leetcode][019] Remove Nth Node From End of List (Java)
题目在这里: https://leetcode.com/problems/remove-nth-node-from-end-of-list/ [标签] Linked List; Two Pointer ...
- [Mugeda HTML5技术教程之7]添加动画
前一节我们讲述了怎么在新建的作品中添加元素,元素加好以后我们还想让他们动起来,来实现比较炫的效果.这节我们将要讲述怎么给元素添加动画.Mugeda动画是通过时间轴和帧来实现的.通过在时间轴上创建图层和 ...
- JS 操作一个数据值
任何语言都有自己的操作数据的方法: Js也不例外,js有3种重要的方式来操作一个数据值. 1>复制它.例如把它赋给一个新的变量. 2>把它作为参数传递给一个函数或方法. 3>可以和其 ...
- 这样就算会了PHP么?-3
关于循环,IF,WHILE.... <?php $month = date("n"); $today = date("j"); if ($today &g ...
- UltraEdit-32 恢复到初始默认配置
不小心把UltraEdit-32搞乱了,字体不管怎么设置,都回不去了..然后那些菜单也被弄得乱七糟八的....于是就想把这些设置都搞成默认的.重装UltraEdit-32.清理注册表.结果发现都没有用 ...
- 简要介绍如何集成Vitamio安卓版SDK
1.下载VitamioBundle的最新稳定,这里下载的是最新版4.2.2. 2.解压缩后,导入 Vitamio 库工程(即vitamio)和Demo工程(即vitamio--sample)到 Ecl ...
- jQuery 弹出div层
目的:使用jQuery弹出一个div窗口:这种效果经常应用于页面内容的展示,登录效果的实现.其实,实现这种效果有好多种方式: 效果如下: 代码如下: <html> <head> ...