getCacheDir() : 返回一个File,代表了我们app的internal缓存目录。请确保这个目录下的文件能够在一旦不再需要的时候马上被删除,并对其大小进行合理限制,例如1MB 。系统的内部存储空间不够时,会自行选择删除缓存文件。
如果需要缓存一些文件,可以使用createTempFile()。
无论是使用 getExternalStoragePublicDirectory() 来存储可以共享的文件,还是使用 getExternalFilesDir() 来储存那些对于我们的app来说是私有的文件,有一点很重要,那就是要使用那些类似DIRECTORY_PICTURES 的API的常量。那些目录类型参数可以确保那些文件被系统正确的对待。例如,那些以DIRECTORY_RINGTONES 类型保存的文件就会被系统的media scanner认为是ringtone而不是音乐。
– http://hukai.me/android-training-course-in-chinese/basics/data-storage/files.html
如果事先知道想要保存的文件大小,可以通过执行getFreeSpace() or getTotalSpace() 来判断是否有足够的空间来保存文件,从而避免发生IOException。那些方法提供了当前可用的空间还有存储系统的总容量。
然而,系统并不能保证可以写入通过getFreeSpace()查询到的容量文件, 如果查询的剩余容量比我们的文件大小多几MB,或者说文件系统使用率还不足90%,这样则可以继续进行写的操作,否则最好不要写进去。
Note:并没有强制要求在写文件之前去检查剩余容量。我们可以尝试先做写的动作,然后通过捕获 IOException 。这种做法仅适合于事先并不知道想要写的文件的确切大小。例如,如果在把PNG图片转换成JPEG之前,我们并不知道最终生成的图片大小是多少。
在不需要使用某些文件的时候应删除它。删除文件最直接的方法是直接执行文件的delete()方法。
myFile.delete();
如果文件是保存在internal storage,我们可以通过Context来访问并通过执行deleteFile()进行删除
myContext.deleteFile(fileName);
Note: 当用户卸载我们的app时,android系统会删除以下文件:
所有保存到internal storage的文件。
所有使用getExternalFilesDir()方式保存在external storage的文件。
然而,通常来说,我们应该手动删除所有通过 getCacheDir() 方式创建的缓存文件,以及那些不会再用到的文件。
SQL Injection:(随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码时没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入)
至于另外一些需要extra数据的implicit intent,我们可以使用 putExtra() 方法来添加那些数据。 默认的,系统会根据Uri数据类型来决定需要哪些合适的MIME type。如果我们没有在intent中包含一个Uri, 则通常需要使用 setType() 方法来指定intent附带的数据类型。设置MIME type 是为了指定应该接受这个intent的activity。
Note: 请尽可能的将Intent定义的更加确切。例如,如果想要使用ACTION_VIEW 的intent来显示一张图片,则还应该指定 MIME type 为image/*.这样能够阻止其他能够 “查看” 其他数据类型的app(比如一个地图app) 被这个intent叫起。
尽管Android系统会确保每一个确定的intent会被系统内置的app(such as the Phone, Email, or Calendar app)之一接收,但是我们还是应该在触发一个intent之前做验证是否有App接受这个intent的步骤。
Caution: 如果触发了一个intent,而且没有任何一个app会去接收这个intent,则app会crash。
为了验证是否有合适的activity会响应这个intent,需要执行queryIntentActivities() 来获取到能够接收这个intent的所有activity的list。若返回的List非空,那么我们才可以安全的使用这个intent。例如:
PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
若activity中的intent filter满足以下intent对象的标准,系统就能够把特定的intent发送给activity:
Action:一个想要执行的动作的名称。通常是系统已经定义好的值,如ACTION_SEND或ACTION_VIEW。 在intent filter中通过指定它的值,值的类型必须为字符串,而不是API中的常量(看下面的例子)
Data:Intent附带数据的描述。在intent filter中通过指定它的值,可以使用一个或者多个属性,我们可以只定义MIME type或者是只指定URI prefix,也可以只定义一个URI scheme,或者是他们综合使用。
Category:提供一个附加的方法来标识这个activity能够handle的intent。通常与用户的手势或者是启动位置有关。系统有支持几种不同的categories,但是大多数都很少用到。而且,所有的implicit intents都默认是 CATEGORY_DEFAULT 类型的。在intent filter中用指定它的值。
Note:为了接受implicit intents, 必须在我们的intent filter中包含 CATEGORY_DEFAULT 的category。startActivity()和startActivityForResult()方法将所有intent视为声明了CATEGORY_DEFAULT category。如果没有在的intent filter中声明CATEGORY_DEFAULT,activity将无法对implicit intent做出响应。
如果只是纯粹想要返回一个int来表示某些返回的result数据之一,则可以设置result code为任何大于0的数值。如果我们返回的result只是一个int,那么连intent都可以不需要返回了,可以调用setResult()然后只传递result code如下:
setResult(RESULT_COLOR_RED);
finish();
Note:我们没有必要在意自己的activity是被用startActivity() 还是 startActivityForResult()方法所叫起的。系统会自动去判断该如何传递result。在不需要的result的case下,result会被自动忽略。
接收的程序需要有访问URI资源的权限。下面有一些方法来处理这个问题:
将数据存储在ContentProvider中,确保其他程序有访问provider的权限。较好的提供访问权限的方法是使用 per-URI permissions,其对接收程序而言是只是暂时拥有该许可权限。类似于这样创建ContentProvider的一种简单的方法是使用FileProvider helper类。
使用MediaStore系统。MediaStore系统主要用于音视频及图片的MIME类型。但在Android3.0之后,其也可以用于存储非多媒体类型。
要插入每一个页面的子视图,你需要把这个layout与PagerAdapter挂钩。有两种adapter(适配器)你可以用:
FragmentPagerAdapter
在同级屏幕(sibling screen)只有少量的几个固定页面时,使用这个最好。
FragmentStatePagerAdapter
当根据对象集的数量来划分页面,即一开始页面的数量未确定时,使用这个最好。当用户切换到其他页面时,fragment会被销毁来降低内存消耗。
为了让Android Developer Tools能够识别你的view,你必须至少提供一个constructor,它包含一个Contenx与一个AttributeSet对象作为参数。这个constructor允许layout editor创建并编辑你的view的实例。
styleable实例的名字,通常与自定义的view名字一致。尽管这并没有严格规定要遵守这个convention,但是许多流行的代码编辑器都依靠这个命名规则来提供statement completion。
为了避免输入长串的namespace名字,示例上面使用了xmlns指令,这个指令可以指派custom作为http://schemas.android.com/apk/res/com.example.customviewsnamespace的别名。
请注意,如果你的view是一个inner class,你必须指定这个view的outer class。同样的,如果PieChart有一个inner class叫做PieView。为了使用这个类中自设的属性,你应该使用com.example.customviews.charting.PieChart$PieView.
TypedArray对象是一个共享资源,必须被在使用后进行回收。
Attributes是一个强大的控制view的行为与外观的方法,但是他们仅仅能够在view被初始化的时候被读取到。为了提供一个动态的行为,需要暴露出一些合适的getter 与setter方法。
请注意,在setShowText方法里面有调用invalidate()) and requestLayout()). 这两个调用是确保稳定运行的关键。当view的某些内容发生变化的时候,需要调用invalidate来通知系统对这个view进行redraw,当某些元素变化会引起组件大小变化时,需要调用requestLayout方法。调用时若忘了这两个方法,将会导致hard-to-find bugs。
注意标签并没有包含任何intent filter。因为发送任务给IntentService的Activity需要使用显式Intent,所以不需要filter。这也意味着只有在同一个app或者其他使用同一个UserID的组件才能够访问到这个Service。
避免频繁调用 findViewById() 的方法之一,就是使用 View Holder(视图占位符)设计模式。
Handler和AsyncTask:这俩类都是用来实现异步的,其中AsyncTask的集成度较高,使用简单,Handler则需要手动写Runnable或者Thread的代码;另外,由于AsyncTask内部实现了一个非常简单的线程池,实际上是只适用于轻量级的异步操作的,一般不应该用于网络操作。
ProGuard会对我们的代码进行检索,删除一些无用的代码,并且会对类、字段、方法等进行重命名,重命名之后的类、字段和方法名都会比原来简短很多,这样的话也就对内存的占用变得更少了。”
导致内存泄漏最主要的原因就是某些长存对象持有了一些其它应该被回收的对象的引用,导致垃圾回收器无法去回收掉这些对象,那也就出现内存泄漏了。比如说像Activity这样的系统组件,它又会包含很多的控件甚至是图片,如果它无法被垃圾回收器回收掉的话,那就算是比较严重的内存泄漏情况了。
我们还可以覆写titlebar中的任何一个layout属性,如layout_gravity、layout_margin等,而非layout属性则无法在标签当中进行覆写。另外需要注意的是,如果我们想要在标签当中覆写layout属性,必须要将layout_width和layout_height这两个属性也进行覆写,否则覆写效果将不会生效。
注意这里我对ViewStub的实例进行了一个非空判断,这是因为ViewStub在XML中定义的id只在一开始有效,一旦ViewStub中指定的布局加载之后,这个id也就失败了,那么此时findViewById()得到的值也会是空。
策略模式用接口实现算法的扩展性。
模板方法模式用继承的方式实现方法的扩展性。
每一个Library和每一个App都是单独的Project。
根据Gradle的要求,每一个Project在其根目录下都需要有一个build.gradle。
build.gradle文件就是该Project的编译脚本,类似于Makefile。
如果选择的Minimum Required SDK为8,而Target SDK大于它的话,系统会自动在项目中导入Support v4包;
tools:context="activity name"这一句不会被打包进APK。
只是ADT的Layout Editor在你当前的Layout文件里面设置对应的渲染上下文,说明你当前的Layout所在的渲染上下文是activity name对应的那个activity,如果这个activity在manifest文件中设置了Theme,那么ADT的Layout Editor会根据这个Theme来渲染你当前的Layout。