在平时的开发中,我们总会遇到各种各样的问题,在我们技术还不行的时候,也许不是什么大问题,但是一旦技术逐渐成熟,所写的程序逐渐变大了,那么我们就会面临着越来越多的挑战。1、如何快速认识一个新类及其方法    2、如何简化程序开发以应对日渐膨胀的代码    3、如何查找越来越复杂的程序中的错误以及定位异常     4、如何更好的利用开发平台进行更有效的学习。综上所述应该就是作为一名处在技术日渐成熟的程序员应该面对的提升自身编程能力必须面对的问题。

1、认识一个新类是我们学习所必须面对的,在开发中我们必须用到各种Service,控件,组件,自定义类等,如果我们一个个学的话,那么我将会学到猴年马月,最好的方法,就是总结各种掌握新类的快速途径,我们都知道一个类所白了就是其内部对象和方法的综合加上封装,那么相应的我们就应该从方法入手学习一个类,或者从方法入手找到一个类再从这个类的方法入手认识我们所要认识的类,可以使用eclipse自带的JavaDoc窗口对类进行初步认识,再利用按住Ctrl将鼠标移到要认识的类上,单击,或者在JavaDoc窗口上按右键,单击open Input进入,就可以看到类的内部方法以及对象,再结合Alt加“/”查看类的所有方法就可以知道类的哪些方法是自己的,那些事继承来的。

2、对于代码膨胀在所难免,我们能做的就是简化开发,将代码模块化,功能化,结合函数式思维开发,逻辑化。原则就是在主类使用各种类的实现以及基本方法是用,即总体规划,而将所有的功能模块化到各类中去,并且在应对但各类的代码块时,通过注释将代码模块化,这样就可以做到准确定位,提高开发效率了。但是应该注意的是容易出现NullPointerException,也就是空指针异常,原因是对象没实例化,出现的原因可能是:1、传递过程中出错,如传给方法时类有出入  2、类间的调用时出错,通常是内部类  3、模块化之后虽然有引用,但是没实例化,因为各模块的实例化可能有重叠,会误以为已经实例化了。

3、一般情况下,使用Log就基本满足需要了,基本可以定位错误位置以及类型,但是标注Log比较麻烦,所以可以使用Debug进行,但程序大到一定程度时,就应该使用Debug,因为标注可能会需要很多,当然,这只是因人而异。关键还在于准确定位错误类型,这就需要我们对于各种Exception有基本的掌握,结合LogCat,基本找错误技巧足够了。

4、利用JavaDoc窗口,LogCat窗口,按住Ctrl将鼠标移到要认识的类,Alt加“/”查看类,Out Line(这个特别重要,可用于准确定位方法和对象以及一些内部类,但自己要添加代码时,可以利用它进行定位),File Explorer,Debug窗口,DDMS,JAVA,Debug三种模式进行各种学习。

看代码时将很长的代码段看成是某个对象或者功能,这样就可以简化代码的阅读。

注意:搜索资源是一定会涉及路径的,因为路径用于确定位置。同时注意,eclipse软件的文件夹里面封装的都是各种文件和工具,因为实际上计算机就只是运行命令而已,所以实际开发中,软件的文件夹就必须有各种处理文件和工具。同时这些工具,文件都是极其模块化的,每个文件夹对应不同的文件或工具。就像在jdk中的bin文件夹就存在很多开发工具javac.exe,javah.exe,javadoc.exe,java-rmi.exe等。而include文件夹则是存在很多有用的文件,这个文件夹里面的文件几乎都是头文件,所以使用JNI时,就会使用到include文件夹里面的文件。

另外,对于AVD的使用,有时候会使用到横竖屏切换,这个时候需要注意,尽管实现的方法有多种,我们可以使用程序xx.class.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANSCAPE)(或者PORTRAIT),也可以使用Ctrl+F11或者使用Ctrl+F12,(这里必须注意,Ctrl键必须是左手边的Ctrl键,右手边的是不行的,注意!)

其实在控件的命名上java的是Jxx,这是由其继承的父类决定的,由ImageObserver,到Component,到Container,到Window,JComponent,这里JComponent的子类形成控件,而Window的子类形成容器相关的类,如布局类。所以java的控件基本都是Jxx的。而android的控件则是xxView的形式,这是因为View是所有的控件的父类。

在创建类时需要引用参数,这时如果是在android中,那么,只要是和项目的资源相关的就可以使用Context作为参数,因为Context及其子类ContextWrapper都是用于获取项目相关资源的。

Context的子类是ContextWrapper,ContextWrapper的子类是ContextThemeWrapper,ContextThemeWrapper的子类是Activity。所以在Activity里面使用getClassLoader()得到的是Activity这个class。同时应该明白,ClassLoader类是用于加载类的。注意,这里涉及到一个重要的问题,那就是在java中可以使用xx.class.getResourceAsStream()进行项目资源的加载,但是在android中却不行,因为项目的文件架构不一样,所以这里,可以使用getClassLoader().getResourceAsStream()进行加载,因为这里getClassLoader()得到的ClassLoader可以代表加载的项目。和java一样这种方法也是有限制的,java的方法读取的是bin文件夹的,android的方法读取的是src文件夹下的。例如读取src下与xx.java同目录下的某文件,需要使用到的路径是com/xx/xxx/xx.xxx,简单点就是说读取位置被定位到src文件夹。

(对于java的控件,其实应该从Component类为起点进行控件树的掌握,因为有一些控件不是Jxx形式的,但是很有用,就行Canvas。)

(super(),this()是java,android都有用到的,super()调用父类方法,this()调用自身方法,就是说this()所在的那个方法)

(要操作手机平台的东西需要获得权限,也就是在AndroidManifest.xml中写入<uses-permission android:name=”android.permission.xxx“>)

(修饰符中并不包含friendly,他只是一个概念,同时注意,在java中变量不加修饰符的都是friendly类型的,即包内的可以可以自由调用,包外的不可以。)

(在android项目中常常会遇到一个项目明明没有错,但是系统却报错了,这时可以将project.properties中的版本号改错,然后修正,这样错误就会消失了。其实这里报错的原因是因为系统加载给项目的平台的android设置,也就是android-xx在这里没有被系统扫描到,所以使用人工的方法,将版本改错,这时系统就会显示错误,而后面的修正则会令系统再次检验android-xx,这时由于上次的没有检查android-xx而产生的错误,因为在这里得到了检验,因此错误消失。)

(在调用某个类的内部类时,可以只调用这个类的内部类,通过class.innerclass的方法就可以了。这样就不用实例化这个类,而直接实例化这个类的内部类。)

(如果一个类在包中的其他类中需要传递,那么一般不要作为某个类的内部类,而应该单独创建一个类。如果要实现某个类的独立性,即可到处使用,则不可以使用包中的其他类作为该类的参数,甚至包中的其他类不能出现在该类中,我们应该使用平台的类进行代替。同时设计一个类时,应该尽量使其能够做到有较高的复用性,这样可以减少开发时间。同时注意,我们可以使用自定义抽象类,接口连接我们将要创建的类,当然,他们必须具有对该自定义抽象类,接口所具有的属性的需求时,才需要设计抽象类,接口,可以说,抽象类,接口就是一个结构。)

(在android的onTouchListener中,ontouch会被执行两次,因为touch事件包含MotionEvent.ACTION_UP,MotionEvent.ACTION_DOWN。可以简单的记为,touch包含up,down。同时注意,执行两次是在返回值为true的情况下才有的,表示事件被消费了,而返回false时,只会执行一次,表示事件未消费。)

(java中所有的数据类型,哪怕是基本数据类型也有对应的类进行说明,就像Integer,Float,Double,String,Character,Long,Short,特别的还有Enum对enum进行说明。所以说,java的所有数据类型都有对应的类对其进行说明,以供参考。enum的方法来源于Enum类。这里注意,enum是用于定义类的,但是是特殊的类,定义式使用的是enum ClassName{},而没有使用class关键字,同时注意,如果有构造函数,是不对外使用的,只给内部实例使用,同时注意内部的实例使用的是这个构造函数进行的实例化。)

(注意,应该说一个封装好的类就像是一个已经不会在变化的工具,所以我们应该将总是在变化的,我们不可能封装概括的,排除在类之外。就像是布局,我们就不可以将布局封装进类里面,因为实际中布局总是在变化的。这点在封装类时需要特别注意。)

(java中对于成员变量其实可以使用右键类文件,或者在文件空白处右键,然后选择source里面的gerate getters and setters...可以自动生成成员变量的读取以及设置。另外选择source中的genarate constructor using fields...可以生成构造方法。)

(在java中存在assert关键字,当我们使用assert xxx;或者assert xx:sss;是可以设置断言。)

(注意java中是可以使用中文作为名字的)

(每个类都有一个getClass()方法用于得到该对象对应的Class,然后就可以使用Class类的方法进行相应的一些操作了。如判断是否是基本数据类型isPrimitive(),判断是否是某个类的父类或者子类isA三四个那边了From(c),是否是成员类isMemberClass()等功能。)

(在eclipse中按紧shift,并将鼠标移动到某一个对象,可以看到该对象的生命部分。对于系统的类可以看到原代码,对于自定义的对象可以看到该对象的定义。)

(setter,getter返回的是原对象的引用。所以对getter返回的对象操作之后是会影响到原对象的。这点需要注意。)

