关于SharedPreference踩的那些坑

SharedPreferences多进程 为什么会突然写这篇文章呢,主要是我昨天在用SharedPreferences的时候,涉及到多进程访问,写的时候没注意,然后导致数据不对,既然踩了坑,肯定要自己反思一下总结,所以也就有了这篇文章,简单总结一下, 首先直截了当得先回答文章开头那个问题,答案是:能但是不行。 为什么这么说呢,因为SharedPreferences确实可以通过设置MODE_MULTI_PROCESS实现多进程访问,而且是SDK2.3 之前是默认的,连这个标志都不用设置,SDK2.3之后就需要手动设置,既然这么说了,那就肯定是能了,但是为什么说不行呢?因为这个标志在 SDK6.0 的时候已经被Deprecated,Android为什么要把这么一个简单易用的进程间通讯方式废弃掉呢,看下源码就可以知道,原因就是它并不能保证数据的安全性和准确性,并没有实现并发修改的机制,所以官方也就不推荐了,而是推荐使用 ContentProvider。总结一句话:爱过。 基础知识大普及 既然看到了源码,索性就看完整一点,这样以后用的时候也更顺手一点,于是简单的把SharedPreferences相关的内容简单都看了下,下面就是自己简单的一些笔记: 我平时在使用 SharedPreferences 一般会直接用: SharedPreferences sp2 = PreferenceManager.getDefaultSharedPreferences(this); 来获得一个SharedPreferences的引用来操作,正好借着这个机会好好看了下官方的介绍,终于算是对SharedPreferences有一个更完善的认识了, SharedPreferences sp1 = getSharedPreferences(getPackageName() + "test", MODE_PRIVATE); SharedPreferences sp2 = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sp3 = getPreferences(MODE_PRIVATE); 上面的三行代码都是为了获得一个SharedPreferences 引用,其中第三个方法是Activity专有的,其实我们看源码的话,就会发现其实后两个方法其实都是第一个方法的封装 public static SharedPreferences getDefaultSharedPreferences(Context context) { return context.getSharedPreferences(getDefaultSharedPreferencesName(context), getDefaultSharedPreferencesMode()); } private static String getDefaultSharedPreferencesName(Context context) { return context.getPackageName() + "_preferences"; } private static int getDefaultSharedPreferencesMode() { return Context.MODE_PRIVATE; } 正如你所见,getDefaultSharedPreferences()就是返回了一个名字为getPackageName() + "_preferences",mode 为MODE_PRIVATE的实例。 public SharedPreferences getPreferences(int mode) { return getSharedPreferences(getLocalClassName(), mode); } 而getPreferences就是返回了一个名字是以当前类名命名的,mode自定义的实例。...

October 20, 2016 · 1 min · vistashao

老司机电台-第二期-微信应用号来了

