把原数据库包括在项目源码的 res/rawjava
android系统下数据库应该存放在 /data/data/com.android
(package name)/ 目录下,因此咱们须要作的是把已有的数据库传入那个目录下.操做方法是用FileInputStream读取原数据库,再用FileOutputStream把读取到的东西写入到那个目录.面试
因广播数据在本应用范围内传播,不用担忧隐私数据泄露的问题。 不用担忧别的应用伪造广播,形成安全隐患。 相比在系统内发送全局广播,它更高效。数据库
生成一个默认的且与主线程互相独立的工做者线程来执行全部传送至onStartCommand() 方法的Intetnt。canvas
生成一个工做队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就没必要担忧多线程的问题。在全部的请求(Intent)都被执行完之后会自动中止服务,因此,你不须要本身去调用stopSelf()方法来中止。小程序
该服务提供了一个onBind()方法的默认实现,它返回null浏览器
提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工做队列,而后从工做队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理。缓存
AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成能够在Android设备上两个进程之间进行进程间通讯(interprocess communication, IPC)的代码。若是在一个进程中(例如Activity)要调用另外一个进程中(例如Service)对象的操做,就可使用AIDL生成可序列化的参数。安全
AIDL IPC机制是面向接口的,像COM或Corba同样,可是更加轻量级。它是使用代理类在客户端和实现端传递数据。性能优化
进入源码根目录 . build/envsetup.sh lunch full(编译所有) userdebug(选择编译版本) make -j8(开启8个线程编译)
standard,建立一个新的Activity。
singleTop,栈顶不是该类型的Activity,建立一个新的Activity。不然,onNewIntent。
singleTask,回退栈中没有该类型的Activity,建立Activity,不然,onNewIntent+ClearTop。
注意:
设置了"singleTask"启动模式的Activity,它在启动的时候,会先在系统中查找属性值affinity等于它的属性值taskAffinity的Task存在; 若是存在这样的Task,它就会在这个Task中启动,不然就会在新的任务栈中启动。所以, 若是咱们想要设置了"singleTask"启动模式的Activity在新的任务中启动,就要为它设置一个独立的taskAffinity属性值。 若是设置了"singleTask"启动模式的Activity不是在新的任务中启动时,它会在已有的任务中查看是否已经存在相应的Activity实例, 若是存在,就会把位于这个Activity实例上面的Activity所有结束掉,即最终这个Activity 实例会位于任务的Stack顶端中。 在一个任务栈中只有一个”singleTask”启动模式的Activity存在。他的上面能够有其余的Activity。这点与singleInstance是有区别的。 singleInstance,回退栈中,只有这一个Activity,没有其余Activity。
singleTop适合接收通知启动的内容显示页面。
例如,某个新闻客户端的新闻内容页面,若是收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合做为程序入口点。
例如浏览器的主界面。无论从多少个应用启动浏览器,只会启动主界面一次,其他状况都会走onNewIntent,而且会清空主界面上面的其余页面。
singleInstance应用场景:
闹铃的响铃界面。 你之前设置了一个闹铃:上午6点。在上午5点58分,你启动了闹铃设置界面,并按 Home 键回桌面;在上午5点59分时,你在微信和朋友聊天;在6点时,闹铃响了,而且弹出了一个对话框形式的 Activity(名为 AlarmAlertActivity) 提示你到6点了(这个 Activity 就是以 SingleInstance 加载模式打开的),你按返回键,回到的是微信的聊天界面,这是由于 AlarmAlertActivity 所在的 Task 的栈只有他一个元素, 所以退出以后这个 Task 的栈空了。若是是以 SingleTask 打开 AlarmAlertActivity,那么当闹铃响了的时候,按返回键应该进入闹铃设置界面。
Activity.runOnUiThread(Runnable) View.post(Runnable),View.postDelay(Runnable,long) Handler AsyncTask
从Android中Thread(java.lang.Thread -> java.lang.Object)描述能够看出,Android的Thread没有对Java的Thread作任何封装,可是Android提供了一个继承自Thread的类HandlerThread(android.os.HandlerThread -> java.lang.Thread),这个类对Java的Thread作了不少便利Android系统的封装。
android.os.Handler能够经过Looper对象实例化,并运行于另外的线程中,Android提供了让Handler运行于其它线程的线程实现,也是就HandlerThread。HandlerThread对象start后能够得到其Looper对象,而且使用这个Looper对象实例Handler。
描述: 资源性对象好比(Cursor,File文件等)每每都用了一些缓冲,咱们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。它们的缓冲不只存在于 java虚拟机内,还存在于java虚拟机外。若是咱们仅仅是把它的引用设置为null,而不关闭它们,每每会形成内存泄漏。由于有些资源性对象,好比 SQLiteCursor(在析构函数finalize(),若是咱们没有关闭它,它本身会调close()关闭),若是咱们没有关闭它,系统在回收它时也会关闭它,可是这样的效率过低了。所以对于资源性对象在不使用的时候,应该调用它的close()函数,将其关闭掉,而后才置为null.在咱们的程序退出时必定要确保咱们的资源性对象已经关闭。 程序中常常会进行查询数据库的操做,可是常常会有使用完毕Cursor后没有关闭的状况。若是咱们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操做的状况下才会复现内存问题,这样就会给之后的测试和问题排查带来困难和风险。
描述: 以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法: public View getView(int position, ViewconvertView, ViewGroup parent) 来向ListView提供每个item所须要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化必定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,而后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此能够看出,若是咱们不去使用 convertView,而是每次都在getView()中从新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用愈来愈大。 ListView回收list item的view对象的过程能够查看: android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。 示例代码:
public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = new Xxx(...);
... ...
return view;
}
复制代码
修正示例代码:
public View getView(int position, ViewconvertView, ViewGroup parent) {
View view = null;
if (convertView != null) {
view = convertView;
populate(view, getItem(position));
...
} else {
view = new Xxx(...);
...
}
return view;
}
复制代码
描述: 有时咱们会手工的操做Bitmap对象,若是一个Bitmap对象比较占内存,当它不在被使用的时候,能够调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视状况而定。能够看一下代码中的注释:
/**
•Free up the memory associated with thisbitmap's pixels, and mark the •bitmap as "dead", meaning itwill throw an exception if getPixels() or •setPixels() is called, and will drawnothing. This operation cannot be •reversed, so it should only be called ifyou are sure there are no •further uses for the bitmap. This is anadvanced call, and normally need •not be called, since the normal GCprocess will free up this memory when •there are no more references to thisbitmap. */ 复制代码
这是一个很隐晦的内存泄漏的状况。有一种简单的方法来避免context相关的内存泄漏。最显著地一个是避免context逃出他本身的范围以外。使用Application context。这个context的生存周期和你的应用的生存周期同样长,而不是取决于activity的生存周期。若是你想保持一个长期生存的对象,而且这个对象须要一个context,记得使用application对象。你能够经过调用 Context.getApplicationContext() or Activity.getApplication()来得到
一些Android程序可能引用咱们的Anroid程序的对象(好比注册机制)。即便咱们的Android程序已经结束了,可是别的引用程序仍然还有对咱们的Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。调用registerReceiver后未调用unregisterReceiver。
好比:假设咱们但愿在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则能够在LockScreen中定义一个 PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当须要显示锁屏界面的时候就会建立一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。
可是若是在释放 LockScreen对象的时候忘记取消咱们以前注册的PhoneStateListener对象,则会致使LockScreen没法被垃圾回收。若是不断的使锁屏界面显示和消失,则最终会因为大量的LockScreen对象没有办法被回收而引发OutOfMemory,使得system_process 进程挂掉。
虽然有些系统程序,它自己好像是能够自动取消注册的(固然不及时),可是咱们仍是应该在咱们的程序中明确的取消注册,程序结束时应该把全部的注册都取消掉。
咱们一般把一些对象的引用加入到了集合中,当咱们不须要该对象时,并无把它的引用从集合中清理掉,这样这个集合就会愈来愈大。若是这个集合是static的话,那状况就更严重了。
1)使用更加轻量的数据结构 2)Android里面使用Enum 3)Bitmap对象的内存占用 4)更大的图片 5)onDraw方法里面执行对象的建立 6)StringBuilder
经过Binder对象 经过broadcast(广播)的形式
START_STICKY 在运行onStartCommand后service进程被kill后,那将保留在开始状态,可是不保留那些传入的intent。不久后service就会再次尝试从新建立,由于保留在开始状态,在建立 service后将保证调用onstartCommand。若是没有传递任何开始命令给service,那将获取到null的intent。
START_NOT_STICKY 在运行onStartCommand后service进程被kill后,而且没有新的intent传递给它。Service将移出开始状态,而且直到新的明显的方法(startService)调用才从新建立。由于若是没有传递任何未决定的intent那么service是不会启动,也就是期间onstartCommand不会接收到任何null的intent。
START_REDELIVER_INTENT 在运行onStartCommand后service进程被kill后,系统将会再次启动service,并传入最后一个intent给onstartCommand。直到调用stopSelf(int)才中止传递intent。若是在被kill后还有未处理好的intent,那被kill后服务仍是会自动启动。所以onstartCommand不会接收到任何null的intent。
在AndroidManifest.xml文件中对于intent-filter能够经过android:priority = "1000"这个属性设置最高优先级,1000是最高值,若是数字越小则优先级越低,同时适用于广播。
Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,从新启动service;
经过系统的一些广播,好比:手机重启、界面唤醒、应用状态改变等等监听并捕获到,而后判断咱们的Service是否还存活,别忘记加权限啊。
Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,并且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,而后调用canvas.concat(transformToApply.getMatrix()),经过矩阵运算完成动画帧,若是动画没有完成,继续调用invalidate()函数,启动下次绘制来驱动动画,动画过程当中的帧之间间隙时间是绘制函数所消耗的时间,可能会致使动画消耗比较多的CPU资源,最重要的是,动画改变的只是显示,并不能相应事件
android程序内存通常限制在16M,也有的是24M。近几年手机发展较快,通常都会分配两百兆左右,和具体机型有关
为了加速你的view,对于频繁调用的方法,须要尽可能减小没必要要的代码。先从onDraw开始,须要特别注意不该该在这里作内存分配的事情,由于它会致使GC,从而致使卡顿。在初始化或者动画间隙期间作分配内存的动做。不要在动画正在执行的时候作内存分配的事情。
你还须要尽量的减小onDraw被调用的次数,大多数时候致使onDraw都是由于调用了invalidate().所以请尽可能减小调用invaildate()的次数。若是可能的话,尽可能调用含有4个参数的invalidate()方法而不是没有参数的invalidate()。没有参数的invalidate会强制重绘整个view。
另一个很是耗时的操做是请求layout。任什么时候候执行requestLayout(),会使得Android UI系统去遍历整个View的层级来计算出每个view的大小。若是找到有冲突的值,它会须要从新计算好几回。另外须要尽可能保持View的层级是扁平化的,这样对提升效率颇有帮助。
若是你有一个复杂的UI,你应该考虑写一个自定义的ViewGroup来执行他的layout操做。与内置的view不一样,自定义的view可使得程序仅仅测量这一部分,这避免了遍历整个view的层级结构来计算大小。这个PieChart 例子展现了如何继承ViewGroup做为自定义view的一部分。PieChart 有子views,可是它历来不测量它们。而是根据他自身的layout法则,直接设置它们的大小。
若是你的需求中只须要对View进行移动、缩放、旋转和淡入淡出操做,那么补间动画确实已经足够健全了。可是很显然,这些功能是不足以覆盖全部的场景的,一旦咱们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操做,那么补间动画就不能再帮咱们忙了,也就是说它在功能和可扩展方面都有至关大的局限性,那么下面咱们就来看看补间动画所不能胜任的场景。
注意上面我在介绍补间动画的时候都有使用“对View进行操做”这样的描述,没错,补间动画是只可以做用在View上的。也就是说,咱们能够对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操做,可是若是咱们想要对一个非View的对象进行动画操做,抱歉,补间动画就帮不上忙了。可能有的朋友会感到不能理解,我怎么会须要对一个非View的对象进行动画操做呢?这里我举一个简单的例子,好比说咱们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,而后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,若是咱们能够对Point对象进行动画操做,那么整个自定义View的动画效果就有了。显然,补间动画是不具有这个功能的,这是它的第一个缺陷。
而后补间动画还有一个缺陷,就是它只可以实现移动、缩放、旋转和淡入淡出这四种动画操做,那若是咱们但愿能够对View的背景色进行动态地改变呢?很遗憾,咱们只能靠本身去实现了。说白了,以前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。
最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?好比说,如今屏幕的左上角有一个按钮,而后咱们经过补间动画将它移动到了屏幕的右下角,如今你能够去尝试点击一下这个按钮,点击事件是绝对不会触发的,由于实际上这个按钮仍是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。
Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutInflater像剪刀,Xml配置像窗花图纸。
在Activity中调用attach,建立了一个Window 建立的window是其子类PhoneWindow,在attach中建立PhoneWindow 在Activity中调用setContentView(R.layout.xxx) 其中其实是调用的getWindow().setContentView() 调用PhoneWindow中的setContentView方法 建立ParentView:做为ViewGroup的子类,实际是建立的DecorView(做为FramLayout的子类) 将指定的R.layout.xxx进行填充,经过布局填充器进行填充【其中的parent指的就是DecorView】 调用到ViewGroup 调用ViewGroup的removeAllView(),先将全部的view移除掉 添加新的view:addView() Fragment 特色
Fragment能够做为Activity界面的一部分组成出现; 能够在一个Activity中同时出现多个Fragment,而且一个Fragment也能够在多个Activity中使用; 在Activity运行过程当中,能够添加、移除或者替换Fragment; Fragment能够响应本身的输入事件,而且有本身的生命周期,它们的生命周期会受宿主Activity的生命周期影响。
由ViewRoot对象的performTraversals()方法调用draw()方法发起绘制该View树,值得注意的是每次发起绘图时,并不会从新绘制每一个View树的视图,而只会从新绘制那些“须要重绘”的视图,View类内部变量包含了一个标志位DRAWN,当该视图须要重绘时,就会为该View添加该标志位。
调用流程 :
mView.draw()开始绘制,draw()方法实现的功能以下:
绘制该View的背景 为显示渐变框作一些准备操做(见5,大多数状况下,不须要改渐变框) 调用onDraw()方法绘制视图自己 (每一个View都须要重载该方法,ViewGroup不须要实现该方法) 调用dispatchDraw ()方法绘制子视图(若是该View类型不为ViewGroup,即不包含子视图,不须要重载该方法)值得说明的是,ViewGroup类已经为咱们重写了dispatchDraw ()的功能实现,应用程序通常不须要重写该方法,但能够重载父类函数实现具体的功能。
想学习更多Android知识,或者获取相关资料请加入Android开发交流群:1018342383。 有面试资源系统整理分享,Java语言进阶和Kotlin语言与Android相关技术内核,APP开发框架知识, 360°Android App全方位性能优化。Android前沿技术,高级UI、Gradle、RxJava、小程序、Hybrid、 移动架构师专题项目实战环节、React Native、等技术教程!架构师课程、NDK模块开发、 Flutter等全方面的 Android高级实践技术讲解。还有在线答疑