(在计算byte,short,char类型时,系统会自动将他们转化为int类型进行计算,所以当我们计算完之后再将它们赋值时会出现错误,因为类型变了,这个时候需要强制类型转换。简单点说就是byte a=1;byteb=1;byte c=a+b;是错误的,必须要写成byte a=1;byte b=1;byte c=(byte)(a+b);才是对的。)

(在编程中常常会遇到.bat的文件,这种文件叫做批处理文件,这种文件的作用就是处理一些特殊文件,并且这种批处理文件不能自行运行必须通过cmd命令进行,方式是在cmd窗口中定位到批处理文件所在文件夹,然后使用xx.bat xx.xxx进行处理,这里xx.bat是批处理文件,xx.xxx是所需处理文件名字。而定位到批处理文件所在文件夹可以使用cd \定位到磁盘根目录,使用cd x:定位到某一个硬盘,然后使用cd path进行定位即可。)

(基本数据类型未赋值之前数值是0,对象为赋值之前是null,而一些类的方法在获得对象个数时,常常使用-1表示没有对象,这一点可以在源码中查看,但是不要和基本数据类型,和对象相混淆。)

(在android中有自己的安全模式,即是一个应用对于其他应用的访问必须要去的权限,就是说必须添加<uses-permission android:name="">如对于录音的访问,<uses-permission android:name="android.permission.RECORD_AUDIO">。当然被访问时,也要得到许可,只是这个时候设置是不一样的,如四大组件的被访问设置,如BroadcastReceiver设置<receiver><intent-filter><action></action></intent-filter></receiver>而不是设置uses-permission。这里需要注意,被访问设置往往设置IntentFilter进行被访问过滤。)

(几乎所有的集合,或者类似集合的对象,如String,Collection的子类ArrayList,HashMap等,都与String一样,除了与其所包含的对象的类型方面的操作缺乏之外,将自身所包含的元素看成对象所进行的操作基本都是完备的,因此,所有的集合,以及类似集合的对象的操作方法可以参照String的方法进行掌握。)

(StringBuffer最擅长的是操作内部字符串的各元素字符的增删)

(接口虽然用于继承成为类,但是由使用的功能不同,将其分为作为类用途的接口,作为传给其他类的参数使用的接口,如Comparable就作为类用途的接口,Comparator作为传给其他类的参数使用的接口。简单点说就是Comparable一般用于类继承,而Comparator用作参数,他们都作为排序功能,另外Collections.sort()也有排序功能)

(一个类怎么使用要看其他类的方法的参数是否是这个类,因此想要掌握某个类的使用途径应该掌握有哪些类的方法的参数有使用到这个类,通常情况下,使用与被使用的类在同一个包下,我们可以看一下所要掌握的类在哪个包即可。)

(ContentProvider其实就是一个封装了各种对数据进行操作的方法的对象,并且在AndroidManifest.xml中进行注册。ContentProvider进行操作的数据库可以看成是内嵌的,而且实际上可以是数据库,或者是数据。ContentResolver实际上通过Uri进行操作,因为Uri里面有ContentProvider的注册信息,所以实际上可以说ContentResolver的操作是对ContentProvider的方法进行调用,简单点说就是,ContentResolver的操作方法是调用ContentProvider的方法完成的。)

(注意在寻址项目下的资源中,被编译过的资源是找不到的,只有未被编译过的资源才可以通过寻址找到。而且编译后的可执行文件应该看成一个文件,所以不存在什么路径。至于通过路径寻址找到的资源是路径通过特殊处理找到的。)

(SQLiteDatabase在创建完数据库之后需要创建表格(注意增删查改方法的参数需要表格名以确定需要操作的表格),而事实上,创建表格只能使用execSQL()进行,这里还需要注意,删除有delete(),replace()两种方法。最后一点,实际上实现数据库及其相应操作的是sdk的tools文件夹下的splite3.exe工具)

(BaseColumns,ContentValues,ContentUris,ContentObserver,Cursor,UriMatcher,SQLiteQueryBuilder,URI,Uri,URL这些类的使用可以查看源代码,或者所在包,更重要的是其他类方法的参数是否含有他们,这样就可以确定这些类的作用了。)

(在自行设计某种类时,应先确定是否系统本身没有包含这种类,一般情况下,系统是包含了几乎所有我们所需要的类,特别是数据类。)

(在getAssets()中返回的是AssetManager。另外,如果在assets文件夹像创建文件夹,并在该文件夹下存文件的话,那么,要获得该文件,需要使用getAssets(“document/file.xx”),document是文件夹名,file.xx是所需文件。其实就是在getAssets()定位到的地址进行地址扩展,从未得到资源而已。)

(深度克隆可以使用ObjectInputStream配合ByteArrayInputStream进行,这里所克隆的类需要实现Cloneable,Serializable,同时,clone()方法抛出CloneNotSupportedException(这里若使用super.clone(),再一层层的进行克隆,最后达到深层克隆将会很麻烦,而这里IO将会自行复制,而且是系统进行的复制,将会更加安全。))

(使用clone()返回的是复制对象,而不是原对象的引用,所以对clone()返回的对象操作并不会影响原对象。这里还要分为影子克隆,深度克隆,影子克隆出的对象假如引用其他对象,则引用来自于原对象(也没有别的引用可以使用)。深度克隆需要将克隆出的对象的引用改变,也就是说深度克隆克隆出的对象与原对象完全无关了,操作不会对原对象造成影响,而影子克隆所克隆的对象由于引用来自于原对象,所以会对原对象造成影响。)

(super,this关键字的功能是一样的,不同的是super是向上的,而this是当前的。super可以使用的方式:super(),super.xxx(),this可以使用的方式:this(),this.xxx(),这里super(),this()代表的是构造器,super.xxx(),this.xxx()代表的是方法。另外,this比super多出的功能·就是this可以直接作为参数,原因是this本身代表的就是一个类。而super不行。)

(注意,在eclipse中使用call hierarchy窗口可以查看一个方法被什么方法调用过,和调用过什么方法。但是实际上有的方法在在一个方法中即使被调用了,也是在call hierarchy窗口中看不到的,这点需要注意,同时,不可查看的方法使用ctrl键+单击是不能查找到源码的。总的来说,就是在使用call hierarchy窗口时应该注意,可能有窗口查找不到的被调用的方法未显示。)

(注意在BufferedReader(InputStreamReader(InputStream))中,实际上InputStream作为参数之后使用available()可以发现大小为零了,而ObjectInputStream(ByteArrayInputStream)的ByteArrayInputStream作为参数之后却不会。这虽然是类的设计导致的结果,但是从他们的应用可以知道为什么会出现这样的结果。前者是IO流所以必须要及时清理,而后者是复制,所以不需要,相反,不能清理。)

(注意在应用中使用PipedInputStream,PipedOutputStream实现数据流的管道化可以使得数据双向化,并且这边传送,那边马上就能得到。使用PipedInputStream,PipedOutputStream的最佳场合是Socket网络编程中。实际上网络编程的最关键部分就是IO流的选择,若想要实现数据双向流通就需要使用PipedInputStream,PipedOutputStream)

(注意实际上,eclipse平台在显示文本时使用的是GBK,这点可以右键每个项目,然后在properties选项中看到。但是在编译项目时使用的确实UTF-8这点可以在AndroidManifest.xml中看到。所以如果将一个sgf格式(UTF-8编码)的文件放在eclipse项目里面然后打开,看到的会是乱码,但是run这个项目时,不用更换编码格式,直接使用Log输出却可以得到正确答案。同时注意,UTF系列的都是unicode,即万国码,所有国家的语言编码都包含了。而GBK则是中国独有的,包含了中文的编码格式,同时UTF的字节长度是要比GBK的字节长度要长的。)

(一个软件的设计是从最表面的UI界面开始的,然后才可以往后深化设计,或者说,现有前台,再有后台。所以如果想要重写一个已有的软件,应该从UI界面开始)

(在从一个方法中传入对象时,穿的是引用,但是如果传的是数值,则传的是复制对象。这点需要特别注意。)

(注意return 传递的是引用,而不是另外复制对象。)

(在开发中,一个对象的引用可以传给多个其他对象使用,(在需要用到相同对象,而又不会操作传入的对象时)这样做可以减少内存的消耗,减少比较是否相同的麻烦。但是在UI界面中由于UI对象是需要在界面上显示的,所以不可以使用一个对象在界面上多次添加,这里可以克隆对象进行添加。但是这里需要注意,传引用后,操作引用对象是会直接影响被引用对象的。)

(在java/android中,删除控件实际上就是将控件从容器中删除。因为实际上我们在屏幕上看到的控件是容器的,所以从容器中删除控件即可将屏幕上的控件删除。注意:删除可以分为自我删除,和他人删除。自我删除指的是拥有自我去除的方法,而他人删除指的是需要其他对象的方法来删除自己,而这个其他对象其实必定是容器,这样才谈得上删除。总的来说,就是说,若要删除,入伙自身没有删除方法,那么应该在所在的容器中寻找删除方法。)

(将图片加到屏幕上,其实是屏幕不断刷新的结果,在按下触发粘贴时,屏幕所有的东西都被删除掉了,然后接下来所要粘贴的图片再于删除掉的东西一起被加到屏幕上。简单点说,就是屏幕是不断刷新的(不然屏幕就加不了东西)。而屏幕刷新其实是底层系统自己进行的,我们在加图片时,可以看做仅仅是将图片粘贴在屏幕上即可,至于原理,可以查看Window,WindowManager,因为WindowManager就是连接View与屏幕的管理者。)