Hello,大家好,欢迎来到老司机电台,这已经是电台的第二期,虽然和第一期之间隔了两周,但我还是很庆幸我还是坚持了下来,为什么这么说,因为我之前干过太多半途而废的事情了,以后找机会可以跟大家好好唠唠,让大家引以为戒 因为中间空了一期,所以也有很多上周的新闻也就不再这里赘述了,毕竟也已经有点过时,这时候再拿出来炒冷饭,相信听众朋友们也不乐意,不过我可以简单得提两句,上周的热点就是iPhone7开箱、万年免费的支付宝将从下个月开始体现收费以及阿里的月饼事件,相信大家也都很清楚。 本周沸点:微信应用号 前世今生 废话不多说,直接开始这期电台的主题《微信应用号来了!》,大家如果这周比较关注互联网圈里的新闻的话,就能一眼看出来这周的沸点是什么了,没错,这周要说的就是微信的应用号,而这个标题就也是来自于Fenng那天晚上发的那篇公众号文章,相信大家也都已经拜读过了,有不太了解的听众,可以在微信里搜一下,虽然没什么内容,但是毕竟是整个应用号新闻浪潮的开端,那篇文章其实是在晚上将近11点的时候才发出来的,我因为当时没看手机,所以也就错过了见证这样的时刻,直到第二天早上看新闻才知道了这件事,然后追本溯源,就来到了Fenng的那篇公众号,当时我看的时候应该也就8、9点钟的样子,那篇文章的阅读量已经将近8W了,可见微信的一个小动作就能引起的轩然大波,到中午的时候,那篇文章的阅读量已经不能统计了,因为早就10W+了。 可能有些人对微信应用号的前世今生并不是很了解,所以我就在这里多说几句,其实早在今年年初的时候,张小龙在“2016微信公开课pro版”就透漏一种全新的公众号形态:应用号,只是沉寂了这么久,终于开始了内测。其实已经不能叫微信应用号,官方给出的称呼是叫微信小程序,虽然还在内测,还没有正式确定是叫什么,但应该也八九不离十了。从网上曝出的微信朋友圈截图看到,张小龙发的一条朋友圈,给我们详细解释了一下什么是微信小程序:小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。应用将无处不在,随时可用,但又无需安装卸载。从这段描述中,我们可以看的出来微信对于小程序的定位,不仅仅是服务号的升级版,更像是用插件化的方式,在微信里面安装应用,不同的是微信想用Web来实现原声应用的体验,来减少用户的使用成本和等待时间,有人说这其实就是React Native的精简版,而且是做在微信OS里的,其实不然,微信的小程序更像是之前百度、360和UC曾经尝试过的轻应用,直接在浏览器里打开一个类似原生应用的程序,跟他们不同的是,微信这次要做的更加接近原生,所有的控件都是用JS去调取的原生应用的控件,而不再是浏览器的控件,这样的体验可能会更加流畅。 说了这么多跟技术有点关系的东西啊,其实这是有违我台的宗旨的,我台的宗旨一向是一本正经的胡说八道,闭口不谈技术实现。好了,回归正题啊,继续八卦,这张小龙的这条朋友圈下面,有一条马化腾的苹果,解释了下为什么不叫原来的应用号而改成什么小程序了,因为苹果不让,毕竟已经是在抢 App Store 的饭碗了好嘛,苹果为了讨好iOS开发者可谓是煞费苦心,又是开WWDC,又是开发 Playgrounds 来把开发者从小抓起,因为在乔布斯时代的时候,就已经说过了,苹果是一家软件公司,在这个硬件产品越来越不好卖的时代,软件的收入相对稳定的多,好吧,毕竟苹果是大爷,而且刚刚在今年,苹果在本次的 WWDC 上特意推荐了腾讯手机管家作为苹果的骚然拦截软件,因为这样一件小事闹掰也不值当,而且在我看来,小程序这个名字似乎有点似曾相识,后来才想到当初刚学Java的时候就接触过一个Java Applet的东西,是一种运行在客户端里的程序组件,翻译过来就是叫:小应用程序,可能微信用这个名字也和这个有点关系。 关于应用号的问题 聊了这么多,最后还是要说点大家比较关心的问题: Q:原生应用真的会被淘汰吗?以后大家是不是手机上只需要装一个微信就够了? A:我觉得不会的,虽然微信发布这个小程序会对原生应用这边有一些冲击,这是不可否认的,从大家对微信小程序的热衷程度就是可以看得出来,大家还是很期待这个东西的,或者说,微信小程序真的挫中了某些人的痛点,不过,我还是觉得大家有些过度乐观,把微信想成了一个操作系统,所有问题都在微信里一站解决,这是不太现实的,如果有新的社交软件,比如探探,它会把探探做成一个小程序放在微信里吗?肯定不会,且不说都是社交产品,存在一定的竞争关系,而且定位就不一样,微信是做熟人社交,而探探是做陌生人交友,怎么可能混在一起,在者说,微信的竞争对手,百度会在微信里做一个小程序,提供搜索功能吗?肯定不会,如果那样做了,谁还会去单独下载一个百度APP搜东西,当然了,我是最不怕打脸的,如果真的有一天,百度做了一个搜索的小程序在微信里,我觉得BAT就解体了。当然还有很重要的一点,所有的需求,小程序都能实现吗?它能实现骚扰拦截吗?它能提供ROOT功能吗?微信会给你读取联系人的权限吗?这些都是不可能或者不明朗的,而且原生还是有原生的好处,使用流畅,而且不那么依赖网络,基于这些考虑,原生应用肯定不会被淘汰。 当初React Native出来的时候,不也是一阵欢呼,感觉Android和iOS都要被淘汰了,JS一统天下的时候终于到了,Swift出来的时候,iOS工程师不也是兴奋的睡不着觉,觉得自己终于要走出那种OC这个坑,殊不知,转身就跳进了另一个坑,大家会新鲜的事物充满了信息,因为我们被现有的东西蹂躏了太久,直到把那一层神秘的面纱扯下,我们才意识到,原来是一路货色。 Q:那什么应用适合做微信小程序呢? A:这个问题其实比较容易回答,因为张小龙已经给出我们答案了:用完即走,工具类应用,用完就走,新闻类应用,看完就走,电商类应用,买完就走,总结一下就是这么几种: 1. 功能单一的,12306,就是一个单纯的购票软件,一年也用不了几次 2. 使用频率低的,还是12306,, 3. 使用时长短的,还是12306,, 4. 现象级应用,终于不再是12306了,大家之前熟悉的脸萌,就属于这种,用过几次以后就不会再想起来了。 Q:为什么大家都这么激动?不就是一个公众号的另一个形态 A:我觉得大家还是反应过度了,因为大家觉得已经错过了公众号早起的红利,不想再错过应用号的首发,而且现在的微信小程序还在内测阶段,很多规则性的东西都还没有公布出来,大家想要看到的都是利好的消息,而且长久以来,不论是初创公司还是老牌公司,都已经做原生应用做烦了,凡事都得做一个应用出来,不论有用没用,投入的人力物力不计其数,甚至于有些小公司App开发到一半,公司就已经不行了,而且大家一直以来的观点不就是:我有一个天才般的想法,就差一个程序员帮我把应用写出来了,现在好了,直接在微信里做就行了,庞大的用户群体,巨大的流量,也再也不用跟各种第三方ROM斗智斗勇,调兼容性,求存活,求推送到达率,现在做一个微信小程序,只有开发一个版本,Android和iOS都可以用了,甚至于之前那个一直躲在犄角旮旯的WP也能体验上一把,我觉得这是大家所期待的,但是事实真的是这样吗?我还是觉得大家有写过度乐观了,微信为什么要做微信小程序?腾讯难道这么好心,只是为了减轻开发者的负担?显然不是,到底如何,最后公测见,到时一切都会了然。 一些传言 本来就是一个八卦的节目嘛,再说一些传言,在做这期节目之前,我也了解了很多关于微信小程序的传言,之所以有这么多传言,主要还是微信官方给出的信息太少了嘛, 不得不让大家有一些猜测,有人就曝出苹果和微信的“约法三章”: 不能做游戏 不能做直播 一个用户最多添加20个小程序 在这里,我们不对信息的可靠性做什么考究啊,本来就是来八卦的嘛,暂且认真一把,好好分析一下,之前已经说过,微信小程序之所以改名,不能叫应用号,就是因为苹果,这点还是有些可靠性的,毕竟微信的这种行为已经干扰到苹果的利益了。在看这里约法三章的第一条,不能做游戏,我觉得这个倒是无所谓的,就算放开这个限制,在微信里面,你能做什么游戏?最多也就是个飞机大战了;第二条,不能做直播,我不知道为什么会有这一条,难道是苹果特别看好直播这块市场?那为什么苹果却一直没有推出自己的产品,所以这一条有点莫名其妙;第三条,一个用户最多添加20个小程序,我觉得就算没有这条约定,微信也会有所限制的,毕竟微信这种做IM的产品,还有联系人上限这个东西,在小程序这边肯定也会有所限制。 还有就是小程序入口的问题,到现在为止,我们都还不知道,微信小程序会被放在哪里,网上有猜测会被放在‘发现’TAB下的购物和游戏下面,我觉得还是很合理的,其实我想到的还有一个合适的地方,就是会话列表,直接像服务号一样出现在会话列表里,也是一个不错的选择。 没错,我就是一个喷子 好,八卦到此结束,接下来我要正式开喷了,作为一名Android原生工程师,骨子里有一种对H5这种取巧的方式是有一些鄙夷的(求H5工程师),包括React Native这些技术,在我看来都是一些旁门左道,原生才是王道!为什么这么狂,接下来说从技术角度说一些微信小程序做不到或者不好做的东西: 微信小程序怎么发推送?不要期望微信会让你出现在通知栏上,如果那样的话,有些ROM的通知栏拦截程序如果拦截了你的通知,是不是也就把微信的通知也拦截掉了,微信怎么会让这种事情发生。那怎么实现呢?我估计是在微信里以消息通知的形式出现,那么又有问题出现了,微信会对你的通知有限制吗?这是必然,微信这么克制的软件怎么可能容忍一些小程序胡乱地发消息,这就意味着你的通知也会受限于微信,再也不能像之前那样随心的骚扰用户。 微信来消息了怎么办?相信大家都有这样的经历:在看公众号文章的时候,突然来了一条微信消息,而且你想点过去看一下,那么当你跳到聊天界面的时候,这篇公众好文章就被关闭了,虽然你再次打开这篇文章的时候,可以继续从刚才的位置读,但是你先得想办法找到这篇文章才行,如果是微信小程序的话,会不会也出现这样的问题呢?要看微信怎么处理了,如果真的是这样,那么果断还是原生多程序切换来的爽快。 有没有想过有一天突然被微信封杀?虽然这种事情,在一些体量较小的公司看来,仿佛是杞人忧天,但是当那一天真的来了,你才会发现自己是多么的无助,因为对于小公司来说,可能微信上的这些用户就是他们的全部了,被封杀就意味着整个就完蛋了,这种事情不是没有发生过,前一段时间的柏拉图app公众号开发了一款性格标签测试产品,火了不到24小时就被微信封杀了,之前圈的那些粉也都没了,接受多大的恩惠就要承担多大的风险,接受了微信这么大的流量,也就要承担着被封杀的风险,天下哪有免费的馅饼,而且我也相信微信不会傻到让你圈粉然后再倒流到自己的应用内。 当然了,微信小程序还是有很多优点的,比如,我就是不说,谁让我是高傲的原生Android工程师,本周的科技沸点就是这些了,稍作休息,下一个话题是三巨头 关于AI的思考 接下来我们聊一下关于AI,人工智能,为什么会扯到这个话题上呢,主要是这一周也发生了一些跟AI有关的新闻,所以在这里就一并总结一下。说到AI,大家首先想到的可能是 Siri,其实不止苹果家有AI产品,还包括微软家的小娜和小冰,以及 Google 家的 Google Now,都算是AI届的翘楚,就在本周,终于迎来了带着桌面版Siri的macOS发布正式版,Google也正式发布了在今天的IO大会上提出的 Allo,带着Google新发布的 Google Assistant,未来可能代替之前的 Google Now,就连一直没有消息的微软小冰和小娜,也在一步步成长,我们可以想象一下,在不久的将来,这几家公司都会培养出来一个完全属于你私人定制的AI助理,你每天几点要干什么,它都知道,并且能在必要的时刻提醒你,甚至于比你自己都更要了解你,你可能想知道它的载体是什么,它几乎是无处不在的,各大厂商都给出了解决方案,苹果可以在一款苹果产品上调出 Siri,不论你是用 iPhone、iPad、iWatch 或者 MacBook,Siri 无处不在,而 Google 也在今年的 IO大会上发布了 Google Home,用来控制家里所有的智能设备,所有的东西都在互联网上,触手可及,国内的一些厂商也在智能家居方面做出了一些努力,比如小米的小米智能家居,魅族的智能家居平台以及京东的京东微联,都在努力接管你家里所有的智能设备。相信再一段时间,智能家居会越来越普及,很多事情不再需要我们去亲力亲为,窗户上的传感器感知到快要下雨会自动关上,检测到外面的空气不错,就自动把窗户打开,慢慢变成常态,这一天,肯定不会太远。好了,这就是这周看到关于AI相关的,所有有感而发,所以简单跟大家畅想一下AI的未来。...

