Need help with LoonAndroid3?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

gdpancheng
135 Stars 51 Forks 6 Commits 8 Opened issues

Description

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

Services available

!
?

Need anything else?

Contributors list

# 99,667
Java
6 commits

LoonAndroid 3.0

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


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


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

特别声明:如有BUG,请告知我,我会跟踪相应BUG以及性能,以做到及时修复。
o2oDemo是我根据别人项目改写的,没改写完,没改动界面,没有改动工具类,只改动了activity和adapter以及网络请求

[TOC]

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

    public class App extends Application {
    @Override
    public void onCreate() {
        app = this;
        Ioc.getIoc().init(this);
        super.onCreate();
    }
    }
    
    ```

    ---------------------------框架基础配置-----------------------------

    配置当前屏幕基于哪个分辨率开发 框架里面所有缩放比例全部来源于此 默认 480 800

    standardw=720 standardh=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 ivphoto; @InBinder(listener = OnClick.class, method = "click") Button btphoto, bt_camera; }

    private void click(View v) { switch (v.getId()) { case R.id.btphoto: //从相册获取图片 PhotoConfig config = new PhotoConfig(); config.aspectX = 1; config.aspectY = 2; config.outputX = 200; config.outputY = 400; photo(config); break; case R.id.btcamera: //从相机获取图片 camera(); break; } }

    @Override public void callBack(Object... args) { Toast.makeText(this, "图片路径:"+args[1], Toast.LENGTHSHORT).show(); System.out.println("-----------------------------"); test.ivphoto.setImageBitmap((Bitmap)args[0]); } }

    **3 登录**

    `以前这么写`
    public class LoginActivity extends Acitivity {

    TextView loginbt, register; EditText username, userpassword, usercode;

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.login); loginbt = (TextView) findViewById(R.id.loginbt); register = (TextView) findViewById(R.id.register); username = (EditText) findViewById(R.id.username); userpassword = (EditText) findViewById(R.id.userpassword); usercode = (EditText) findViewById(R.id.usercode); }

    /** * 网络请求回调 */ AjaxCallBack callBack = new AjaxCallBack() { @Override public void callBack(ResponseEntity status) { progressDimss(); switch (status.getStatus()) { case FastHttp.resultok: HashMap data = JsonUtil.initJson(status.getContentAsString()); if (data.get("status").toString().equals("0")) { showToast(data.get("data").toString()); } else { App.app.setData("userid", 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.loginbt: hideSoft(username); 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 params = new HashMap();
        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.ednumber, R.id.edpassword, R.id.edsubmit, R.id.edremember); }

    /** * 当点击登陆按钮,会自动获取输入框内的用户名和密码,对其进行验证 */ @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.LOGINKEY) public void result(ResponseEntity entity){ if (entity.getStatus() == FastHttp.resultneterr) { Toast.makeText(this, "网络请求失败,请检查网络", Toast.LENGTHSHORT).show(); return; } if (entity.getContentAsString()==null||entity.getContentAsString().length()==0) { Toast.makeText(this, "网络请求失败,请检查网络", Toast.LENGTHSHORT).show(); return; } //解析返回的数据 HashMap data = HandlerJson.JsonToCollection(entity.getContentAsString()); int status = Integer.valueOf(data.get("status").toString()); if (status == 0) { Toast.makeText(this, data.get("data").toString(), Toast.LENGTHSHORT).show(); return; } save(); //清除保存的数据 //clear("bbb");清除账号bbb的缓存 //clear();清除所有缓存 } }

    **4 自动验证输入框**

    `平时我们这么写`
    String name = username.getText().toString().trim(); String email = useremail.getText().toString().trim(); String mobile = usermobile.getText().toString().trim(); String password = userpassword.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 tvpasswordconfirm; @InVa(value=VaEmail.class,index=3) EditText tvemail; @InVa(value=VaMobile.class,index=4) EditText tvmobile; @InVa(value=VaDate.class,index=5) EditText tvdata; @InVa(value=VaWeb.class,index=6) EditText tvweb; @InVa(value=VaCard.class,index=7) EditText tvcard; @InVa(msg = "不能为空",empty=false,index=8) EditText tvnotnull; @InVa(reg=Regex.LETNUMUNLINEREG,msg="请输入字母数字或下划线",empty=false,index=9) EditText tvnumber; @InBinder(listener=OnClick.class,method="click") Button btonclick; } 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 {
    @[email protected]
    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: @码农无码

捐助开发者

有意也好,无意也罢,至少写了一个东西,有欣喜,也还有汗水,有谩骂,有沮丧,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场,没钱捧个人场,谢谢各位。

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.