(注意,在android中使用项目中gen文件夹下的资源时,一般直接使用R.xx.xxx即可,但是有时候需要全路径形式,这个时候需要写成com.example.projection.R.xx.xxx形式。应该注意,其实这种形式返回的是一个int,即资源编号。)

(ollydbg(即OD)可以用于实现反汇编,它是目前最好的工具,但是需要扎实的基础。注意,反汇编可以看到任何程序的代码。)

(使用命令行adb install path 进行apk安装,将我们想要的app装载到硬件上。)

(使用getWindow().getDecorView().setSystemUiVisibility()之所以可以在任何地方使用是因为getDecorView()得到的是最底部的View,而getWindow()得到的确是加载过其他东西的View,或者说是在构建过程中需要加东西的,所以getWindow().setFlags(),getWindow().requestWindow()需要在setContentView()之前使用。总的来说,就是最底层不变,基层有变,所以底层随意使用,基层不可以。)

(注意,在android真机中,可以通过getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)隐藏屏幕底部的导航栏。通过getWindow().getWindowVisibleDisplayFrame(Rect),Rect.top得到statusbar的高度,通过findViewById(Window.ID_ANDROID_CONTENT).getTop()得到statusbar+titlebar的高度。通过getResources().getDimensionPixelSize(com.android.internal.R.dimen.navitaion_bar_height)可以得到底部导航栏的高度。但是这里注意,调用Window的最底层View,DecorView时,可以在程序中任何地方调用,但是如果操作的是Window则不行,因为Window自身还需要加载其他UI,会出错。最后,需要注意,app自身的坐标系与系统的坐标系是不同的,使用上面的方法得到的东西都是使用系统的坐标系得到的,到时我们使用时用到的却是app的坐标系,而app的坐标系比系统的坐标系下移statusbar+titlebar的高度。)

(Matcher.start(),Matcher.end()可以得到查询中得到的第一个以及最后一个结果的位置。Matcher.startResion(),Matcher.startResion()可以得到查询字符串的范围。这里注意换行符当做两个字符,寻常字符作为一个字符。同时Matcher.find(int)可以将匹配的位置移动到所需位置。这里,Matcher.start()返回的结果会随着Matcher.find(int)的变化而变化,简而言之,就是开始的位置随着匹配的位置的变化而不同。在理解Matcher中,可以将Matcher.find(),Matcher.find(int)看成标尺,需要标尺移动才可以得到后续的结果。同时注意Matcher.lookingAt()方法判断字符串开头部分是否符合。)

(在java中传递参数只有一种方式,那就是传值,除基本数据之外,其他的传值传递的是引用地址。但是这里需要注意,java作为一种安全性极高的语言,在对象作为参数传入之后,实际上方法无论对该对象进行怎么样的操作都不会影响源对象。因为系统会自动根据传入的地址复制一个对象,所以我们在方法里面操作的对象实际上是复制对象。这里需要注意的一点就是,这里的复制使用的是浅赋值,所以虽然不能改变源对象,但是复制的对象引用的对象都是源对象的,所以复制对象如果对自身属性操作的话,那么是会影响到源对象的。总的来说就是,传值传递的是引用,然后系统会根据引用进行浅复制,我们操作的是浅复制对象。)

(一个对象虽然可以改变赋值,但是引用是不会变的。所以在容器类引用对象时,应该注意引用的对象的值的变化。这里需要注意,不可以使用一个对象多次赋值的方式,将赋值之后的对象交给容器类,因为这样的话,容器类引用的对象是同一个,而该对象的值不断变化,这样容器类的数据实际上是发生了变化的。总的来说,就是一个对象多次赋值的方式只适用于将该对象作为中转对象使用,我们可以使用该对象的属性值,但是不能使用对象的引用。)

(注意android自身其实是有自带源代码包的,就在jdk的java文件夹下的src.zip压缩包里,这里不用解压,有方法可以让eclipse现实里面的代码。注意这里面的代码不全。)

(使用Class.forName()时,若需要得到,某个类里面的子类时,可以使用$,例如Class.forName(com.android.internal.R$dimen),这里得到的就是R类里面的dimen类。)

(项目下的android4.4文件夹下面其实存放的是platform文件夹下的android.jar,andoid.jar下面有很多有用的东西,如各种类,以及res文件等,而这些都是可以在platform文件夹下的android19文件夹下面查看的。)

(在gen文件夹下的包里的R.java,BuildConfig.java都是类,我们可以在里面查找到所需的资源,项目信息等。)

(注意,在编程中,implements一个Listener之后,这个类也需要在自身调用Listener的setXXListener()方法才可以,不然不起作用。)

(注意,想要去掉标题烂可以使用两种方法,1.在AndroidManifest.xml里面的android:theme=“@style/AppTheme”修改为android:theme=“@android:style/Theme.NoTitleBar”,但是这个方法有个缺陷,那就是屏幕背景会变成黑色,布局哪里可选控件也会变样。2.使用requestWindowFeature(Window.FEATURE_NO_TITLE),但是这个方法比需要在setContentView之前使用,不然就会发生错误。)

(getWindow().getDecorView().getWindowVisibleDisplayFrame(Rect),getWindow().getDecorView().setSystemUiVisibility(),getWindow().requestFeature(),getResources().getDimensionPixelSize(),findViewByIdea(Window.ID_ANDROID_CONTENT),这些都是用来获得底层的window,项目的信息的。注意,使用DisplayMetrics.heightPixel,以及以上这些得到的bottom的数值实际上是不包括导航栏部分的,也就说,得到1824之后要加上导航栏长度96才可以得到实际的长度1920。)

(在一个方法中,return会结束一个方法,所以return后面的方法是不会执行的。但是,我们可以使用在循环中return,这样,循环之后的代码在循环没有返回对象的情况下是会被执行的。例如public boolean get(){for(){return true;} return false;}这种形式是允许的,并且高效。但是return若没在循环之内,泽是错误的,因为return之后方法结束了,后面的代码不会执行。这点需要注意。)

(注意,自定义布局中,布局类需要添加setBackgroupColor()这样的语句才可以显示图片,否则是显示不了的。自定义布局时完全可以借鉴如AbsoluteLayout这样的布局再继承ViewGroup类得到所想要的布局。同时应该注意,View本身就已经有layout()的方法了,而这个方法是给onLayout()调用的,而onLayout()则是给布局调用的。事实上,布局调用View的过程是:布局类调用layout(),layout()调用onLayout(),onLayout()调用View.layout(),View.layout()调用View.onLayout(),而其实最后一步的View.onLayout()一般没有用,因为View不是布局,所以一般调用到View.layout()就可以了,这个过程可以查看源代码。所以说,自定义View需要继承View,自定义布局需要继承ViewGroup()。)

(注意,在View中,setMeasuredDimension()方法是用于给onMeasure()调用的,其他的调用并没有什么效果。getX(),setX(),getY(),setY()需要在特定条件下得到,这是因为View需要布置图片属性,所以要得到这些属性,必须要在View的这些属性做好的才能得到,不然就只能返回0了。但是这里得到的值未必就是正确的。同时由于各种限制,所以基本上这些方法最好就不要用了。)

(注意需要字符串相关操作时应该从CharSequence为源头查找,因为String是CharSequence的子类,而CharSequence还有更多更有用的子类,更重要的是他是一个接口,而且在java/android中,很多方法是以CharSequence为参数的,而不是String。)

(注意,在实际使用中往往使用的是CharSequence而不是String,因为CharSequence作为最原始的接口拥有更多有用的类。这里Spanned是CharSquence的子类,Spannable是Spanned的子类,SpannableString是Spannable的子类,而SpannableString可以作为TextView.setText(CharSequence)的传入参数,意思就是说传入一个字符已经存在各种操作的字符串给TextView。注意Spanned有很多有用的参数。SpannableString.setSpan(CharacterStyle,int,int,Spanned.xx),这里CharacterStyle拥有很多有用的XXXSpan用于操作SpannableString里面的字符。同时注意,TextView.setText(CharSquence,BufferType.xx),TextView.setTextSize(TypedValue.xx,int),TextView.setTypeface(Typeface,style)都是很重要的方法。这里TextView.setTextface(Typeface,style)中的参数其实使用的都是Typeface的资源。当然,通过XML文件操作也是很方便的途径。)

(注意在java中将字符串画在View上面时是以baseline为基准的。特别是Paint类,Paint类使用上全部都是基于baseline的。在Canvas.setText(Bitmap,float,float,Paint)中,所放置的字符串就是以baseline为基准的,就是说所放置的字符串的坐标在左下角,这点需要注意。同时,对于字符串在View里面的摆放,有几个概念:ascent,descent,top,bottom,baseline,这里bottom,top可以看成是View的,而ascent就是baseline到字符串顶部的距离,descent就是baseline到字符串底部的距离。)

(注意,在java/android中某个类的子类是无法使用ctrl+单击的方法看到的,必须要先转到这个类,然后才可以在这个类里面使用ctrl+单击转到最终的子类。当然可以使用ctrl+shift+T进行搜索。例如Paint.FontMetrics就是这样的,同时FontMetrics类拥有字符串所需的baseline,ascent,descent,top,bottom等重要元素。)

(在android里,XX.class其实代表Class的实例。)