September 26, 2016 · 1 min · vistashao

Android消息处理机制:Handler|Message

在日常开发中,不管出于什么目的,我们可能都会用到Handler来异步更新UI,有时是为了将一些费时的操作放到异步线程去处理,然后通过Handler将数据更新到UI线程,有时是为了在子线程里更新UI,种种原因,反正我们最后都是选择了直接的Handler+Message组合或者AsyncTask,而了解AsyncTask的同学都知道,AsyncTask内部就是通过Handler和Message实现的线程间通信,所以我们还是要好好熟悉一下这位老朋友 为什么要使用Handler 我们使用Handler更多是为了异步操作,那么为什么非得要异步操作呢,直接在子线程更新UI不行吗?答案当然是不行的,不然Handler存在的意义是什么,这一切都是因为UI的控件都不是线程安全的,如果允许并发访问,那控件的状态就是未知的了,可能你刚获取完一个控件的状态,准备进行一些操作,这时候另一个线程改变了这个控件的状态,那就很麻烦了,解决这种问题的方法一般有两种:1.加锁,在对控件进行操作的时候先加锁,不允许其他人访问,这样的问题是会导致UI更新的效率会很差,而且容易堵塞某些线程,因为他需要等上一个访问这个控件的线程释放锁;所以Android选择的是第二种方法,只允许在一个线程内对UI控件进行更新,这个线程就是创建View时的线程,默认状态下,这个线程就是主线程,这也就是为什么我们在对UI组件进行更新的时候,必须回到主线程去操作。 经極ws丶琪 指正,更新View的线程不一定必须是主线程,而是创建该View的线程,因为默认状态下,我们创建View都是在主线程,所以就慢慢有种只能在主线程更新View的错觉,其实是:只能在创建View是所在的线程更新一个View。 Handler、MessageQueue和Looper 我一直在用Handler,不过总是对它一知半解,一直停留在会用的程度,以致于别人在提到MessageQueue和Looper的时候,我竟是一脸懵逼,当时觉得好羞愧,连这些都不知道,你还用什么Handler,回去搬砖吧!我相信也有很多的Android初学者跟我有同样的问题,所以在这里,我想先跟大家详细介绍一下这几个概念 Looper Looper是一个用于给线程提供消息循环处理的类,其实在没有感知的情况下,创建一个Handler,看似简单,但是最少需要三步:在目标线程中执行Looper.prepare(): private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } 省去部分细节我们不谈,我们只看我们最关心的,那就是它新建了一个Looper实例并把它放在了它的一个成员变量里,具体ThreadLocal的作用我们先不在这里展开,只需要记住它是跟线程相关的,每个线程从它这里读出来的数据都是不一样的。创建好Looper之后,我们就可以创建我们最终需要的Handler了: public Handler() { this(null, false); } public Handler(Callback callback, boolean async) { ... mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper....

July 15, 2016 · 2 min · vistashao

Android中的事件分发和处理

上次跟大家分享了一下自定义View的一下要点,这次跟大家聊一下View的事件分发及处理,为什么主题都是View,因为作为一名初级应用层Android工程师,跟我打交道最多的莫过于各种各样的View,只有详细了解他们各自的习性,才能更好地跟他们沟通交流,做出自己想要的效果。 基础储备 View、MotionEvent 我们都能详细地说出Android的四大组件:Activity,Service,ContentProvider和BoardcastReceiver,但是四大组件之外,我们用到也很多的是什么,其中肯定包括View,View是用户跟程序沟通的入口,也是程序展现给用户信息的窗口。关于View,一些基础属性还是要了解的,left,top,right,bottom,分别代表了view的左上角和右下角分别相对x轴,y轴的坐标,而且view的getWidth和getHeight的值都是通过这四个值算得,而且在Android3.0中还增加了x,y,translationX和translationY这几个属性,便于我们对view的平移操作,x、y代表了当前view左上角的xy坐标,而translationX和translationY代表了view相对它的父容器的偏移量,默认值是0。 MotionEvent表示用户的触摸事件,用户的一次点击、触摸或者滑动都会产生一系列的MotionEvent: MotionEvent.ACTION_DOWN 表示用户的手指刚接触到屏幕 MotionEvent.ACTION_MOVE 表示用户的手指正在移动 MotionEvent.ACTION_UP 表示用户的手指从屏幕上抬起 所以一次用户触摸屏幕可能会产生这些事件: 点击屏幕然后松开,Down->Up 点击屏幕,然后滑动一段距离,松开屏幕 ,Down->Move->…->Move->Up 了解了这些基本知识以后,我们就来学习一下具体怎么分发这些事件 ViewGroup 分发-> 拦截 -> 处理 首先说一点,虽然ViewGroup也是继承View而来,但是因为在事件拦截上,ViewGroup分析起来更加方便理解,所以先说ViewGroup,下面也会简单介绍一下View的事件处理。 在事件分发的过程中,主要涉及到三个方法: dispatchTouchEvent(MotionEvent event); onInterceptTouchEvent(MotionEvent event); onTouchEvent(); 初看这三个方法就有蒙圈,如果这时候在蒙头钻进源码里,就更是糊涂,我在这里借用任玉刚大大的一段伪代码解释一下这三者之间的关系: public boolean dispatchTouchEvent(MotionEvent event) { boolean consume = false; if (onInterceptTouchEvent(event)) { consume = onTouchEvent(event); } else { consume = child.dispatchTouchEvent(event); } return consume; } 从这段伪代码中,我们可以看出来,在dispatchTouchEvent中,先调用ViewGroup自身的onInterceptTouchEvent方法,判断自己是否要拦截,如果这时候自己拦截,那就调用自己的onTouchEvent方法,如果onTouchEvent方法返回了True,那么这次的事件就算消耗了,事件传递到此为止,如果返回了False,证明这次没有消耗这次MotionEvent,那么这次的事件就会往上返回,由上一级继续处理;如果当前ViewGroup的onInterceptTouchEvent返回了False,那就会调用它的子view的dispatchTouchEvent方法,这样这个事件就传递下去了,如果它的子View处理不了,那么还会回来调用ViewGroup的onTouchEvent方法,当然这一点是没有在这一段伪代码里体现的,用一段通俗的例子解释: 领导收到一份任务(有可能是上级给的),自己看了一眼,然后决定好好休息,今天不工作,就把这个任务交给了手下的小王,小王的默认属性是只要来任务就接,而且就干,能干不能干一样接,如果这是一个简单的任务,那么小王就解决了,这个任务也就完成了,不幸的是,这次任务小王没有解决掉,然后向领导反馈,领导没办法,手下没人能解决,只好自己干了,就开始解决问题,然后解决掉,任务也完成了。 这就是ViewGroup层的事件分发,当然不是这么简单,这只不过是通过简单的方式去理解,其实在真实的事件分发中,有很多问题需要注意: 一个完成的事件序列以Down开始,中间可能包含若干个Move,然后以Up结束 一个view一旦拦截一个某个事件,当前事件所在的完整事件序列将都会由这个view去处理,反应在真实的代码中,就是一旦view拦截了down事件,那么此后的move和up事件都将不调用onInterceptTouchEvent,而直接由它处理,这就也意味着在onInterceptTouchEvent处理事件是不合适的,因为有可能来了事件,却直接跳过onInterceptTouchEvent方法。这个也意味着,一旦一个ViewGroup没有拦截ACTION_DOWN,那么这个事件序列的其他Action,它都将收不到,所以在处理ACTION_DOWN的时候,尤其需要谨慎。 onTouchEvent中是要判断MotionEvent的Action,因为一次点击操作就会调用两次onTouchEvent方法,一次是ACTION_DOWN,一次是ACTION_UP,如果手滑一下,还会有若干个ACTION_MOVE ViewGroup默认不拦截任何事件,源码中ViewGroup的onInterceptTouchEvent方法默认返回的是false 整个事件分发,看起来都是由外向内传递的,父View将事件传递给子View,理论上来看,子View是没有办法影响到父View的事件处理的,但是有一个标示位,requestDisallowInterceptTouchEvent方法,通过这个方法 ,子View能够影响父view的事件处理,这个可以用于解决父view和子view的滑动冲突,具体想了解的可以搜索它的相关用法,这里将不进行展开。...

July 12, 2016 · 2 min · vistashao

Android自定义view详解

对于我这样一个Android初级开发者来说,自定义View一直是一个遥不可及的东西,每次看到别人做的特别漂亮的控件,自己心里那个痒痒啊,可是又生性懒惰,自己不肯努力去看书,只能望而兴叹,每次做需求用到自定义控件,就直接去Github上找,找到合适的就用,找不到合适的,凑合也用,反正从来没想过要自己来做这样的东西,可是毕业以后到了新公司,为了自己的荣誉,这次不得不硬着头皮自己来了,一个月的紧张开发过后,回头再看,自定义控件也无非那么回事,只要记得几个要领,几乎是手到擒来。 从继承开始 懂点面向对象语言知识的都知道:封装,继承和多态,这是面向对象的三个基本特征,所以在自定义View的时候,最简单的方法就是继承现有的View {% codeblock lang:java %} public class SketchView extends View{ public SketchView(Context context) { super(context); } public SketchView(Context context, AttributeSet attrs) { super(context, attrs); } public SketchView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } } {% endcodeblock %} 通过上面这段代码,我定义了一个SketchView,继承自View对象,并且复写了它的三个构造方法,我主要来分析一下这三个构造方法: 第一个构造方法就是我们普通在代码中新建一个view用到的方法,例如 {% codeblock lang:java %} SketchView sketchView = new SketchView(this); {% endcodeblock %} 就这样,一个自定义的view就被新建出来了,然后可以根据需求添加到布局里 第二个构造方法就是我们一般在xml文件里添加一个view {% codeblock lang:java %} <me.shaohui.androidpractise.widget.SketchView android:layout_width=“match_parent” android:layout_height=“match_parent” android:layout_marginRight=“16dp” android:layout_marginTop=“16dp” /> {% endcodeblock %} 这样,我们就把一个SketchView添加到布局文件里,并且加了一些布局属性,宽高属性以及margin属性,这些属性会存放在第二个构造函数的AttributeSet参数里...

July 8, 2016 · 2 min · vistashao