Onelong

分享知识,与你一起进步......
RSS icon Home icon
  • 学习小结

    post by onelong / 2016-12-17 21:41 Saturday [android]
    最近一直想聊一聊Android的那些事,对于android,想起来都荒废了一年多了,这些年更新的技术都不曾折腾过。这一年来所有折腾的重点是iOS,最近突然想补一补那些错过的事情,于是拿起来折腾了一个月左右,渐渐的觉得精力远不如从前了,也是这样不得不思考是不是应该专注一门呢?学习的都不是什么新技术,都是现在看着比较流行的技术。例如dagger2、rxjava2、rxandroid2、rxlifecycle2、retrofit2、 okhttp3、gson/jackjson、glide/picasso、Databinding等。今年折腾过Spring,然后理解Dagger2的时候还是比较容易的,一个框架的基础思想“依赖注入,控制反转”。在以往的日子里面,一直不喜欢用注解了,因为一直觉得注解是运行时反射实现的,效率不高,尤其是在android上,今年年初的时候就有人问我,Dagger、RoboGuice和ButterKnife都是用注解的,有什么不同呢,其实retrofit2也是使用注解的,Dagger和RoboGuice开始的确是运行时反射的,但是为什么还是那么多人用呢,软件开发有时候考虑的不仅仅是性能,还有架构和可维护性,在java的世界里面,spring是行业的标配。Dagger和RoboGuice是移动领域的spring,后来Google重写了Dagger,也是这样由运行时的变成了编译时处理的注解了。这样的话,对性能影响非常小。除了Dagger2,还有ButterKnife都是编译时处理注解的,只是通过注解处理器生成相应的java代码。Roboguice 在运行时利用反射进行依赖注入,性能不好,不再更新了,Dagger 利用编译期的注解处理来生成依赖注入的代码,尽可能的减少了反射的使用,ButterKnife 只是View绑定,预处理注解,只是View绑定,与框架无关。对于View的绑定,Databinding逐渐成熟了,一年前就想用上了,碍于技术人员和项目进度的要求,最终没有用上了。对于retrofit2,虽然使用了反射和动态代理,但是对使用者更友好。okhttp3面向切面的编程框架,使用拦截器在中间过程定制个性化需求。至于rxjava2、rxandroid2、rxlifecycle2相关的东西,主要是用于组件之间解耦。具体的分析就不深入说了,很多测试代码都放在GitHub了。 
    https://github.com/OnelongX/GoApp2
    https://github.com/OnelongX/HttpClient  java项目
    https://github.com/OnelongX/Databinding
    https://github.com/OnelongX/JsonTest 
    感兴趣的可以看看。

  • DataBinding

    post by onelong / 2016-12-9 3:56 Friday [android]

    DataBinding主要解决了两个问题:

    • 需要多次使用findViewById,损害了应用性能且令人厌烦 
    • 更新UI数据需切换至UI线程,将数据分解映射到各个view比较麻烦

    DataBinding基本使用包括以下内容:

    • 单纯的摆脱findviewbyid
    • 绑定基本数据类型及String
    • 绑定Model数据
    • 绑定事件
    • 通过静态方法转换数据类型
    • 通过运算符操作数据
    • 自定义Binding的类名
    • 绑定相同Model的操作
    • model变量改变自动更新数据
    • 绑定List/Map等集合数据
    • Observable自动更新
    • Databinding与include标签的结合
    • DataBinding与RecyclerView的结合

    命名规则

    • 布局通过DataBindingUtils.setContentView()加载到代码中,而且会生成对应一个Binding对象,对象名是布局文件文称加上Binding后缀
    • 通过Binding对象.id名称,就相当于拿到了指定的布局中的id的控件了,使用起来和findviewbyid获取的控件是一样的
    • 在布局中是通过@{}来绑定数据的,{}中是布局中该控件属性对应的数据类型数据,同时还可以支持运算符运算和静态方法调用和转换
    binding设置数据有2中方式:
    1.binding.setUser(user) 
    2.binding.setVariable(BR.user,user)–采用BR指
    1.android:onClick="@{event.click1}"
    2.android:onClick="@{event::click2}"
    3.android:onClick="@{()->event.cilck3(title4)}"
     [注]:()->event.cilck3(title4)是lambda表达式写法,
     也可以写成:(view)->event.cilck3(title4),前面(view)表示onClick方法的传递的参数,
     如果event.click3()方法中不需要用到view参数,可以将view省略。
     当然event.click1也可以写成(view)->event.click1(view),将onClick(View view)的view参数传递给event.click1(view)方法。
    大概就这意思,以下是伪代码
    onclick(View view){
         event.click1(view)
    }
    <?xml version="1.0" encoding="utf-8"?><!--布局以layout作为根布局-->
    <layout>
    
        <data>
            <!--绑定基本数据类型及String-->
            <!--name:   和java代码中的对象是类似的,名字自定义-->
            <!--type:   和java代码中的类型是一致的-->
            <variable
                name="content"
                type="String" />
    
            <variable
                name="enabled"
                type="boolean" />
                <!--绑定Model数据2中形式,一中是导入该类型的,一种指定类型的全称,和java一样-->
            <!--  方式一 -->
            <variable
                name="user"
                type="www.zhang.com.databinding.User" />
            <!--  方式二 -->
            <!--<import type="www.zhang.com.databinding.User" />-->
            <!--<variable-->
                <!--name="user"-->
                <!--type="User" />-->
        </data>
        <!--我们需要展示的布局-->
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <!--绑定基本数据类型及String的使用是通过   @{数据类型的对象}  通过对应数据类型的控制显示-->
            <Button
                android:id="@+id/main_tv2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:clickable="@{enabled}"
                android:text="@{content}" />
           <Button
                android:id="@+id/main_btn3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{user.text}" /><!--这里user.text相当于user.getText()-->
        </LinearLayout>
    </layout>
    <data>
         <variable
                name="user"
                type="www.zhang.com.databinding.User" />
    
            <!--调用静态方法,需要先导入需要的包    当然java中的lang包可以不用导包-->
            <import type="www.zhang.com.databinding.Utils" />
    
        </data>
        android:text="@{Utils.getName(user)}" /><!--就和java中写代码一样,只要符合数据类型就好-->
        
        public class Utils {
        public static String getName(Object o) {
            return o.getClass().getName();
        }
    }
    
            android:paddingLeft="@{user2.state ? @dimen/largepadding : (int)@dimen/smallpadding}"
            android:text="@{user2.content ?? @string/app_name}" />
            <!-- android:text="@{user2.content ?? @string/app_name}"
             等价于
             android:text="@{user2.content!=null? user2.content : @string/app_name}"-->
             android:text="@{`Hello World`+ @string/app_name}" /><!--``字符包裹的表示字符串,可用作拼接字符串 -->
    
     <data class="www.zhang.com.databinding.activity.Item">
        ...
    </data>
    import www.zhang.com.databinding.activity.Item;
    Item binding = DataBindingUtil.setContentView(FiveActivity.this, R.layout.activity_five);
    
    
    
    <data class=".Item">
        ...
    </data>
    import www.zhang.com.databinding.Item;
    Item binding = DataBindingUtil.setContentView(FiveActivity.this, R.layout.activity_five);
    
    
    <data class="Item">
        ...
    </data>
    import www.zhang.com.databinding.databinding.Item;
    Item binding =DataBindingUtil.setContentView(FiveActivity.this, R.layout.activity_five);
    
    <!--因为type="User"都为User类,会导致不知道到那个包,所以可以通过alias属性重命名type的类型,但实际上alias被指定的那个类型(如:www.zhang.com.databinding.model.User)-->
            <import type="www.zhang.com.databinding.model.User" alias="Model"/>
            
     
    Model类继承BaseObservable,BaseObservable实现Android.databinding.Observable接口,Observable接口可以允许附加一个监听器到model对象以便监听对象上的所有属性的变化。
    Observable接口有一个机制来添加和删除监听器,但通知与否由开发人员管理。为了使开发更容易,BaseObservable实现了监听器注册机制。DataBinding实现类依然负责通知当属性改变时。这是通过指定一个Bindable注解给getter以及setter内通知来完成的。
    notifyPropertyChanged(BR.参数名)通知更新这一个参数,需要与@Bindable注解配合使用。notifyChange()通知更新所有参数,可以不用和@Bindable注解配合使用
    
    Observable是一个接口,它的子类有BaseObservable,ObservableField,ObservableBoolean, ObservableByte, ObservableChar, ObservableShort, ObservableInt, ObservableLong, ObservableFloat, ObservableDouble, and ObservableParcelable,ObservableArrayList,ObservableArrayMap
    
    泛型的支持会在编译时期报红线,是可以直接运行的,但是需要通过转义字符才行,如:\<数据类型> 或者\<数据类型\>
    android:text="@{list[1]}"
    android:text="@{map[`name`]}" 
    android:text="@{arrays[0]}"
    
    <include
                android:id="@+id/toolbar"
                layout="@layout/toolbar"
                android:layout_height="56dp"
                android:layout_width="match_parent"
                bind:content="@{con}" />
     <!--通过命名空间将写有toolbar的xml文件中定义的content对象作为属性绑定con对象,这2个对象是同一个类-->

  • Android 优化

    post by onelong / 2016-12-4 16:44 Sunday [android]
    一直以来都没怎么做android方面的优化,使用的时候时候不卡就算了,也没有一些指标。或者是因为过往项目的缘故吧,总是没有一群专业的人员去测试,甚至只有靠自己去测试。每次面对性能优化的问题,都是没有很明确的指标,随着硬件的升级,其实出现卡顿的时候也会越来越少了,甚至有人去推测,原生迟早被h5替代的,哈哈,这个就是其他问题了。市场需求是多样化的,就像我们常常觉得一个卖二手机平台为什么要自己做,反正目标是卖出更多的手机而已,平台是啥都不重要,例如淘宝,微信等,普遍认为这种二手机平台是没有用户粘性的,买完之后可能一年内都不会再买了,用完即走的意思。可是我在评论上缺看到很多回头客,甚至有人买了8台。无论技术怎样发展,品牌是才是最重要的。技术只是一个工具,工具是否要变革,是市场需求决定的,当手机还在拼命增量的时候,我们就去推断移动互联网已经过去了,大数据来了。其实我们的终端还是在增量,而且没有被替代趋向,我们怎么会觉得Android和iOS就会死掉呢?从过往的我有个想法就差一个程序员,到现在细分,深度垂直发展。我相信对于技术和市场需求的挖掘都是不够的。洗牌之前,我们或许可以看到很多赚快钱的企业,洗牌之后我们只能看到一堆真枪实干的企业。开发者过剩的问题也是同样,由于以前要求过低,入门门槛低,涌入大量开发者,当市场需求趋向饱和的时候,优胜劣汰就来了。
     对于技术,始终要相信“科技是第一生产力”,一个不注重技术或不注重技术变革的企业是走不远的。Google,苹果等就不说了,国内看看阿里,华为。大数据,云平台,人工智能最终展现给用户的是终端,而市场需求总是多样化的。除了工作,我基本不会用到pc,以前有事没事都是大卡pc,二手机浏览器呢,也是同样,在需要百度查资料的时候才会用,而平时都是app。微信和网页是在app基础上多了一种方式而已,并不能说它们是未来,我相信任何人都是一样的,不喜欢只靠着一个大企业而生存,这样没有安全感。所以没有必要去担忧微信未来替代啥啥的,看重大厂app的主要是流量,例如罗一笑事件,就可以理解为什么那么多想赚快钱的人那么喜欢微信了。就像以前经常说的,php弄死了java,可以SOA,微服务又让java火起来了,技术是重要的,也是不重要的。技术作为基础平台,很多时候它的价值是不明显的,也就是这样大家就觉得平台能用就行了。好了,扯了那么多,入正题吧。
    说到android方面的优化,每次我都无奈了,gc优化,内存优化,网络优化,布局渲染优化,动画优化,自定义View优化,电量优化
    等的优化,内存嘛,OOM,对象池,内存泄漏等,通常都会扯到BItmap那一块去的。有时候觉得这方面的东西没什么可说的,java本身有垃圾回收,优化无非就是改变一些不良的习惯,别动不动就用静态,我经常看到静态的Context,Bitmap,甚至是一个集合。我更喜欢用单例,的确单例本质也是静态的,封装成一个对象比例零散的静态变量,在管理上比较方便,生命周期控制上也是会比较方便。经常造成内存泄漏的肯定是我们很熟悉的handler,这个就不用多说了,好的习惯就是在onDestroy时,handler.removeMessageAndCallback(null)。容易出现内存泄漏地方:
    1、静态
    2、
    handler的延时调用
    3、线程
    对应的优化方案就是:少用静态,
    handler.removeMessageAndCallback(null),取消线程,为了加速垃圾回收,我们还可以在onDestroy设置xxObj=null,减少gc,用ArrayMap,对象池,重用,StringBuilder,避免在onDraw方法里面执行对象的创建等主要减少对象数。
    电量用优化主要是在网络,传感器,蓝牙方面,蜂窝数据很费电的,当手机进入后台时,批量操作,延迟操作,为什么呢,启动的过程总是很费电的。传感器的频率调低,甚至关闭。优化关键次:JobScheduler,AlarmManager,网络请求队列,预加载,数据压缩,按场景加载等。充电时操作,用户点亮屏幕时操作,有Wi-Fi时操作,甚至在WiFi,4G,3G等不同的网络下设计不同大小的预取数据量。
    布局渲染优化:布局加载也是需要耗时的,虽然是二进制的xml,说白了就是简化布局,选择合适的布局,简单从效率上来看线性布局和帧布局会比较高效,但是要衡量可读性和可维护性,控制overdraw,overdraw上面大多数减少不必要的背景。建议关键次:Fragment,include,megre,ViewStub。这一块的优化内容很多,也很无奈。我们不能在非主线程上布局和渲染,也不像iOS那样可以监听Runloop推出的事件做后台渲染,android的消息机制和UI无关,所以很难做到平滑16ms,总会加载一个页面时,GPU耗时猛增,我对比了一下淘宝,qq,qq空间等app,都做不到很平滑。overdraw基本都是蓝色,所以我优化的目标也是overdraw蓝色,无色确实比较难做到了,而且也容易出现兼容性问题。至于动画的话,PropertyAnimation,ViewAnimation性能会好些。自定义View的优化,我就不说了,这方面的经验比较少。

    View -> GPU能识别的格式->cache as Display List->GPU Render

    阅读全文>>

  • 满满的收获

    post by onelong / 2016-8-19 21:09 Friday [android]

    好久没有做Android的项目了,一直刻意去回避,都在折腾iOS的项目,好多人问是不是转型了,其实也不是吧,只是觉得iOS会纯粹一点,再加上以前在iOS上的实践太少了,没有足以让我无比自信的去面对所有面试。最近因为特殊情况,让我回到刚毕业的时候,熬了4个晚上优化一个项目,给自己交上满意的答卷。这4个晚上,用了洪荒之力,鬼知道我经历了什么呢。。。。。哈哈,没那么夸张。其实看着师弟惆怅了一个月,种种跌宕起伏,之前给他做这项目的哥们,用了洪荒之力都跪了,一方面看着那个app做的太丑了,另一方面出于好奇,同时想证实自己给那个哥们的建议,于是自己找苦来吃了。结果呢,好屌。。。。。
    这次优化都用了哪些技术和工具呢?首先是应该有一个好的思维,我打个不太恰当的比喻吧,你拿到一块地,地上有一堆牛粪,那个哥们呢,喜欢在牛粪上差点鲜花,鲜花的华丽虽然掩盖了牛粪,但是终究是不够优雅。而我就想着先清理那堆牛粪,然后再种上鲜花。所以第一步,我做了代码清理,把一些重复,多余的框架去掉,一个项目3个图片加载框架,2个网络请求框架,费不费劲呀?一样一个就够了。那哥们说Facebook的fresco很好,不要用Universal-Image-Loader,按照他的意思是因为Universal-Image-Loader性能不好,导致app频繁崩溃了,好明显是没有找到原因,胡乱搬库,以往用好了就说是自己的经验了,的确android开发者很多就处于这种水平。这个问题恰恰反映这个问题。
    我解决问题的过程是怎样的呢?首先询问师弟运营的数据,例如android用户在集中在那个版本上,毫不意外,基本没有android2.3的用户了,都是android4以上了。这样意味着不需要兼容android2.3了,也就是直接可以app的largeheep,打开了之后,崩溃已经明显少了,但是用了10-20分钟,还是出现内存溢出。经过计算10-15张560x560的图片,内存最多才20m,而app监控到了180m内存,很显然内存泄漏了。于是我自己手动管理图片的内存,但是依然无效。android内存泄漏一直以来都是开发的难点,面试经常有人问的。之前用过MAT,完全看不懂,后来试了一下facebook的LeakCanary,果然好用了,的的确确发现一堆堆内存泄漏,一泄漏就是10多m,妈的。。。。。得益于这个工具,很快就找到问题了,大部分是因为没有正确使用hander,线程导致的,activity退出应该清理没用的数据,移除没用的消息。经过一番折腾,内存明显可控了,峰值最多120m,我看了支付宝有时候内存占用都180m,所以我断定可以了。结果发给师弟它们测试,玩了20分钟,没啥问题,这是算完了?不是的,这么多图片好卡,于是我适当做了延时加载和缓存,真个界面就流畅起来了。
    想着既然做了,那就一优到底吧,把里面支付的,图片加载的,网络的库都升级到最新的,这样更好兼容android6.0吧,网络还是用我比较熟悉的volley+okhttp,不过这次用了okhttp3,之前在案场用了okhttp2.0。换库发现
    volley本身有内存泄漏,也是这样我发现了好神奇的东西,java无用的对象尽可能置为null,加速gc。发现列表滚得卡顿,于是再优化了一下,列表滑动时不加载图片,果然流畅了,这次的优化也结束了。
    为什么用volley,没有用retrofit呢,原因1:这个项目从android-async-http切换到retrofit比较麻烦,可能是我不熟的原因吧,原因2:volley代码少,我很容易做到有问题快速库,一切都在掌握之中。对于recyclerview,还没开始用,我觉得复杂的列表界面应该切换到recyclerview,在recyclerview我看到很多优点,很灵活。LeakCanary是个神器,建议大家用。
    送上几个截屏吧,二手iPhone,找靓机。哈哈,开发用二手机不错哇。。。

    阅读全文>>

  • android studio jni

    post by onelong / 2015-9-8 21:47 Tuesday [android]

    在android studio 导入jni项目,报如下错误。

    Error:(12, 0) Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

    阅读全文>>

  • Android 外勤管家

    post by onelong / 2015-8-14 21:42 Friday [android]

    android版截图:

    点击查看原图

    阅读全文>>

  • android 热点

    post by onelong / 2015-8-2 0:48 Sunday [android]

    最近要做一个热点App,类似快牙。也是这样看系统的Settings代码,做点笔记吧。创建配置对象:

    public WifiConfiguration getConfig(int type,String ssid,String password) {

    阅读全文>>

  • 政府企业服务软件-员工服务平台客户端

    post by onelong / 2014-5-26 2:31 Monday [android]

  • Google play 应用内支付的一些文章

    post by onelong / 2014-1-25 5:00 Saturday [android]

    最近在做Google play的东西,真的很蛋疼。我把看过的文章收集起来了

    http://zengrong.net/post/1801.htm

    http://blog.csdn.net/midashao/article/details/10122333

    阅读全文>>

  • 移动客户经理工具

    post by onelong / 2013-12-13 16:53 Friday [android]

    参与UI编码和部分功能实现的android客户端

    点击查看原图

    阅读全文>>

  • 罗西尼解决方案客户端

    post by onelong / 2013-12-13 16:19 Friday [android]

    罗西尼的营业员和业务员的业务工具。这个客户端主要在安全上做了很多功夫。看看界面的吧,功能不多,但做了好久了

    点击查看原图

    阅读全文>>

  • byte2Hex和byte2Base64

    post by onelong / 2013-11-26 16:25 Tuesday [android]

    byte2Hex会变大1倍,使用byte2Base64相对小一些,文件大小200kb的,base64后300kb左右,如果使用byte2Hex就是400多kb。

    总的来说,使用byte上传会比较好些,数据量少一些。

    阅读全文>>