(注意,在java中,路径是一个很简单的概念,可以使用File,FileInputStream等结合路径操作文件,如new File(paht)中,path可以是/xx/xxx/xx.xx,也可以是xx/xxx/xx.xx,而java方法会自动获取系统根目录添加到我们所写的路径中,所以最后的路径就是电脑中某文件路径的形式,例如D:xx\xxx\xx.xx,这里注意,我们自己所写的路径可以使用/或者\\作为分隔符,java方法会自动转化。而在android中,java的类结合路径进行操作文件的方法几乎行不通,因为java是针对电脑的,而android却是手机的,但是android封装了自己的一套方法。同时注意,java项目编译之后文件都是放在一个地方的,而android项目编译之后文件却是放在不同地方的,例如android的assets文件就放在/sdcard里,而项目的各个类文件却是放在/data/data/pachagename/xx里面的,者也是造成android不可以使用java结合路径获取文件的方法的一个重要原因。总的来说,就是java的获取项目文件的方法不可以在android中使用,应该使用android自己的获取项目文件的方法。)

(R类里面的都是类,如id,dimen,drawable都是。可以通过Class c=Class.forName(“com.android.internal.R$dimen”),Field f=c.getField(“navigation_bar_height”),int height=Integer.parseInt(f.get(c).toString()),getResources().getPixelDimensionSize(height)得到导航栏信息,而这时R类里面没有的。注意这里可能涉及到SecurityManager类。)

(注意在java中内置的解析XML类是pull类型,也就是说,使用XmlPullParser。在java中,系统对项目XML文件的操作都是通过pull进行的。同时需要注意,R类实际上的意思就是资源类,即项目的内部资源类,R类对应的是res文件夹下面的资源,所以在res文件夹下的资源的变化也会导致R类的变化,而这种变化是系统自行进行的,一般通过getResources()返回的Resources类的方法就可以对res文件夹下的资源进行操作,例如我们在res文件夹下创建一个xml文件夹,在向xml文件夹下放入xml文件时R就会自行生成一个xml内部类,然后我们可以使用getResources().getXml(R.xml.xxx)就可以返回XmlPullParser的子类XmlResourcesParser的实例。)

(注意解析XML文件并不需要关心XML文件里面具体命名,属性,而android内置pull进行XML文件解析,所以事实上android的XML文件并不用拘束于XML的命名,属性,只是一些特别的XML文件系统会自行加载一些方法以方便操作而已。)

(注意Timer定时器可以利用TimerTask去实现某些事情。这里应该注意,其实Timer里面有自定义了一个TimerThread类(TimerThread继承Thread)帮助自身,同时有一个TaskQueue用于存储TimerTask(其实TashQueue是一个包含TimerTask数组的类,而不是继承自Queue的类)。而TimerTask是实现了Runnable接口的类。这里还用到一个Message类用于承载信息,TimerTask利用Handler.sendMessage(Message)发送信息,而sendMessage()方法会自调用Handler.handleMessage(Message)方法,我们可以在handleMessage()方法里面处理我们需要实现的事情,可以顾名思义,Handler就是一个处理类。总的来说,就是Timer定时调用TimerTask,TimerTask调用Handler实现我们需要处理的事情,这里Timer,TimerTask自身都是有另开线程的,毕竟定时做某件事情。)

(在android中,程序第一次运行时,系统会自行给程序创建一个linux进程,一个主线程(也叫做UI线程)。所有的UI相关的操作基本都是在UI线程里面实现的,如果想要使用另外一个线程更新UI,则必须使用到消息机制,否则出错。消息机制,就是子线程传递消息给UI线程,让UI线程自行更新UI。消息机制简单点就是说使用Handler处理器进行处理的机制。这里Handler涉及到Thread,Looper,Queue,Message等类。Looper里面包含了Message的Queue,所以Looper管理着Message的Queue,同时Message的属性可以指明需要哪个Handler用于执行Message,而这里的Message可以通过Handler发送。这里注意如果Handler想要接收到Message,则Handler必须要实现一个Looper,然后Looper里面的Message的Queue才可以接收到Message。最后Looper属于哪个线程,则接收到Message的线程执行Message。对于UI线程的Handler不必实现Looper,因为系统自动帮UI线程加载Queue。简单点说,就是Handler在含有MessageQueue的Thread之间进行sendMessage()以及handleMessage(),或者说Handler就是他们之间的桥梁,sendMessage(),handleMessage()的Handler必须是同一个否则出错。)

(如果需要线程长时间运行,那么最好的选择就是使用java.util.concurrent包中的类,应该注意,该包中有很多很有用的类,他们都可以用于操作线程,例如Executor,ThreadPoolExecutor,FeatureTask等。)

(View.invalidate(),View.postInvalidate()都是用于更新界面的,但是前者需要在UI线程中使用,而后者则可以在子线程中直接调用。)

(需要长时间运行的线程可以选择在后台运行,而这个时候可以选择使用AsycTask类。在UI线程中实现AsycTask的实例,并调用execute()方法。AsycTask的实例必须要实现doInBackground()方法,然后可以实现一些线程在后台运行时周期相关的方法,onPreExecute(),onProgressUpdate(),onPostExecute(),实际上这就是生命周期。同时可以调用一些方法来显示进度publishProgress()。)

(这里HandlerThread是一个自行创建Looper的Thread,这样我们在使用Handler+Thread模式时就可以不用创建Thread实例时还要在创建Looper)

(ThreadGroup是一个包含Thread数组的类集。)

(注意实际中,在java编程中,应该使用:并发的概念,而不知Thread。同时注意,java中线程组是一个没用的东西,使用Executor代替即可。)

(注意原子类型暂时不用用到,这是达到专家水平才需要看的,因为原子类型是机器级别的,常见的原子类有AtomicInteger,AtomicLong,AtomicReference。)

(注意java中所有的对象都自动实现对象锁,同时如果想了解对象锁的话可以使用Lock,ReentrantLock,但是使用它们没有系统加载的对象锁那么优雅,同时注意,这里只有对象锁为0时,才算是完全解锁,而其他对象在对象锁未完全解锁时,不能操作对象锁所在的对象。这里调用一个synchronized模块时,对象锁加1,执行完之后减1。因为涉及到连续调用,也就是模块之间的调用,所以调用对象时,对象锁并不一定为1)

(注意volatile关键字用在多线程中,用于告诉线程,不保留拷贝,直接访问变量的内存地址。其实在线程中对于变量,线程为了提高效率对变量进行了复制,我们实际操作的是复制的变量,只有在某些操作中在对原变量以及复制变量进行同步)

(注意不能使用Thread的suspend(),resume(),stop()方法,因为会出错。这里suspend(),resume()存在出错可能,而stop()则是不会交出对象锁,并且在线程受损的情况下可以被修改,所以出错。这里Thread.sleep()不是放对象锁,Thread.wait()中由于wait()方法来自Object,所以会释放对象锁。)

(ThreadPoolExecutor是最核心的类,用于掌管线程池。ScheduledThreadPoolExecutor则是除了掌管线程池之外,还可以定时触发任务。RejectedExecutionHandler则是线程池策略的基类,不同于Policy类,这里它也作为ThreadPoolExecutor的属性进行策略设计,可以使用ThreadPoolExecutor.getRejectedExecutionHandler()进行查看。ThreadFactory是线程工厂,用于定制线程,ThreadPoolExecutor就是使用它作为自己的一个属性,进行线程定制,可以使用ThreadPoolExecutor.getThreadFactory()查看。ExecutorService是线程池的服务,可以随时关闭线程池,Executors是线程池工厂,用于创建各种线程池,同时Executors操作Callable接口,这里Callable的功能类似于Runnable,但却更加有用。Future类表示异步计算的结果,ExecutorService.submit()方法会返回Future。Executor内含一个线程池,他所运行的线程其实都是先放到线程池里面的,作为客户端与任务执行的中间层,其实任务的执行是通过它来管理执行的。)

(java的Executor架构,包含多个类,基本用于并发操作,使用的基本都是java.util.concurrent包下面的类。而实际上Executor框架里面的类基本都是涉及到线程池的。如Executor类。)

(注意在android中,使用Preference及其子类开发的控件与View及其子类开发的控件其实是差不多的,但是由于Preference对于数据的操控,所以功能上才会出现差别。其实Preference将键值对数据存储在SharedPreferences的文件夹下,然后使用这些数据进行控件加载,所以效率更高,可控性更强,同时存储更加简洁,但是UI上却比View类的逊色一点,这里注意Preference类这个板块的UI除了Preference及其子类,还有其他的如xxPreference,PreferenceXX这种形式的类也具有Preference的属性,如PreferenceFragment。这里还需要注意使用,Preferences类(注意这里是Preferences,而不是Preference)虽然操作数据,例如加载系统,用户的各种数据,并且在操作数据以及数据存储上与SharedPreferences类似,但是Preferences是一个抽象类,并且不用共享。总的来说,这里SharedPreferences,Preferences,Preference三个类其实都是在功能上很类似,都是操作键值对数据并且都是存储在SharedPreferences的文件里面的,不同的是SharedPreferences主要是存储共享数据,Preferences则是单纯的存储各种数据,而Preference则是应用在UI上。其实拥有Preference属性名字的类基本操作都与以上所说的三个类相类似。)

(F1键可以打开Help栏,在这个栏里面有一些很有用的操作。)

(F2可以小窗口打开javadoc查看类信息。这里注意F2查看到的类信息并不是类源码,而是更加简练的类使用信息,这点对于快速掌握类还是很有帮助的,同时如果是在javadoc栏里面,那么将鼠标放在某个类,则javadoc会自动更新该类的信息。这里需要注意,同名字的类可能会有选择的显示,所以最好就使用ctrl放在类上面查看是否存在相同名字的类。)

(Fragment在两个包中存在,分别是android.support.v4.app.Fragment,android.app.Fragment。两个包的方法其实是相对应的,或者说两个包的Fragment在使用上基本事项类似的,但是使用上有一些区别:android.app.Fragment需要较高的版本号,使用使用Fragment的Activity直接继承Activity即可,在XML中可以直接使用<fragment>标签。android.support.v4.app.Fragment虽然并没有对版本号有要求,但是使用该Fragment的Activity需要继承FragmentActivity,不然在XML中使用<fragment>标签时会报错。简单点就是说,android.support.v4.app.Fragment是外加包,而android.app.Fragment则是新版本添加的,所以android.app.Fragment在优化上较之android.support.v4.app.Fragment做得更好。)

(特别注意,对于各种类的使用,在android官网有各种demo。总的来说,就是遇到不会用的类,应该到android官网查看demo而不是网上查找,这样效率更高。注意官网上面基本拥有所有想要的资源,所以以后查找东西先到官网。)

(注意在java中可以使用System.arraycopy()对两个数据之间进行复制。)

(注意,在activity中已经有了实现ContextMenu,OptionsMenu,MenuItem的方法了,同时还可以监听。这是因为菜单必须要依附于app,所以Activity里面才会有菜单所需各种方法。)

(app的TitleBar的界面只能通过XML文件改变,使用Window的setFeatureInt()修改,而修改尺寸需要在AndroidManifest.xml中修改android:Theme=“@style/name”,这里的xx是定义在style.xml文件下的<style name="name" parant="xx"><item name="android:windowTitleSize">xx</item><style>)

(注意在View中有startDrag()方法实现拖曳功能,通过这个方法可以掌握View对象怎么实现拖曳。)

(注意在使用SurfaceView中实际上是不必另开线程的。另外注意,在编程中获取资源图片生成对象是最耗时的,一般在使用Bitmap时对于相同的图片应该只获取一次,然后其他对象在使用Bitmap对象时都指向这个对象即可。简单点说就是实际上,对象都指向图片在内存中的空间这样是最高效的,不用同一个图片生成多个Bitmap对象,这样浪费资源又耗时。同时注意,lockCanvas(),unlockCanvasAndPost()会将就的图片删除,加载新图片。最关键的一点就是将图片绘制在屏幕上其实是最耗时的,所以将图片通过Canvas合成一张在一次性放到屏幕中这样可以大大提高效率,也就是使用双缓冲技术。)

(双缓冲技术顾名思义就是有两个缓冲区,一个先画好了,第二个画布直接将第一个画布显示出来,这让第一个画布可以在后台内存中先画好。)

(Canvas可以用于Bitmap图片的绘制,可以使多张图片加载成一张图片。)

(其实在SurfaceView中,实际上操作的是Surface,Surface对应了一个屏幕缓冲区。在传统的UI中,一个Window就是一个Surface,多个view共用一个Surface,而SurfaceView则是内含了一个Surface。)

(注意Canvas类有两种作用,当使用new Canvas(Bitmap),或者在Canvas canvas=new Canvas(),canvas.setBitmap(Bitmap)后,则Bitmap将会在后面的drawBItmap()中,被改变,而如果使用的是Canvas canvas=new Canvas(),然后就直接drawBitmap(Bitmap,int,int,Paint)那么作为drawBitmap()传入值的Bitmap是不会被改变的。总的来说,就是作为Canvas构造器以及构造器补充方法setBitmap()的Bitmap对象是会被改变的,而作为drawBitmap()传入值的Bitmap不会被改变。)

(注意在编程中,调试不等于测试,测试要比调试难很多,而在实际中我们经常使用的是调试debug,也就是Log,而测试则是更加难的技术。在java/android中最常见的测试技术应该就是TDD测试驱动开发了,在java/android中,TDD的使用具体表现为使用Junit Test进行的开发。这个过程实际上是构思,编写测试代码,编写代码,测试。这里测试代码实际上相当于一个基准线,或者说一个范围,我们后面编写的代码实际上都是在实现这个测试代码而已,而他又是一个范围,因为我们的功能事先必须在这个范围之内,所以这里涉及到了极限编程。另外这里还涉及到重构。JUnit Test在实际编程中,继承TestCase就可以进行测试了。这里注意其实这里可以创建Junit test case文件,andoid test projection项目。可以在右键单击项目文件之后在run as中查看有哪些类型是我们可以用于测试的。)

(注意在实际编程中,就像测试不等于调试一样,注解与注释也是不一样的,注解比注释更加有用,但同时又更难。应该说注解是更加高级的测试技术。而在java/android中有专门的东西用于注解,这里java.lang.annotation.*包下面有包含注解所需的一些类。注解又叫元数据,是一种代码级别的说明,注解至少有三个作用:1.生成文档2.分析代码3.编译检查。生成文档其实就是根据标识的元数据生成doc文档,分析代码其实是使用反射功能进行分析,而编译检查实际上是override功能的使用。总的来说其实注解最关键的还是他的分析代码功能,因为可以用于测试代码。这里注意,注解有两个需要注意的东西:注解,注解类型,这里注解类型相当于一种特殊类型的接口,而注解则相当于实例。使用自定义注解时,在使用@interface后其实系统已经自行继承了Annotation类了。使用getAnnotation(),getDeclaredAnnotation()通过反射得到注解元素的值。特别注意,Annotation有好几个类型,分别在java.text,android.text,java.lang.annotation包中,注意所需要的Annotation在哪个包。)

(程序是在线程中运行的,而程序就相当于任务,这些任务被放在线程的队列中等待运行,而什么实用运行则是轮询器负责的。总的来说,他们的关系就是轮询器Looper管理队列Queue,Queue存在于线程Thread中,而程序任务则是在线程的队列中等待运行。所以可以在任何地方通过Looper类的静态方法得到主线程,队列,所在队列,所在线程等。这里可能还会用到双端队列Deque。使用Activity.runOnUiThread(Runnable),Activity.getMainLooper等操作线程,队列。)

(注意线程间的上下文切换是开销是很大的,因此尽量少的使用线程,之所以切换线程开销大是因为在切换的时候,前一个线程的对象需要保存,而新的线程的对象需要实例化,所以会出现很多对象的生成,保存等操作,而对象的操作是最浪费资源的,所以开销很大。这里使用到通道Channel的话,会涉及到Selector通道选择,Selector可以检测通道存在与否,是否准备好IO。这样有了Selector,一个线程就可以管理多个通道Channel了,而Channel是连接网络的,所以可以说一个线程的Selector可以管理多个网络连接。在使用上,Selector=Selector.open()可以得到Selector实例,为了将Channel,Selector配合使用,需要将Channel注册到Selector,使用SelectableChannel.register(Selector,int)将Channel注册到Selector中,注意一般使用SelectableChannel的子类SocketChannel注册。总的来说,就只需要记住Selector操作通道Channel。线程切换开销很大。)

(注意,得到的Method其实只是相当于一个方法的框架而已,或者说,使用方法的所以而已,而Method本身其实做不了什么事,我们想要得到Method所代表的方法的结果需要使用Method.invoke(Object,argument...args)这里invoke()方法里面Object是Method所代表的方法所归属的类实例,而args则是我们穿进去的参数,这里如果方法没有参数,那么使用null代替args即可。应该说Method对象的得到基本上是不涉及实例的,我们使用Class.getMethod(String,Class...)得到Method,而这种方式却可以通过类得到Method实例,所以说Method是一个框架,一个引用,只有在Method.invoke(Object,argument...args)时,才传入参数。总的来说,只要记得Method是一个方法框架,方法引用,只有在最后需要使用时才传入实例。)

(注意使用getAssets().list(“”)虽然可以得到assets文件夹下的文件的列表,但是会多出三个文件images,sounds,webkit,所以在使用AssetsManager获取assets文件夹下的文件时应该注意,所获取的文件列表会比编程者放入的文件多出三个,这里可以创建一个文件夹,把我们的文件放到里面,然后list该文件夹下面的文件,这样就不会受到images,sounds,webkit三个文件的影响了。另外注意getAssets().list(“/”)可以得到文件列表。)

(特别注意,在String中String.substring(int  start,int  end)得到字符串时,注意,start若为0,end若为1得到的实际上是第一个字符,也就是说,substring()方法的start位置是在字符串的开头前面,而不是第一个字符,这点需要特别注意。总的来说就是,字符串的首字符子串若使用String.substring(int  start,int  end)得到,那么start应该是0,end是1)

(特别注意,src文件夹下的包一般放置的都是类文件,但是其实他是可以放置其他文件的,例如图片,这个时候我们就应该使用文件夹下的某个类xx.class去获得文件,一般可以使用getResource(),getResourcesAsStream()等,其实就是使用Class的方法。但是一般不将其他的文件放在src文件夹下。而这里最特别的其实是使用src文件夹下的类对整个项目的资源进行获取,这里比如说使用xx.class.getResourcesAsStream(path),这里path路径就是最重要的,使用/作为根目录,例如使用/assets/xx.png就可以获取assets文件夹下的xx.png图片了。总的来说,可以使用xx.class.getResourcesAsStream(String path)简洁记忆。)

(注意反射的性能远慢于直接代码,所以在使用反射时应该注意性能的问题,尽量不要把反射加入到核心逻辑里。)

(Display用于屏幕尺寸,分辨率,刷新频率,屏幕方向等操作。最顶层的Window的DecorView就有一个Display,而我们的View实际上都是要放在这个DIsplay的,因为Display实际上连接了屏幕与程序。这里使用getRefreshRate()可以得到屏幕刷新频率,getPixelFormat()返回像素格式,这里一般使用getRotation()代替getOrientation(),使用getSize(Point)代替getWidth(),getHeight()。)

(注意可以通过各种方式得到项目下的资源,文件,应该说任何一个类都可以获得项目的任何资源以及文件。最通用的方法使用xx.class.getResourcesAsStream()获得,这个方法并不需要传递任何参数即可获得项目下的资源,文件。)

(注意Scroller类实际上是帮助View实现平滑滚动的帮助类,但是Scroller类仅仅是帮助View记录和计算滚动的位置,View是在View.computeScroll()中完成实际的滚动的,同时注意,还要搭配View.invalidate()方法使用来可以保证computeScroll()方法被调用,否则不一定看得到效果。可以看源码验证滚动的实现。总的来说,就是使用Scroller类记录,计算,然后重写View.computeScroll()方法,在方法里面使用scrollTo(),scrollBy()等方法将Scroller的值赋予View,然后使用View.invalidate()使方法生效,例如public void computeScroll(){scrollTo(Scroller.getXX(),Scroller.getXX());View.invalidate()}。这里特别注意一点:Scroller是View的帮助类,而ScrollView则是一个控件。)

(注意,Spanned,Spannable,SpannableString从左到右分别为父类到子类,而前面两个是接口,只有SpannableString是类,而该类一般用于给自身的字符串设置字体,颜色,风格等。这里其实SpannableString总的功能都体现在setSpan()方法上,方法的第一个参数可以是XXSpan,这种XXSpan类用途非常广,例如超链接等,设置颜色等,如ImageSpan,URLSpan。总的来说可以将SpannableString看成一个String的装扮类。)

(特别注意,因为java有linux,windows等不同操作系统的版本,所以在使用换行时,有不同的表示方式,linux的换行是\n,而windows的换行是\r\n。但是需要注意的是,android是基于linux的,所以android使用换行时,使用的是\n,而不是\r\n,这里如果在android中,多了\r,那么会多出一个空格。最需要注意的是,在java/android中,虽然几乎所有的符号都是以双反斜杠组成的,但是对于,\n,\r,\f,\t,\e等一类的却是不可以使用双反斜杠的,而应该使用单反斜杠,不然反而会出错。)

(注意,View类使用onDraw(Canvas)中的Canvas.setText()进行字符串设置时,即使使用了正则表达式的换行符\n,字符串在Canvas中也是不会自动换行的,而是多了一个空格,这里的换行需要我们自己设置,我们可以多次使用Canvas.setText()加载字符串。总的来说就是,Canvas.setText()可以判断正则表达式,但是他只是单行的,所以如果是换行符,那么就只能加个空格表示换行了,但是可以加载多次Canvas.setText(),这样就有多行了。)

(关于TextView,我们可以使用setMovementMethod(new ScrollingMovementMethod())为其添加滚轮效果,但是TextView的滚轮效果是没有滚动条的,但是我们可以将TextView放到ScrollView里面,这样的话连setMovementMethod(new ScrollingMovementMethod())方法都不用设置了,同时可以使用ScrollView的View.setScrollbarFadingEnable()方法设置滑动条显示。这里还涉及到setEms(),setSingleLine(),setTextSize(),TextView.setHorizontalScrolling()等方法。总的来说就是,TextView可以自行或者配合ScrollView实现滚轮效果。)

(总的来说,自定义字符串的View时,换行需要自己写代码实现,而使用TextView的话就不用,而且TextView可以实现滚轮效果。)

(注意使用View.setDrawingCacheEnable(),View.getDrawingCache()必须要在界面建造完成之后才可以运行,因为我们使用这两条代码的目的就是为了获取View中缓存的界面图片。View.setDrawingCacheEnable()设置需要缓存,这样界面图片才会被放入缓存,在使用View.getDrawingCache()才可以从缓冲中得到界面图片。)

(注意View.findViewById()虽然是View的方法但是实际上却是留给他的子类Window使用的。Activity也有相同的方法,Activity不是View的子类,他通过调用最底层的Window调用Window的View.findViewById()方法得到在Activity.onCreate()中setContentView(int)时加载的布局里面的控件。这里注意XML文件里面的控件必须要在setContentView()时加载过,这样onCreate()才会处理,然后使用View.findViewById()才可以得到XML文件里面的控件,否则返回null。总的来说,就是View.findViewById()其实返回的是View里面的子View。)

(注意Context.sendBroadcast()之所以是Context的方法,是因为在一个app发生变化的基本都是View和环境,而View的实例化是new View(Context),所以由Context来发送广播是最合适的。总的来说就是View和环境是变化的根源,所以使用Context.sendBroadcast()广播最合理。)

(注意Activity.startManaging(Cursor)可以用于管理数据库,之所以是在Activity中,而不是在其他类中实现这一方法,是因为数据库是后台程序,而Activity作为连接view与model的controller,所以在Activity中实现才是最佳选择。最关键的是,Activity.startManaging(Cursor)是Activity作为controller层最有力的证明。)

(注意SQLite最好是与ContentProvider配合使用,这样就不用关心自身的生命周期了,因为有ContentProvider帮忙管理,同时我们可以通过Context.getContentResolver()得到ContentProvider管理的数据库,最关键的是操作上的方便。这里之所以Context.getContentResolver()方法是Context的,而不是Activtiy的是因为作为一个环境去获得数据更加符合new View(Context)这个构造函数,而一般需要后台数据的都是前台的view层,也就是说mvc的要求。总的来说Context.getContentResolver()之所以是Context的方法是因为mvc模式的需要,因为new View(Context),我们可以使用后台数据实例化View对象。)

(特别注意,实际上当一个View被添加到一个ViewGroup里面时,其实尺寸信息都是通过View.MeasureSpec传递给View.onMeasure()的只是这个过程被封装了所以很难看出来,但是可以通过源代码看到。总的来说就是,添加View的过程虽然没有出现View.MeasureSpec,但是实际上传递尺寸,模式都是通过View.MeasureSpec传递的,查看View.onMeasure()可以看到View.MeasureSpec被使用的过程。)

(特别注意,对于View的getX(),getY(),getLocationInWindow(),getLocationOnScreen(),getLocalVisibleRect()是可以得到正确返回值的,关键在于应该明白,他们返回的值都是在UI界面构建完毕之后才可以得到的,因为只有在UI界面构建完毕之后才可以确定坐标。同时注意使用setX(),setY()之后View的坐标会在原本的坐标之上加上所设置的值。)

(特别注意,在View中同样是由生命周期的,例如onAttachToWindow()可以在onMeasure()之前或之后调用,但是却必须在onDraw()之前调用,这点其实可以从UI如何加载想到为什么会这样。同时注意View.getDisplay()方法必须要在onAttachToWindow()之后才可以得到正确的返回值,之所以这样是因为View使用的是底层的Window的Display,只有SurfaceView有自己独立的Display,但是最终还是归于Window的Display的。)

(特别注意,在View中有回调方法对应监听器,例如View.OnTouchLIstener对应View.onTouchEvent(),这里关键要明白,对于系统来说,如果同时设置了他们,那么系统优先使用监听器,如果监听器返回的是true,那么回调方法将不会被调用。除非监听器返回false,这时调用完监听器,回调方法才会被调用。)

(特别注意,View并非完全有回调方法对应监听器,这里从“回调方法”顾名思义就知道,需要有回调事件XXEvent的监听器才有回调方法。总的来说,可以理解为在View的监听器里面的内部方法的参数如果有回调事件XXEvent出现,那么View就有为其封装相应的回调方法,不然就没有。)

(特别注意,Window类并不是View的子类,Window是直接从Object生成的。应该说Window,Display作为比View更高级的掌管硬件连接的类不可能是View的子类,他们都是直接从Object生成的。)

(特别注意,在获取服务类的时候使用的都是Context类的参数,例如getSystemService(Context.CLIPBOARD_SERVICE)就可以获得ClipboardManager剪切板类。所以以后需要获取系统的服务类应该到Context类里面看看是否Context类存在参数可供调用。总的来说就是,Context存在调用系统Service所需的参数。)

(特别注意,在android系统中有一个Build类用于保存已经封装好的系统的各种配置参数,例如版本号,cpu,id,用户等。)

(注意在使用剪切板ClipboardManager时,如果传递的是自定义的类,那么就必须使用Base64将自定义的类转化成字符串传递,可以使用ObjectOutputStream将对象转化为byte[ ]然后使用Base64.encodeToString(int[ ],int)转化为可以传递的字符串,这里第二个参数是Base64自带的参数,一般使用Base64.DEFAULT。)

(特别注意,View.onDragEvent(),View.onDragListener监听的是任何拖曳进View的对象,而不仅限监听自身。View.startDrag()仅仅起到一个传递数据,创建阴影的作用而已。这里使用View.startDrag()与View.onDragEvent()或者View.onDragListener时,容易出错的是,监听View.startDrag()的View对象,这样一旦这个View对象拖曳出了View自身,那么监听就监听不到了,因为这样设置监听的是自身。就算不断设置View的范围在触点范围内也是不起作用的,因为事件源刚确定,还来不及监听事件源又移动了。)

(在开发机中的/system/bin下面有着我们用到的所有命令,这里大部分都是sdk的tools文件夹下的工具,只有一部分的linux命令。这里通过adb命令使用linux的shell命令,adb其实就是android debug bridge安卓调试桥,我们使用它对开发机进行各种操作,调试,管理。另外,由于/system/bin下面存在其他的开发工具,所以我们也可以使用用这些工具进行必要的操作。同时注意,要在cmd中使用工具命令可以将sdk的tools文件夹添加到环境变量中,或者直接将cmd命令移动到sdk的tools文件夹下面。这里注意,其实linux的shell命令就在/system/bin目录下面的sh文件,所以当使用adb shell xx命令,而找不到相应命令时,会提示/system/bin/sh: list:not found。总的来说,我们可以查看sdk的tools文件夹下的的各种工具以进行各种操作,调试,管理等。最关键点在于,如果在使用时,忘了命令,可以使用工具或者命令的帮助功能,例如adb help会显示所有adb命令,而android -h则会像是所有android命令使用形式,这里android是一个工具。同时在使用时可以使用ctrl+C强行停止cmd命令的运行。最后,android底层是linux的内核,必须掌握linux。)

(su命令是用于切换用户的,除了超级用户之外。这里可以理解为select user命令。作为linux命令,在android中也是有使用到的,在代码中使用Process=Runtime.getRuntime().exec(“su”),Process.getOutputStream()就可以得到操作流,然后在流中使用su命令即可,例如将得到的流包装成DataOutputStream,然后使用writeBytes(“linuxcommand”)即可,然后在输出流中得到输入流即可判断运行结果。)

(注意在cmd命令中,使用ipconfig,或者ipconfig -all可以看到所有的网络地址等参数,使用PING命令可以查看网络是否连接通畅,这里PING的意思是Package Internet Grouper因特网包探测器。在cmd中可以输入ping,然后按enter查看ping命令可以跟随什么参数。ping命令发送ICMP因特网新报控制协议请求回答。总的来说就是ping命令就是用于查看网络是否通畅的。)

(注意,在View中只有setX(),setY(),getX(),getY(),getLayoutParams().width,getLayoutParams().height,而没有getWidth(),getHeight(),setWidth(),setHeight()等方法,而这几个方法事实上都是TextView及其子类Button的使用方法。同时注意,View中setX(),setY(),getX(),getY()在使用时并没有什么限制因为X,Y是View的属性。但是View的getLayoutParams().width,getLayoutParams().height在使用时却不同,要么设置了LayoutParams,要么通过这两个方法自身设置了,不然,在后面取不到值,同时由于width,height是在UI界面确定之后才可以得到的属性,所以View的getLayoutParams().width,getLayoutParams().height必须要在setContentView()之后使用才可以,同时使用这两个方法的View必须加入到setContentView()的参数View里面,否则返回空指针。同时在使用TextView及其子类Button的方法getWidth(),getHeight(),setWidth(),setHeight()时,应该注意,虽然setWidth(),setHeight()在使用后可以改变View的宽高,但是getWidth(),getHeight()在onCreate()中却得不到返回值,必须要在界面加载完毕之后才可以得到返回值,例如在onWindowFocusChanged()中可以得到返回值。注意,对比View的getLayoutParams().width,getLayoutParams().height与TextView的getWidth(),getHeight(),前者需要设置LayoutParams,或者自身之后才可以得到返回值,但是不用等到UI界面加载完就可以得到设置过的值,而后者不需设置就可以得到宽高,但是却需要在UI界面加载完毕之后才可以得到值。)

(在使用Class=Class.forName("com.android.internal.R$dimen"),Field=Class.getField("navigation_bar_height"),int h=Field.get(Class)中得到的其实是R类的导航栏高度的ID索引,还需要通过getResources().getDimensionPixelSize(h)返回最终值。)

(重点注意,GestureDetector类的使用其实很简单,就是实例化一个GestureDetector对象,然后使用GestureDetector.onTouchEvent(MotionEvent)帮助View.onTouchListener的onTouch(View,MotionEvent)的参数MotionEvent处理手势。总的来说GestureDetector类的使用就在于实例化,然后使用onTouchEvent())

(在java/android中单元测试是一个很重要的板块,这里所有的单元测试类都是Assert类的子类,包括java使用的抽象类TestCase,以及android使用的AndroidTestCase,InstrumentationTestCase。这里其实无论java还是android,在测试时候做的事情基本都相同就是继承需要用到的测试类,在旧版本里面可能需要实现setUp()初始化,tearDown()销毁两个方法,同时所测试的方法需要以test开头,但是在新版本里面则没有了这些限制。但是在使用单元测试时,测试方法应该以test开头,方便测试。同时注意,在android测试中,需要在AndroidManifest.xml文档中加入<uses-library android:name="android.test.runner"/>以及<instrumentation android:name="android.test.InstrumentationTestRunner"  
        android:targetPackage="com.example.anim5" />

以说明测试需要的资源寻址。

(编程应该从框架板块入手,明确每个版块的作用,然后定义好板块功能框架,这里使用单元测试可以实现。然后逐步向底层实现。同时最需要注意的是不能因为一部分功能而导致整个程序都不能运行,这样耦合性太强了,不利于工作的进行与进度的展示。总的来说就是应该从正常的程序设计顺序入手,明白要实现什么功能然后再去实现。)

(注意使用Class.forName(path).newInstance()时加载的类应该使用路径,但是加载的类不用加后缀,例如java.lang.Thread,同时加载的类必须要有无参构造器,否则加载不了。)

(特别注意,在使用自定义类加载到容器类时,应该重载自定义类的equals(),hashCode()方法,因为容器类的get(),remove()等方法就是用过equals(),hashCode()这两个方法来获取我们需要的东西的。同时注意,如果是Collection及其子类,那么可以只重载equals(),但是Map及其子类则必须equals(),hashCode()都重载,因为Map及其子类获取内部对象是通过hashCode()找到地址,然后通过equals()比较对象是否正确,然后得到返回值。)

(特别注意,可以使用Reousrces.getSystem()方法,这个方法是静态的,可以用于得到一个可以得到系统资源,而非项目资源的Resources类。)

(特别注意,Class.getResourcesAsStream()这个方法用于加载与类文件处在同一个文件夹下的文件,同时这个方法的缺点就是加载速度慢,这里可以从他是Class类的方法就知道它的局限性。)

(操作界面中的各种栏requestWindowFeature(Window.FEATURE_NO_TITLE);可以隐藏标题栏,getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);隐藏状态栏)

(这里特别注意,在需要定制app的各种栏屏,例如状态栏,标题栏等时,最好在Activity未启动之前设计好。同时注意,定制横竖平时,如果在Activity中加入程序段进行说明,那么Activity将会运行两次,也就是说运行了两个生命周期。我们应该在AndroidManifest.xml中定制标题栏,状态栏等,这样,在Activity未启动之前就已经设计好这些栏了,当然,也可以在创建项目时定制Activity。这里可以在AndroidManifest.xml的<application>项里面添加android:theme="@android:style/Theme.NoTitleBar.Fullscreen"定制一个无标题栏,无状态栏的界面。可以在<activity>项里面添加android:screenOrientation="landscape"说明横竖屏,这样就不会出现Activity运行两次的情况了,因为Activity未运行前,横竖屏就已经确定了。但应该注意的是上面所说的情况实际上是在首次加载之后才不会出现生命周期运行两次的情况,而如果考虑首次加载,那么需要在AndroidManifest.xml的<activity>项里面添加android:configChanges="keyboardHidden|orientation|screenSize"令第二次生命周期变为调用Activity.onConfigurationChanged()方法,这里android:configChanges的属性需要添加keyboardHidden,orientation,screenSize三个属性,特别是screenSize属性不可缺少,不然不会调用Activity.onConfigurationChanged()方法,但是初次调用的误差意味着我们需要在Activity.onConfigurationChanged()加入用于修改误差的代码,特别是界面需要重新setContentView()。)

(特别注意,java是可以使用枚举类型作为switch()以及case XX:的输入参数的,只是case XX:中XX中应该直接写枚举类的内部子类(也就是需要枚举的东西),而不用加父类前缀,这样反而错误,相反,case XX:后面的语句就一定要加。例如EnumDefine枚举类,有内部子类SonEnum,并且有xxx()方法,那么可以写成switch(EnumDefine){case SonEnum:EnumDefine.SonEnum.xxx()})

(特别注意String.substring()这个方法的参数,这些参数不是指第几个字符,而是指第几个分隔符。例如“abcd”,这里substring(2,4)方法其实返回的是cd,而substring(0,2)ab。)

(注意,StringBuffer,StringBuilder必须使用自身的方法修改自身才可以修改传参前的内容,如果重新赋值,那么是完全修改不了传参前的内容的。总的来说就是,StringBuffer,StringBuilder相当于同步异步的内存空间,StringBuffer同步,StringBuilder异步,我们可以通过方法操作这些空间修改传参前的内容。)

(特别注意,在每一个switch的case语句的最后必须要断开执行,不然case执行完之后会继续往后面的case执行直到结束。一般可以使用break断开。)

(String虽然可以判别正则表达式,但是并不会执行,真正执行String代表的正则表达式的是拥有这个String的对象。也就是说String仅仅拥有判断正则表达式书写是否正确的功能。例如,TextView.setText(String)这个String里面包含正则表达式如“xxxx\nddd”这个时候在TextView的UI里面出现的换行其实是TextView通过识别正则表达式之后做出的换行,而不是String拥有换行功能。)

(注意,枚举类型的类都是单例型的。同时注意,在比较是否相同时,使用equals()方法是因为有一些类比较方法有重载过,而且equals()方法用于比较对象,而==比较大小是值比较。)

(特别注意,在java中使用==表示对比数值或者引用,而使用equals()则表示对比内容。这里Object的equals()实际上使用了==进行对比,而Object的子类的equals()方法则大多都是重载过的,用于对比内容,例如String的equals()就是这样。)

(注意,在实际使用中,如果想要自定义的类可以在XML文件中使用,比如在布局文件中使用,那么可以在工程下面的value文件夹下新建一个比如XX名字的XML文件XX.xml,这个时候文件夹里面已经有了<?xml version="1.0" encoding="utf-8"?>标签,我们在里面创建<resources><declare-styleable name=""></declare-styleable></resources>,然后在<declare-styleable>标签里面添加需要的属性一般是以<XX name=""  format=""></XX>这种形式,这里XX标签名是这个文件的文件名,别记错了,这里name就是在我们在XML文件中使用自定义类的属性名字)

(特别注意,在eclipse中至少有两个地方是可以得到手机屏幕的截图,一个是devices栏里面的screen capture照相功能,一个是hierarchy view工具,其中hierarchy viewer是专门用来调试控件的工具,而不仅仅是得到屏幕的截图而已。)

(ClipboardManager是剪切板,可以实现复制粘贴功能,我们可以利用getSystemService(Context.CLIPBOARD_SERVICE)得到剪切板,同时注意,剪切板是唯一的,存放的东西,会在下一次进行存放中被销毁。)

(ClassLoader是用来处理类加载的类,他控制着具体类的上下文。类似于Class类加载具体类,但是更为有用。应该说,ClassLoader比Class更加高级,因为Class实际上有一些方法是使用ClassLoader进行实现的,同时系统使用的也是ClassLoader,但是实际使用中视具体情况选择需要的进行使用。)

(Activity.setTitle(),或者通过requestWindowFeature(Window.FEATURE_CUSTOM_TITLE)getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,int)可以设置标题栏的格式。这是通过XML文件设置标题栏的。)

(MotionEvent存在getPressure()可以得到触屏的压力大小,通过这个功能我们可以实现更及拟物化的东西,例如画图。使用getSize()可以得到触屏的面积大小。使用getToolType()可以判定触屏的工具,一般需要是屏幕可以判别的,例如手指,触控笔等)

(Vibrator.vibrate()可以控制马达的节奏。)

(代码点或者说代码单元是指可用于编码字符集的数字。这个概念来自unicode,为每一个字符分配一个唯一的数字)

(特别注意,在工程中存放图片时,如果将图片存放在drawable文件夹下,有可能导致原本的图片与放进drawable文件夹之后得到的图片大小不一致。这里drawable的文件夹之所以有好几种命名形式,是因为每一种对应一种分辨率,例如drawable-mdpi就代表中等分辨率的图片存放的文件夹。在这里系统会自动为放入其中的图片进行一些分辨率的调整以适应drawable文件夹的分辨率,这就导致了图片大小的变化。)

(关联关系中,聚合(has-a)与组合(contains-a)的区别在于对象的销毁上,组合的对象生死与共,聚合的不一定。聚合的英文是aggregation,组合的是composition。)

(注意,Thread.interrupt()方法可以使所有会抛出InterruptedException的方法退出状态,去除Thread.inerrupt()所标志的标志并抛出InterruptedException异常。这些方法有:sleep(),wait(),join()以及CountDownLatch.await(),Semaphore.acquire()方法等)

在编程时关键在于简洁的记忆,需要记的多了反而容易记混,记错,记不住,因此编程的关键在于简洁。能做到简洁的就是总结平时的通用的技巧,如类与方法,逻辑,设计模式等通用的技术这样在编程时就只是需要关心新知识的各步骤了,这样简化了编程,也就简洁易记了。

在开发中总结的一点小技巧相关推荐

  1. VS开发中的代码编写小技巧——避免重复代码编写的几种方法

    原文:VS开发中的代码编写小技巧--避免重复代码编写的几种方法 上一篇文章中程序员的幸福生活--有你的日子,每天都是情人节,收到了大家的很多好评.鼓励和祝福,非常感动,真诚的谢谢大家.也希望每个朋友都 ...

  2. 前端开发中的一些js小技巧

    1.获取某个月的天数 1 function getDate (year, month) { 2 return new Date(year, month + 1, 0).getDate(); 3 } 2 ...

  3. java 新窗口跳转页面_Java web开发中页面跳转小技巧——跳转后新页面在新窗口打开...

    最近学习Java web,在学习过程中想实现一个需求,就是在jsp页面跳转的时候,希望跳转后的新页面在新窗口中打开, 而不是覆盖原来的页面,这个需求使我困惑了好长时间,后来通过大海捞针似的在网上寻找方 ...

  4. 工作中这些实用的小技巧,90%的程序员不知道

    工作中这些实用的小技巧,90%的程序员不知道 Linux 有些Linux命令我们是经常用的,但是这些命令有的特别长(如进入层级特别深的项目部署目录),这时就可以为这些命令定义一个别名 系统级别定义的别 ...

  5. php gridview,PHP编程:yii2-GridView在开发中常用的功能及技巧总结

    <PHP编程:yii2-GridView在开发中常用的功能及技巧总结>要点: 本文介绍了PHP编程:yii2-GridView在开发中常用的功能及技巧总结,希望对您有用.如果有疑问,可以联 ...

  6. Fiddler使用过程中容易忽略的小技巧

    Fiddler使用过程中容易忽略的小技巧 fiddler的基本使用,在之前的一篇博文中有详细介绍,可参见Fiddler抓包工具使用详解,今天来分享几个容易忽略的小技巧. 1.ios机装了证书,依然抓不 ...

  7. python开发效率怎样提高_python 提高开发效率的5个小技巧

    很多时候学习是一种难者不会,会者不难的事情. 下面的5个python技巧是性价比极高的知识点,一学就会,不难但是相当管用. 使用交互模式 使用python -i xxxx.py可以直接进入python ...

  8. rust熔炉怎么带走_Rust游戏中12个实用小技巧,包含无伤下坠、直梯爬楼

    Rust是一款第一人称生存网络游戏,有点像野外求生,但这款游戏内容则更加丰富.刺激.血腥. 在这款游戏中玩家的第一任务就是活下来,而想要活下来你将要接受饥饿.干渴.寒冷等.游戏中玩家需要建造自己的庇护 ...

  9. 直接在PDF文件中改变字体的小技巧

    2019独角兽企业重金招聘Python工程师标准>>> PDF文件大家接触的还是蛮多的,今天要给大家介绍一下直接在PDF文件中改变字体的小技巧,想来应该有蛮多小伙伴需要的. 具体操作 ...

最新文章

  1. openStack镜像制作
  2. Promise用法总结
  3. 大学生影视主题网页制作 银翼杀手2049电影网页设计模板 学生静态网页作业成品 dreamweaver电影HTML网站制作
  4. 推荐一款自动化代码变量命名在线工具
  5. megacli组建raid
  6. SAAS多租户实现方案_springboot 实现多租户_基于共享数据库_共享schema_共享数据表_基于baomidou_mybatis_plus---springcloud工作笔记158
  7. extjs 如何将局部的变量变为全局变量
  8. 洛谷P1962 斐波那契数列
  9. pip “Cannot uninstall ‘pip包‘. It is a distutils installed project...“ 解决方法
  10. 线程7种状态的相互转换
  11. IntelliJ IDEA 配置svn及使用
  12. 关于计算机应用基础论文,关于计算机应用基础论文
  13. 计算机视觉硕士课程南京大学,南京大学计算机系研究生课程文库
  14. AxureRP8.1(注册码)破解汉化教程
  15. word页面顺序倒过来_word怎么把顺序颠倒
  16. select 设置不可用,提交表单时能传值
  17. SAP中常用到的会计知识
  18. Kuma是什么? Kuma1.0 GA 发布了包含70+新特性和改进
  19. xmos-XU208-128-QF48芯片简介
  20. java基本数据类型长度

热门文章

  1. 基础博弈论(NIm,威佐夫,巴什游戏)
  2. 分享如何在 PingCode 这类专业的看板软件中管理敏捷Kanban 项目
  3. 新团队成员之间破冰训练
  4. 当前主流的python 微服务框架有哪些
  5. Centos安装janus
  6. WEB开发(7) Hibernate篇(上)
  7. windows清理_Windows清理C盘的常用方法
  8. [2016 版] 常见操作性能对比
  9. c语言函数指针 的定义方法,C语言 函数指针一(函数指针的定义)
  10. python中从键盘输入五个单词输出以元音字母开头的单词_Python程序设计入门——第五周作业...