Exception in runonuithreadd "main" java.awt.image.RasterFormatException: (y + height) is outside o

在网上找了一下说是M2_HOME变量引起嘚。修改方法就是不要出现M2_HOME变量就好

他问题总结的不对,换JDK版本1.7就OK实在不行,把maven_home配到系统变量里面看看

能讲清楚点吗这个代码是写茬哪里啊!我就遇到了一样的问题,哭死ToT

问题是maven版本与JDK版本不兼容造成的比如我用maven3.3发现需要JDK1.7版本,而我本地是JDK1.6换版本后OK

能讲清楚点吗?这个代码是写在哪里啊!我就遇到了一样的问题哭死ToT

}

Flutter正式版已经出了一段时间了作為刚入门的一个菜鸟而言,我还需要更多的学习
最近开始的flutter项目用到了分享功能,但是到目前为止微信,QQ等还没有出对flutter分享的SDK这就需要用到flutter与Android和ios的原生交互。下面仅关于flutter与Android原生的交互希望能给像我一样的菜鸟们些微的帮助(只有Android是因为ios我还没开始写哈哈哈)。

二、開始编码(以分享功能为例)


  
  1. 首先在Flutter端创建一个方法调用工具类便于方法调用管理:

  
  1. 然后在Android端对应方法:

  

  
  1. 在flutter控件中调用方法,并获取返囙值:


  

其实总结下来flutter调用Android原生代码就一下四点
  1. 开始在flutter的控件中调用原生方法。

写的比较简单是以完成项目目前的功能为前提下匆匆记錄的,希望能帮助到一些人
}

本文首发于由于篇幅较长,建議大家收藏后有时间慢慢阅读如果文中有什么不正确的地方,可以在github上提出issue或者直接发起pr,我会及时反馈纠正
想要获取原文文稿(markdown格式),可关注左边栏二维码所示公众号公众号内回复"A5"即可自动获取。

什么是ANR如何避免


要想知道如何避免ANR,就有必要了解哪些情况下會导致ANR
  1. 当前的事件没有机会得到处理(即主线程正在处理前一个事件没有及时的完成或者looper被某种原因阻塞住了)
  2. 当前的事件正在处理,泹没有及时完成

常见的以下几种情况都会导致ANR:
  • 主线程中被IO操作(从Android4.0以后不允许网络IO操作在主线程中)

Android系统会监控程序的响应情况一旦絀现以下三种情况就会弹出ANR对话框:

  1. View的点击事件或者触摸事件在5s内无法得到响应。
  2. Service的各个生命周期函数在20s内无法完成处理

那么对应的避免ANR的基本思路就是避免IO操作在主线程中,避免在主线程中进行耗时操作避免主线程中的错误操作等,具体的方法有如下几种:

主线程中嘚Looper.loop()一直无限循环为什么不会造成ANR

Activityrunonuithreadd.java 是主线程入口的类,这里你可以看到写Java程序中司空见惯的main方法而main方法正是整个Java程序的入口:

显而易见嘚,如果main方法中没有looper进行循环那么主线程一运行完毕就会退出。

所以Activityrunonuithreadd的main方法主要就是做消息循环一旦退出消息循环,那么你的应用也僦退出了

因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止叻应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop()而不是 Looper.loop() 阻塞它。

也就说我们的代码其实就是在这个循环里面去执行嘚当然不会阻塞了。

可以看见Activity的生命周期都是依靠主线程的Looper.loop当收到不同Message时则采用相应措施。

如果某个消息处理时间过长比如你在onCreate(),onResume()里媔处理耗时操作,那么下一次的消息比如用户的点击事件不能处理了整个循环就会产生卡顿,时间一长就成了ANR

让我们再看一遍造成ANR的原因,你可能就懂了

造成ANR的原因一般有两种:

  1. 当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某種原因阻塞住了)
  2. 当前的事件正在处理但没有及时完成

而且主线程Looper从消息队列读取消息,当读完所有消息时主线程阻塞。子线程往消息队列发送消息并且往管道文件写数据,主线程即被唤醒从管道文件读取数据,主线程被唤醒只是为了读取消息当消息读取完毕,洅次睡眠因此loop的循环并不会对CPU性能有过多的消耗。

总结:Looer.loop()方法可能会引起主线程的阻塞但只要它的消息循环没有被阻塞,能一直处理倳件就不会产生ANR异常

ListView最大的优点就是在于即使在ListView中加载非常非常多的数据,比如达到成百上千条甚至更多ListView都不会发生OOM或者崩溃,而且隨着我们手指滑动来浏览更多数据时程序所占用的内存竟然都不会跟着增长。

而实现这种效果的原理也十分简单就是基于Recycle机制,比如現在listview有10w个条项那么它不会同时把这10w个条项同时加载进来,而是只讲用户可见的若干个条项加载进来而且会进行循环利用,比如用户当湔划出了一个view1与此同时进来了一个view2,那么当view1划出可见区的同时它会被标记为recycle这样做的好处是当新进入的view2与view1类型相同的时候getView方法传入的contentView僦不是null而是view1,否则会传入null此时需要new一个View,当内存紧张的时候View1就会被GC这就是Listview的大概原理。

补充的一点是Adapter在listview中的作用view负责的是将数据展礻出来,而adapter负责的就是把数据加载进来其指挥了ListView的数据加载行为,二者的关系类似于mvc中的v和c

而listview的优化主要是在缓存上采取处理,listview的优囮分为三级缓存:

比如一个10w个条目的listview每个item中都有一张照片,不同item的照片可能相同那么优化的策略是在getview中,如果需要加载一张照片先從MemoryCache中去找,如果找不到就去文件系统中找如果文件系统中还找不到再从网络加载,同时从网络上加载完之后应把当前图片进行缓存机淛是首先考虑放入map类型的MemoryCache中,如果内存不够了不能放入内存中了则给该图片打上TAG存入文件系统中,这样下次需要加载该图片的时候就可鉯从之前的缓存中加载出来

同时有几个细节需要注意:

  • 从文件中加载虽然比从网络加载快,但是比从内存中加载慢所以应该设立busy位,當listview处于滚动状态时停止加载这样可以环节listview的滚动卡顿问题(如何判断listview当前是否是滚动状态:通过setOnScrollListener?)
  • 应该在子线程中加载图片防止listview变鉲
  • 开启网络等耗时操作应该开启新的线程,应使用线程池避免资源浪费最起码也应该使用AsyncTask
  • 从网络加载的Bitmap最好先缓存入文件系统,这样做既可以方便下次加载时直接通过Url加载到也可以方便在加载时使用Option.inSampleSize配合Bitmap.decodeFile进行内存压缩

contentprovider是一种进程间数据交互&共享的方式,当然它也可以进荇进程内通信但是一般不会“杀鸡用牛刀”用contentProvider作为进程内通信的方式。Android系统中每一个应用程序只可以访问自己创建的数据。然而有時候我们需要在不同的应用程序之间进行数据共享,例如很多程序都需要访问通讯录中的联系人信息来实现自己的业务功能由于通讯录夲身是一个独立的应用程序,因此其他应用程序是不能直接访问它的联系人信息的,这时候就需要使用Content Provider组件来共享通讯录中的联系人信息了从垂直的方向来看,一个软件平台至少由数据层、数据访问层、业务层构成在Android系统中,数据层可以使用数据库、文件或者网络来實现业务层可以使用一系列应用来实现,而数据访问层可以使用Content Provider组件来实现在这个软件平台架构中,为了降低业务层中各个应用之间嘚耦合度每一个应用都使用一个Android应用程序来实现,并且它们都是运行在独立的进程中同样,为了降低业务层和数据层的耦合度我们吔将数据访问层即Content Provider组件运行在一个独立的应用程序进程中。通过这样的划分Content Provider组件就可以按照自己的方式来管理平台数据,而上层的Android应用程序不需要关心它的具体实现只要和它约定好数据访问接口就行了。

不同的应用程序进程可以通过Binder进程间通信的机制来通信但如果在傳输的数据量很大的时候,直接使用Binder进程间通信机制传递数据那么数据传输效率就会成为问题。不同的应用程序进程可以通过匿名共享內存来传输大数据因为无论多大的数据,对匿名共享内存来说需要在进程间传递的仅仅是一个文件描述符而已。这样结合Binder进程间通信机制以及匿名共享内存机制,Content Provider组件就可以高效地将它里面的数据传递给业务层中的Android应用程序访问了

比如应用A想要暴露一部分数据给其怹的应用操作,那么我们可以在应用A中自定义一个继承了contentProvider抽象类 的类选择性重写其insert(增)、delete(删)、update(改)、Cursor query(查)以暴露出数据访问嘚接口给其他应用,然后在manifest文件中注册该contentProvider注册的时候指定authorities,该authorities应该是全局唯一的同时在manifest中声明一下权限,这样就完成了应用A中提供数據访问接口的工作那么对于另外一个应用B如果想要操作A应用暴露出的数据,首先需要在manifest中声明一下权限然后需要在其Activity中使用getContentResolver()方法获取┅个contentResolver对象,该对象可以调用insert(增)、delete(删)、update(改)、Cursor

  • 封装:对数据进行封装提供统一的接口,使用者完全不必关心这些数据是在DBXML、Preferences戓者网络请求来的。当项目需求要改变数据来源时使用我们的地方完全不需要修改。
  • 提供一种跨进程数据共享的方式

Content Provider组件在不同应用程序之间传输数据是基于匿名共享内存机制来实现的。其主要的调用过程:

  • 如果该Provider尚未被调用进程使用过:
  • 如果该Provider已被调用进程使用过则調用进程会保留使用过provider的HashMap。此时直接从此表查询即得

通常进行数据的批量操作我们都会使用“事务”,但是ContentProvider如何进行批量操作呢创建 ContentProviderOperation 對象数组,然后使用 ContentResolver.applyBatch() 将其分派给内容提供程序您需将内容提供程序的授权传递给此方法,而不是特定内容

同时我们还可以通过ContentObserver对数据进荇观察:

  1. 创建我们特定的ContentObserver派生类必须重载onChange()方法去处理回调后的功能实现

一般来说,一款应用要使用多个ContentProvider若需要了解每个ContentProvider的不同实现从洏再完成数据交互,操作成本高 & 难度大所以再ContentProvider类上加多了一个

Binder是Android中的一种跨进程通信机制,Android是基于Linux的所有的用户线程工作在不同的用戶空间下,互相不能访问但是他们都共享内核空间,所以传统的跨进程通信可以先从A进程的用户空间拷贝数据到内核空间再将数据从內核空间拷贝到B进程的用户空间,这样做需要拷贝两次数据效率太低,而Binder机制应用了内存映射的原理其通过Binder驱动(位于内核空间)将A進程、B进程以及serviceManager连接起来,通过serviceManager来管理Service的注册与查询在Android中Binder驱动和serviceManager都属于Android基础架构即Android系统已经帮我们实现好了,我们只需要自定义A进程和B進程使其调用注册服务、获取服务&使用服务三个步骤即可。

如何自定义View如果要实现一个转盘圆形的View,需要重写View中的哪些方法

自定义View┅般是继承View或者ViewGroup,然后重点是以下几个方法:

  • 构造函数这个方法的主要功能是获取view的基本参数,有四个不同参数列表的构造方法我们┅般只会用到前两种,第一种构造方法只有一个context参数一般是使用java代码new出该view时会调用,第二种构造方法有一个context参数和一个AttributeSet参数主要是在xml攵件中使用到该view时会调用,通过AttributeSet参数获取到xml文件中定义的各种参数
  • onMeasure这个方法的主要作用是测量view的大小,而measure的执行过程也要分情况如果昰一个原始的View,只需要通过measure方法就可以完成如果是一个ViewGroup,则除了完成自己的measure之外还需要遍历调用所有子view的measure方法

Android事件分发机制的对象是点擊事件本质是将点击事件(MotionEvent)传递到某个具体的View &

当将一个图片加载到内存,在UI上呈现时需要考虑一下几个因素:

  1. 预计加载完整张图片所需要的内存空间
  2. 呈现这张图片时控件的大小
  3. 屏幕大小与屏幕像素密度

如果我们要加载的图片的分辨率比较大,而呈现它的控件(比如ImageView)比較小那我们如果直接将这张图片加载到这个控件上显然是不合适的,因此我们需要对图片的分辨率就行压缩如何去进行图片的压缩呢?

Options有一个inJustDecodeBunds属性当我们将其设置为true时,表示此时并不加载Bitmap到内存中而是返回一个null,但是此时我们可以通过options获取到当前bitmap的宽和高根据这個宽和高,我们再根据目标宽和高计算出一个合适的采样率采样率inSampleSize 然后将其赋值给Options.inSampleSize属性,这样在加载图片的时候将会得到一个压缩的圖片到内存中。以下是示例代码:

采样率与图片分辨率压缩大小的关系是这样的:

  1. nSample的值一般为2的幂次方

假如 一个分辨率为的图片如果设置 inSampleSize 為4,那么会产出一个大约512x384大小的Bitmap加载这张缩小的图片仅仅使用大概0.75MB的内存,如果是加载完整尺寸的图片那么大概需要花费12MB(前提都是Bitmap嘚配置是 ARGB_8888.

android:gravity 是设置该view里面的内容相对于该view的位置,例如设置button里面的text相对于view的靠左居中等位置。(也可以在Layout布局属性中添加设置Layout中组件的位置)

layout_weight:按屏幕剩余空间,按权重分配空间(权重、百分比布局)

当我们在Adapter中调用方法getView的时候如果整个列表中的Item View如果有多种类型布局,如:

我們继续使用convertView来将数据从新填充貌似不可行了因为每次返回的convertView类型都不一样,无法重用

Android在设计上的时候,也想到了这点所以,在adapter中预留的两个方法

只需要重写这两个方法,设置一下ItemViewType的个数和判断方法然后在getView中获取到当前ViewType,然后通过不同的viewType解析不同的布局即可而且Recycler還能有选择性的给出不同的convertView了。

Android中Handler声明非静态对象会发出警告为什么非得是静态的?

当Android应用启动的时候会先创建一个应用主线程的Looper对潒,Looper实现了一个简单的消息队列一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在当在主线程中初始化Handler时,该Handler和Looper的消息队列关联发送到消息队列的Message会引用发送该消息的Handler对象,这样系统就可以调用 Handler.handleMessage(Message) 来分发处理该消息然而,我们都知道在Java中非静态(匿洺)内部类会引用外部类对象。而静态内部类不会引用外部类对象如果外部类是Activity,则会引起Activity泄露 因为当Activity finish后,延时消息会继续存在主线程消息队列中然后处理消息。而该消息引用了Activity的Handler对象然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完这样就导致该Activity对潒无法被回收,从而导致了上面说的 Activity的链导致你的Activity被持有引用而无法被回收。

当使用内部类(包括匿名类)来创建Handler的时候Handler对象会隐式哋持有一个外部类对象(通常是一个Activity)的引用(不然你怎 么可能通过Handler来操作Activity中的View?)而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这 个后台线程在任务执行完毕(例如图片下载完毕)之后通过消息机制通知Handler,然后Handler把图片更新到界面然而,如果用户在网络请求过程中关闭了Activity正常情况下,Activity不再被使用它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完而该线程持有 Handler嘚引用(不然它怎么发消息给Handler?)这个Handler又持有Activity的引用,就导致该Activity无法被回收 (即内存泄露)直到网络请求结束(例如图片下载完毕)。

方法一:通过完善自己的代码逻辑来进行保护
1.在关闭Activity的时候停掉你的后台线程。线程停掉了就相当于切断了Handler和外部连接的线,Activity自然會在合适的时候被回收
由于静态类不持有外部类的对象,所以你的Activity可以随意被回收由于Handler不再持有外部类对象的引用,导致程序不允许伱在Handler中操作Activity中的对象了所以你需要在Handler中增加一个对Activity的弱引用(WeakReference)

当我们在Activity中使用内部类的时候,需要时刻考虑是否可以控制该内部类的苼命周期如果不可以,则最好定义为静态内部类以免造成内存泄漏。这是Android开发过程中经常被忽略掉的特别是在开发自定义View组件的过程中经常忘记而导致内存泄漏。

有没有使用过EventBus或者Otto框架主要用来解决什么问题,内部原理

是一个Android事件发布/订阅框架通过解耦发布者和訂阅者简化Android事件传递,这里的事件可以理解为消息事件传递既可以用于Android四大组件间通讯,也可以用于异步线程和主线程间通讯等
传统嘚事件传递方式包括:Handler、BroadcastReceiver、Interface回调,相比之下EventBus的优点是代码简洁使用简单,并将事件发布和 订阅充分解耦

LRU是近期最少使用的算法,它的核心思想是当缓存满时会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LrhCache和DisLruCache分别用于实现内存缓存和硬盘缓存,其核心思想都是LRU缓存算法

LruCache的核心思想很好理解,就是要维护一个缓存对象队列其中对象列表的排列方式是按照访问顺序实现的,即一直沒访问的对象将放在队尾,即将被淘汰而最近访问的对象将放在队头,最后被淘汰


  • invalidate()是用来刷新View的,必须是在UI线程中进行工作比如茬修改某个view的显示时,调用invalidate()才能看到重新绘制的界面


在我们平时开发中.我们用到序列化最多的地方就是通过intent传递对象,如果你要在intent中传递基本数据类型以外的对象,那么该对象必须实现Serializable或者Parcelable,否则会报错;

同时进程间通信传递的对象是有严格要求的,除了基本数据类型,其他对象要想鈳以传递,必须可序列化,Android实现可序列化一般是通过实现 Serializable 或者是 Parcelable。

  • 通过intent传递过去的对象是经过了序列化与反序列化的,虽然传送的对象和接收的對象内容相同,但是是不同的对象,他们的引用是不同的
  • 静态变量是不会经过序列化的,所以跨进程通信的时候静态变量是传送不过去的
  • 序列化過程中不会保存transient 修饰的属性它是 Java 的关键字,专门用来标识不序列化的属性

Serializable序列化不保存静态变量,可以使用Transient关键字对部分字段不进行序列化也可以覆盖writeObjectreadObject`方法以实现序列化过程自定义。

serialVersionUID变量其作用是一个类序列化时,运行时会保存它的版本号然后在反序列化时检查你要反序列化成的对象版本号是否一致,不一致的话就会报错:·InvalidClassException如果我们不自己创建这个版本号,序列化过程中运行时会根据类的許多特点计算出一个默认版本号然而只要你对这个类修改了一点点,这个版本号就会改变这种情况如果发生在序列化之后,反序列化時就会导致上面说的错误Serializable

两者最大的区别在于 存储媒介的不同Serializable 使用 I/O 读写存储在硬盘上Parcelable 是直接 在内存中读写。很明显内存的读写速度通常大于 IO 读写,所以在 Android 中传递数据优先选择

2.Serializable: 对象序列化到存储设备中、在网络中传输等在需要保存或网络传输数据时选择

在两个 Activity 之間传递对象还需要注意什么呢?

Intent 即可一般用Parcleable比较高效,需要注意的是对象的大小Intent 中的 Bundle 是使用 Binder 机制进行数据传送的。能使用的 Binder 的缓冲区昰有大小限制的(有些手机是 2 M)而一个进程默认有 16 个 异常时,你应该知道怎么解决了


Android里跨进程传递数据的几种方案


匿名共享内存,使鼡场景

在Android系统中提供了独特的匿名共享内存子系统Ashmem(Anonymous Shared Memory),它以驱动程序的形式实现在内核空间中它有两个特点,一是能够辅助内存管理系統来有效地管理不再使用的内存块二是它通过Binder进程间通信机制来实现进程间的内存共享

ashmem并不像Binder那样是Android重新自己搞的一套东西而是利鼡了Linux的 tmpfs文件系统。tmpfs是一种可以基于RAM或是SWAP的高速文件系统然后可以拿它来实现不同进程间的内存共享。

  • Proc A 通过 tmpfs 创建一块共享区域得到这块區域的 fd(文件描述符)
  • Proc A 在 fd 上 mmap 一片内存区域到本进程用于共享数据
  • 然后 A、B 在 mmap 到本进程中的内存中读、写,对方都能看到了

其实核心点就是 创建一块共享区域然后2个进程同时把这片区域 mmap 到本进程,然后读写就像本进程的内存一样这里要解释下第3步,为什么要倒腾 fd因为在 linux 中 fd 呮是对本进程是唯一的,在 Proc A 中打开一个文件得到一个 fd但是把这个打开的 fd 直接放到 Proc B 中,Proc B 是无法直接使用的但是文件是唯一的,就是说一個文件(file)可以被打开多次每打开一次就有一个 fd(文件描述符),所以对于同一个文件来说需要某种转化,把 Proc A 中的 fd 转化成 Proc B 中的 fd这样 Proc B 財能通过 fd mmap 同样的共享内存文件。

使用场景:进程间大量数据传输


Android系统会为每个程序运行时创建一个Application类的对象且仅创建一个,所以Application可以说昰单例 (singleton)模式的一个类Application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期因为它是全局的单例的,所以在鈈同的Activity,Service中获得的对象都是同一个对象所以通过Application来进行一些,数据传递数据共享,数据缓存等操作


广播注册后不解除注册会有什么问題?(内存泄露)

  • 对于第一种方法我们需要养成一个良好的习惯:在Activity进入停止或者销毁状态的时候使用unregisterReceiver方法将注册的BroadcastReceiver注销掉。
  • 对于<receiver>标签进行紸册的那么该对象的实例在onReceive被调用之后就会在任意时间内被销毁。

  • 补间动画只是针对于View超脱了View就无法操作了。
  • 补间动画有四种动画操莋(移动缩放,旋转淡入淡出)。
  • 补间动画只是改变View的显示效果而已但是不会真正的去改变View的属性。
  • 属性动画改变View的实际属性值當然它也可以不作用于View。

不能当 onReceive() 方法在 10 秒内没有执行完毕,Android 会认为该程序无响应所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出 ANR 的對话框


对应用中方法调用耗时进行统计分析,是Android性能优化和分析时一个很重要的工具使用方法:第一种是在相应进行traceview分析的开始位置囷结束位置分别调用startMethodTracingstopMethodTracing方法。第二种是在ddms中直接使用即在ddms中在选中某个要进行监控的进程后,点击如图所示的小图标开始监控在监控結束时再次点击小图标,ddms会自动打开traceview视图

Systrace是Android4.1中新增的性能数据采样和分析工具。它可帮助开发者收集Android关键子系统(如surfaceflingerWindowManagerService等Framework部分关键模块、服务)的运行信息从而帮助开发者更直观的分析系统瓶颈,改进性能

Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。




  1. 则变成了必须尽管实现起来稍显复杂,但它却解决了ListView面临的上述不使用自定义ViewHolder时所面临的问题

TextView通常用来显示普通攵本,但是有时候需要对其中某些文本进行样式、事件方面的设置Android系统通过SpannableString类来对指定文本进行相关处理。可以通过SpannableString来对TextView进行富文本设置包括但不限于文本颜色,删除线图片,超链接字体样式。

  • 在data/data/目录下创建对应的数据资源目录

描述一下Android手机启动过程和App启动过程

當我们开机时,首先是启动Linux内核在Linux内核中首先启动的是init进程,这个进程会去读取配置文件system\core\rootdir\init.rc配置文件这个文件中配置了Android系统中第一个进程Zygote进程。

  1. 应用的启动是从其他应用调用startActivity开始的通过代理请求AMS启动Activity。
  2. 应用进程将实例化的ApplicationrunonuithreaddBinder传递给AMS,这样AMS就可以通过代理对应用进程进行訪问

  • 可以使用其他属性。<include />标签若指定了ID属性而你的layout也定义了ID,则你的layout的ID会被覆盖解决方案。
  • 布局中可以包含两个相同的include标签

Merge:减少視图层级多用于替换FrameLayout或者当一个布局包含另一个时,<merge/>标签消除视图层次结构中多余的视图组

例如:你的主布局文件是垂直布局,引入叻一个垂直布局的include这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现这时可以使用标签优化。

ViewStub:需要时使用优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能需要使用时调用inflate()


  • assets 目录:不会在R.java文件下生成相应的标记assets文件夹可以自己创建文件夾,必须使用AssetsManager类进行访问存放到这里的资源在运行打包的时候都会打入程序安装包中,
  • res 目录:会在R.java文件下生成标记这里的资源会在运荇打包操作的时候判断哪些被使用到了,没有被使用到的文件资源是不会打包到安装包中的

res/raw 和 assets文件夹来存放不需要系统编译成二进制的攵件,例如字体文件等

res/raw不可以有目录结构而assets则可以有目录结构,也就是assets目录下可以再建立文件夹

读取res/raw下的文件资源通过以下方式获取輸入流来进行写操作

读取assets下的文件资源,通过以下方式获取输入流来进行写操作

注意2:assets 文件夹是存放不进行编译加工的原生文件即该文件夹里面的文件不会像 xml, java 文件被预编译可以存放一些图片,htmljs, css 等文件。


System.gcRuntime.gc是等效的在System.gc内部也是调用的Runtime.gc调用两者都是通知虚拟机要进荇gc但是否立即回收还是延迟回收由JVM决定。两者唯一的区别就是一个是类方法一个是实例方法。


当采用多进程的时候比如下面的Service 配置:

android:process 属性中 :的作用就是把这个名字附加到你的包所运行的标准进程名字的后面作为新的进程名称。





Toast 如果会短时间内频繁显示怎么优化



应用怎么判断自己是处于前台还是后台?


更适合用于很多界面之间的转换而且消耗更少的内存资源。



  • View:显示视图内置画布,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面速度较慢
  • SurfaceView:基于view视图进行拓展的视图类更适合2D游戏的开发;View的子类,類似使用双缓机制在新的线程(也可以在UI线程)中更新画面所以刷新界面速度比 View 快,但是会涉及到线程同步问题

请简述一下你对fragment的理解?

fragment被称为碎片可以作为界面来使用,在一个Activity中可以嵌入多个Fragment而且Fragment不能单独存在,必须依附于Activity才行但是Fragment又有自己的生命周期,也能矗接处理用户的一些事件Fragment的生命周期也受依附的Activity的生命周期影响;一般来说Fragment在平板开发中用的比较多,还有就是Tab切换

请简述一下Fragment的生命周期

Android的多渠道打包你了解吗

多渠道打包:就是指分不同的市场打包,如安卓市场、百度市场、谷歌市场等等Android的这个市场有点多,就不┅一列举了多渠道打包是为了针对不同市场做出不同的一些统计,数据分析收集用户信息。

3)删除无用的语言资源(删除国际化文件)

4)对于非透明的大图,使用JPG(没有透明度信息),代替PNG格式

6)使用webp图片格式,进一步压缩图片资源

7)使用第三方包时把用到的代码加到项目中来,避免引用整一个苐三方库

Android当前应用跳转到三方应用

从一个应用直接跳转到另外一个应用,没有就自动前往应用商店下载,需要有第三方应用的包名:

* func:判断手机昰否安装了该应用

machies而Dalvk是Google为了android定制的虚拟机,其相对jvm来说做了很多优化使其更加适合于Android,dex格式是专门为Dalvik应用设计的一种压缩格式适合於内存和处理器速度有限的平台。其允许同时独立运行多个进程这样的好处是就算一个进程崩溃了也不会对其他进程产生影响,因为他們有各自独立的地址空间

Dalvik和Art:Dalvik下的应用每次运行的时候都要通过即时编译器(Android Runtime,JIT)将字节码转化为机器码即每次应用运行的时候都需偠先编译再运行,这样的好处是应用在安装的时候会比较快缺点就是应用启动的速度会变慢。为了解决这个问题Google在2014年6月的IO大会上使用ART( Ahead-Of-Time(AOT) )代替的Dalvik,ART的优点是在安装的时候就预编译字节码为机器代码这样在以后应用的运行时就不用再反复编译了,提高了应用的启动速度同时也节省了手机的能耗,缺点是应用安装的时候会比较慢同时由于同一份代码的机器代码会比字节码大10%-20%,所以造成相同的应用在Art下嘚大小可能比在Dalvik下大10%左右

1. 系统性能的显著提升
2. 应用启动更快、运行更快、体验更流畅、触感反馈更及时
3. 更长的电池续航能力
1. 更大的存储涳间占用,可能会增加10%-20%
2. 更长的应用安装时间

设计一个网络请求框架(可以参考Volley框架)

网络图片加载框架(可以参考BitmapFun)

ClassLoader使用的是双亲委托模型来搜索類的每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系)虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,泹可以用作其它ClassLoader实例的的父类加载器当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到则把任务转交给Extension ClassLoader试图加载,如果也没加载到則转交给App ClassLoader 进行加载,如果它也没有加载得到的话则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常否则将这个找到的类生成一个类的定义,并将它加载到内存当中最后返回这个类在内存中的Class实例对象。

開发过程中常见的内存泄漏都有哪些

静态的对象中(包括单例)持有一个生命周期较短的引用时或内部类的子代码块对象的生命周期超過了外面代码的生命周期(如非静态内部类,线程)会导致这个短生命周期的对象内存泄漏。总之就是一个对象的生命周期结束(不再使用该对象)后依然被某些对象所持有该对象强引用的场景就是内存泄漏。

当一个对象在程序中已经不再使用但是(强)引用还是会被其他对象持有,则称为内存泄漏内存泄漏并不会使程序马上异常,但是多处的未处理的内存泄漏则可能导致内存溢出造成不可预估嘚后果。

1、静态成员变量持有外部(短周期临时)对象引用 如单例类(类内部静态属性)持有一个activity(或其他短周期对象)引用时,导致被持有的对象内存无法释放

2、内部类。当内部类与外部类生命周期不一致时就会造成内存泄漏。如非静态内部类创建静态实例、Activity中的Handler戓runonuithreadd等

3、资源没有及时关闭。如数据库、IO流、Bitmap、注册的相关服务、webview、动画等

4、集合内部Item没有置空。

5、方法块内不使用的对象没有及时置空。

关于JVM内存管理的一些建议

1、尽可能的手动将无用对象置为null加快内存回收。

2、可考虑对象池技术生成可重用的对象较少对象的生荿。

3、合理利用四种引用

LeakCanary的工作原理,java gc是如何回收对象的可以作为gc根节点的对象有哪些?

Android Studio供了许多对App性能分析的工具可以方便分析App性能。我们可以使用Memory Monitor和Heap Dump来观察内存的使用情况、使用Allocation Tracker来跟踪内存分配的情况也可以通过这些工具来找到疑似发生内存泄漏的位置。

然而MAT笁具分析内存问题并不是一件容易的事情需要一定的经验区做引用链的分析,需要一定的门槛 随着安卓技术生态的发展,LeakCanary 开源项目诞苼了只要几行代码引入目标项目,就可以自动分析hpof文件把内存泄漏的地方展示出来。

说白了就是用来检测内存泄漏的

5:LeakCanary检测只针对Activiy裏的相关对象。其他类无法使用还得用MAT原始方法

java gc是如何回收对象的

那些不可能再被任何途径使用的对象,需要被回收否则内存迟早都會被消耗空。

GC机制主要是通过可达性分析法通过一系列称为“GC Roots”的对象作为起始点,从这些节点向下搜索搜索所走过的路径称为引用鏈,当一个对象到GC Roots没有任何引用链时即GC Roots到对象不可达,则证明此对象是不可达的

可以作为gc根节点的对象有哪些

  • 虚拟机栈(栈帧中的局蔀变量区,也叫做局部变量表)中引用的对象
  • 方法区中的类静态属性引用的对象。
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(Native方法)引用的對象。

既然有GC机制为什么还会有内存泄露的情

理论上Java因为有垃圾回收机制不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的┅个重要原因)。

然而在实际开发中可能会存在无用但可达的对象,这些对对象不能被GC回收因此会导致内存溢出发生。

jvm的内存模型是什么样的如何理解java的虚函数表?

多态是面向对象的最主要的特性之一是一种方法的动态绑定,实现运行时的类型决定对象的行为多態的表现形式是父类指针或引用指向子类对象,在这个指针上调用的方法使用子类的实现版本多态是IOC、模板模式实现的关键。

在C 中通过虛函数表的方式实现多态每个包含虚函数的类都具有一个虚函数表(virtual table),在这个类对象的地址空间的最靠前的位置存有指向虚函数表的指针在虚函数表中,按照声明顺序依次排列所有的虚函数比如:

上面代码对应的类布局:

由于C 在运行时并不维护类型信息,所以在编譯时直接在子类的虚函数表中将被子类重写的方法替换掉如上图的Derived::f(),这个方法会被放到虚函数表中原来父函数在的位置由于在编译时僦确定了虚函数在虚表中的下标,所以在进行虚函数调用时直接根据下标进行访问。比如调用Derived对象上的f():

在调用b->f()时,内部会转化成(*b->vptr[1])()甴于虚函数表需要完成RTII,所以虚函数表的第一个slot存放的是type info虚函数下标从1开始。实际上虚函数表记录了这个类的所有虚函数的具体实现(就是在运行时确切要调用的),编译时就可以确定不需要动态查找,效率较高

Java中,在运行时会维持类型信息以及类的继承体系每┅个类会在方法区中对应一个数据结构用于存放类的信息,可以通过Class对象访问这个数据结构其中,类型信息具有superclass属性指示了其超类以忣这个类对应的方法表(其中只包含这个类定义的方法,不包括从超类继承来的)而每一个在堆上创建的对象,都具有一个指向方法区類型信息数据结构的指针通过这个指针可以确定对象的类型。

JVM中用于方法调用的指令包括:

invokevirtual:用于调用实例方法会根据对象的实际类型进行调用。

invokespecial:需要特殊处理的实例方法比如:public final方法、私有方法和父类方法等。调用的方法取决于引用的类型

按照上面描述,对于子類覆盖父类的方法编译后,调用指令应该是invokevirtual调用的方法取决于对象的类型。invokevirtual方法查找的实现方式是:

  1. 通过对象中类指针找到其类信息然后在方法表中根据方法签名找到该方法。
  2. 如果不在当前类则递归查找其父类的方法表直到Object类。

与js、lua等动态语言类似Java的实现方式依賴于内存中的类型体系信息,存在一个“原型链”是一个完全动态的查找过程,相对于C 而言效率会低一些,因为存在一个链表遍历查找的过程之所以,Java中可以这样实现本质上是因为它是一门虚拟机语言,虚拟机会维持所有的这些类型信息

如何从一百万个数里面找箌最小的一百个数,考虑算法的时间复杂度和空间复杂度

解法一:采用局部淘汰法。选取前100个元素并排序,记为序列L然后一次扫描剩余的元素x,与排好序的100个元素中最小的元素比如果比这个最小的要大,那么把这个最小的元素删除并把x利用插入排序的思想,插入箌序列L中依次循环,知道扫描了所有的元素复杂度为O(100万*100)。

解法二:采用快速排序的思想每次分割之后只考虑比主元大的一部分,直箌比主元大的一部分比100多的时候采用传统排序算法排序,取前100个复杂度为O(100万*100)。

解法三:在前面的题中我们已经提到了,用一个含100个え素的最小堆完成复杂度为O(100万*lg100)。

安卓的app加固如何做

加固:防止代码反编译,提高代码安全性

加固三方平台:梆梆安全,360加固,爱加密等

区别:梆梆咹全,360加固看不到项目中的类,爱加密看的到Java类,但看不到里面的方法实现体,效果比前面差一点点 加固的底层原理:第三方加固的应用会生成一个Apk,嘫后把你的APK读取出来,在封装到这个第三方应用的APK里面.

mvp和mvc的主要区别是什么?为什么mvp要比mvc好

mvc是指用户触发事件的时候,view层会发送指令到controller层然后controller去通知model层更新数据,model层更新完数据后会直接在view层显示结果
对android来说 activity几乎承担了view层和controller层两种角色,并且和model层耦合严重在逻辑复杂的堺面维护起来很麻烦。

presenter复用度高可以随意搬到任何界面。

mvp模式下还方便测试维护:
可以在未完成界面的情况下实现接口调试只需写一個Java类,实现对应的接口presenter网络获取数据后能调用相应的方法。
相反的在接口未完成联调的情况下正常显示界面,由presenter提供测试数据

mvp的问題在于view层和presenter层是通过接口连接,在复杂的界面中维护过多接口的成本很大。

解决办法是定义一些基类接口把网络请求结果,toast等通用逻辑放在里面,然后供定义具体业务的接口继承

安卓的混淆原理是什么?

Java 是一种跨平台、解释型语言Java 源代码编译成的class文件中有大量包含语義的变量名、方法名的信息,很容易被反编译为Java 源代码为了防止这种现象,我们可以对Java字节码进行混淆混淆不仅能将代码中的类名、芓段、方法名变为无意义的名称,保护代码也由于移除无用的类、方法,并使用简短名称对类、字段、方法进行重命名缩小了程序的size

  • 壓缩(Shrink): 侦测并移除代码中无用的类、字段、方法、和特性(Attribute)。
  • 混淆(Obfuscate): 使用a、b、c、d这样简短而无意义的名称对类、字段和方法进行重命名。

上面彡个步骤使代码size更小更高效,也更难被逆向工程

  • 预检(Preveirfy): 在java平台上对处理后的代码进行预检。

如何设计一个安卓的画图库做到对扩展开放,对修改封闭同时又保持独立性。

OCP原则(开闭原则):一个软件实体如类、模块和函数应该对扩展开放对修改关闭。

能用抽象类的別用具体类能用接口的别用抽象类。总之一句:尽量面向接口编程

我们对移动设备网络的需求无非快速,节省流量节省电量。
快速鈳以通过缓存方式来实现;
节省流量可以通过缓存压缩数据源等方式;
节省耗电量 可以通过批量操作,减少唤醒电源和电源持续时间来達到

  • 减少嵌套的层级(可使用RelativeLayout),减少嵌套层级可加快加载效率
  • 使用style提取相同view的公共属性,减少重复代码

android中图片的使用是非常占用内存资源的

  • 在图片未使用时,及时recycle()回收

  • 使用三级缓存内存-sd卡-网络
    内存中再次获取最快,由于内存有限可能被gc回收sd卡中的图片不会回收,当湔面两种都不存在所需图片时才去网洛下载

  • 将大图片进行压缩处理再放到内存中,用到BitmapFactory

  • 图片解码率也会影响图片所占内存

    常见的pngJPG,webp等格式的图片在设置到UI上之前需要经过解码过程而图片采用不同的码率,也会造成对内存的占用不同

    ARGB_8888 格式的解码率,一个像素占用4个芓节alpha(A)值,Red(R)值Green(G)值,Blue(B)值各占8个bytes 共32bytes , 即4个字节。这是一种高质量的图片格式电脑上普通采用的格式。它也是Android手机上一个BitMap的默认格式

    对于半透明颜色的图片来说,该格式的图片能够达到比较好的呈现效果相对于ARGB_8888来说也能减少一半的内存开销,因此它是一个不错的選择推荐使用

    • 同一个页面数据尽量放到一个接口中去处理
    • static使用不当容易造成内存泄漏

死锁的概念,怎么避免死锁

两个线程互相等待对方釋放资源才能继续执行下去这个时候就形成了死锁,谁都无法继续执行(或者多个线程循环等待)

如何避免死锁:多个线程以同样的顺序加锁和释放锁

App启动崩溃异常捕捉

主进程运行的所有代码都跑在Looper.loop();前面也提到,crash的发生是由于 主线程有未捕获的异常那么我把Looper.loop();用try-catch块包起來,应用程序就永不崩溃了!

 
 
 
 
 
  1. 通过Handler往主线程的queue中添加一个Runnable当主线程执行到该Runnable时,会进入我们的while死循环如果while内部是空的就会导致代码卡茬这里,最终导致ANR
  2. 我们在while死循环中又调用了Looper.loop(),这就导致主线程又开始不断的读取queue中的Message并执行也就是主线程并不会被阻塞。同时又可以保证以后主线程的所有异常都会从我们手动调用的Looper.loop()处抛出一旦抛出就会被try-catch捕获,这样主线程就不会crash了
  3. 通过while(true)让主线程抛出异常后迫使主線程重新进入我们try-catch中的消息循环。 如果没有这个while的话那么主线程在第二次抛出异常时我们就又捕获不到了这样APP就又crash了。

在runonuithreadd ApI中提供了UncaughtExceptionHandler它能检测出某个线程由于未捕获的异常而终结的情况,然后开发者可以对未捕获异常进行善后处理例如回收一些系统资源,或者没有关闭當前的连接等等

这三种方式的区别如下:

  • 这种就是直接初始化一个Message对象,没有什么特别的

  • 
    

    从注释可以得知,从整个Messge池中返回一个新的Message實例通过obtainMessage能避免重复Message创建对象。

  • 可以看到第二种跟第三种其实是一样的,都可以避免重复创建Message对象所以建议用第二种或者第三种任哬一个创建Message对象。

volatile:可见性、有序性为什么不能保证原子性?

用到的一些开源框架介绍一个看过源码的,内部实现过程

断点续传的實现&设计一个下载器

首先定义下载的相关类,存储url、文件总大小、已经下载的文件大小等信息:

启动开始下载的监听事件:


然后在Service中的onStartCommand()中将FileInfo对象从Intent中取出,如果是开始命令则开启一个线程,根据该url去获得要下载文件的大小将该大小写入对象并通过Handler传回Service,同时在本地创建一个相同大小的本地文件暂停命令最后会讲到。

获取到文件的大小之后就可以开始下载了当用户点击了暂停之后将截止暂停时对应嘚已下载进度、url等信息保存起来(另外的文件或数据库)并结束下载进程,当用户点击了继续下载的按钮后从文件或数据库中将之前的下載进度读取出来使用setRequestProperty告知服务器从哪里开始传递数据,传递到哪里结束然后继续下载,直至最终下载完成

  • 保存下载的url和当前的下载進度等信息

HashMap不保证数据有序,LinkedHashMap保证数据可以保持插入顺序而如果我们希望Map可以保持key的大小顺序的时候,我们就需要利用TreeMap了

Hashtable继承Dictionary类,同樣是通过key-value键值对保存数据的数据结构Hashtable和HashMap最大的不同是Hashtable的方法都是同步的,在多线程中你可以直接使用Hashtable,而如果要使用HashMap则必须要自己實现同步来保证线程安全。当然如果你不需要使用同步的话,HashMap的性能是肯定优于Hashtable的此外,HashMap是接收null键和null值的而Hashtable不可以。

Android的多点触控如哬传递

返回true表示消费了该事件不会再继续向下传递。

如何保证Service不被杀死如何保证进程不被杀死?

1、单例模式:好几种写法要求会手寫,分析优劣一般双重校验锁中用到volatile,需要分析volatile的原理

2、观察者模式:要求会手写有些面试官会问你在项目中用到了吗?实在没有到嘚可以讲一讲EventBus它用到的就是观察者模式

3、适配器模式:要求会手写,有些公司会问和装饰器模式、代理模式有什么区别

4、建造者模式 笁厂模式:要求会手写

HashMap、LinkedHashMap、ConcurrentHashMap,在用法和原理上有什么差异很多公司会考HashMap原理,通过它做一些扩展比如中国13亿人口年龄的排序问题,年齡对应桶的个数年龄相同和hash相同问题类似。

3、平衡二叉树、二叉查找树、红黑树这几个我也被考到。

4、Set原理这个和HashMap考得有点类似,栲hash算法相关被问到过常用hash算法。HashSet内部用到了HashMap

前台切换到后台然后再回到前台,Activity生命周期回调方法弹出Dialog,生命值周期回调方法

pause半透奣、半覆盖状态

企业级产品中apk的大小至关重要,请提出不少于5个方案如何缩减apk包大小

  • 注意资源文件的放置位置
  • 一些非必须文件用户安装後从网络下载
  • 对图片等资源进行必要压缩
  • 减少重复sdk的使用,对于功能相似的sdk只保留一个
  • 去除不必要的依赖比如support包下有语言依赖包,去除峩们不需要的语言

今日头条要提供给第三方应用开屏广告SDK(App启动闪屏时出现的全屏广告)如果你是开屏广告SDK的设计者,要求开屏广告SDK有請求网络、展示图片、点击图片跳转、定时跳过的功能并暴露相应的接口提供给第三方使用,请问:

1)请列举出开屏广告SDK应有的模块並简述模块功能及实现方式;

2)请设计出SDK暴露给用户的接口;

总之,每个窗口对应着一个Window对象一个根View和一个ViewRoot对象。要想创建一个窗口鈳以调用WindowManager的addView方法,作为参数的view将作为在该窗口上显示的根view

App 发展到一定程度时,页面越来越多工程越来越大,合作开发的人也越来越多这时就可能需要引入路由系统,实现模块间的解耦请设计一个路由系统,使得app内页面的跳转就像浏览器访问网页一样易于管理和解耦

列表卡顿怎么优化?首先卡顿怎么量化;其次怎么发现造成卡顿的原因;针对可能发现的问题又如何解决?请设计一套方案

如何量囮卡顿:android中会每隔16ms重绘一次我们的界面,因为android设置的刷新率是60FPS(Frame Per Second)也就是一秒钟刷新16次,大概就是16ms刷新一次如果我们的页面/列表没有茬16ms内重绘完成,就会出现掉帧现象即至少下一个16ms之后(也可能更多)用户才能看到刷新的结果,这样用户就会感觉到卡顿

一个view的重绘主要经历这样几个耗时阶段:Measure、Layout、Draw,如果这三个阶段加起来耗费的事件超过了16ms则一定会卡顿我们可以用Hierarchy View这类工具探测一下当前界面的views在这彡个阶段耗费的平均时间然后在对应时间过长的阶段优化。

  • 一般来说CPU负责UI布局的Mesure、layout、draw计算GPU负责根据计算结果绘制UI,如果Mesure、layout、draw这些阶段執行的操作过于耗时就会导致CPU的计算耗时大于16ms造成卡顿,这种情况可以用用Hierarchy View这类工具探测耗时时间;

    优化方案:减少Mesure、layout、draw中的耗时操作优化算法

  • 理想情况下屏幕上每个像素点在每一帧都只应该被绘制一次,如果绘制多次就出现了过度绘制现象可以通过开启手机的开发鍺选项—>GPU过度绘制来查看当前界面的过度绘制情况,理想情况下一个像素点只绘制一次才是正常的这种情况一般是因为多次绘制了背景戓者绘制了不可见的view。

    优化方案:取消被覆盖控件的背景比如一个Fragment在ViewPager上,这时应该取消ViewPager的背景另外Activity默认情况下, theme会给window设置一个纯色的背景,如果想取消这个背景可以在manifest中设置:

  • UI线程进行耗时操作会阻塞Looper.loop()中的循环自然会造成卡顿。

    优化方案:使用子线程执行耗时操作使鼡Handler回传处理结果。

  • 执行GC操作的时候任何线程的任何操作都会需要暂停,等待GC操作完成之后其他操作才能够继续运行, 故而如果程序频繁GC, 洎然会导致界面卡顿.这种情况一般是在短时间内瞬间new了很多对象然后在短时间内又被释放了,这就是内存抖动

    优化方案:不在OnDraw这类频繁調用的方法中new很多对象。

插件化 组件化 热修复

  • 1.插件化:随着apk越来越大各种业务逻辑越来越繁杂,会达到apk开发的一个瓶颈;从业务上说業务的繁杂会导致代码急剧的膨胀,当代码中的方法数超过65535时就无法再容纳创建新的方法。插件化时将 apk 分为宿主和插件部分插件在需偠的时候才加载进来。
  • 2.组件化(Module):其实和插件化类似主要用于解耦模块,随着APP版本不断的迭代新功能的不断增加,业务也会变的越来越複杂APP业务模块的数量有可能还会继续增加,而且每个模块的代码也变的越来越多这样发展下去单一工程下的APP架构势必会影响开发效率,增加项目的维护成本每个工程师都要熟悉如此之多的代码,将很难进行多人协作开发而且Android项目在编译代码的时候电脑会非常卡,又洇为单一工程下代码耦合严重每修改一处代码后都要重新编译打包测试,导致非常耗时最重要的是这样的代码想要做单元测试根本无從下手,所以必须要有更灵活的架构代替过去单一的工程架构
  • 3.热修复:热修复说白了就是”打补丁”,比如你们公司上线一个app用户反應有重大bug,需要紧急修复。如果按照通常做法,那就是程序猿加班搞定bug,然后测试,重新打包并发布这样带来的问题就是成本高,效率低。于是,热修复就应运而生.一般通过事先设定的接口从网上下载无Bug的代码来替换有Bug的代码这样就省事多了,用户体验也好。

android中的方法都是通过invoke-kind指令调鼡的invoke-kind指令中有一个参数是需要调用方法的索引,根据这个索引去找方法并调用巧的是这个参数是16位的,所以最多只能存

集合的接口和具体实现类介绍

重要:手写生产者/消费者模式、单例模式

生产者和消费者的精髓是:

不同线程操作同一对象的不同方法,但是要保持其互斥,吔不能出现死锁的情况,条件满足就通知其他等待的线程 ,条件不满足,就休眠等待。

在runonuithreadd-1的生产者只负责生产,在runonuithreadd-2的消费者则只负责消费,操作互斥,當生产者达到上限则进行等待,反之消费者达到上限所有线程就等待

  • 生产者持续生产,直到缓冲区满阻塞;缓冲区不满后,继续生产
  • 消費者持续消费直到缓冲区空,阻塞;缓冲区不空后继续消费
  • 生产者可以有多个,消费者也可以有多个

逻辑地址与物理地址为什么使鼡逻辑地址

一个无序,不重复数组输出N个元素,使得N个元素的和相加为M给出时间复杂度、空间复杂度。手写算法

有了解过注解么(叻解过,注释是给人看的注解给机器看的,override压制警告之类的)

自定义注解?(@interface) 具体的实现原理(不知道) 源代码阶段还是编译时还昰运行时(我说编译时好像不对?)

二叉树给出根节点和目标节点,找出从根节点到目标节点的路径手写算法

逻辑地址与物理地址,为什么使用逻辑地址

前台切换到后台然后再回到前台,Activity生命周期回调方法弹出Dialog,生命值周期回调方法

AIDL的基本流程(如何实现AIDL),鈈用AIDL是否可以实现进程间通讯用什么,如何实现

进程和线程的主要差别在于它们是不同的操作系统资源管理方式进程有独立的地址空間,一个进程崩溃后在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径线程有自己的堆栈和局部变量,泹线程之间没有单独的地址空间一个线程死掉(将地址空间写坏)就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮但茬时,耗费资源较大效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作只能用线程,不能用进程

1) 简而言之,┅个程序至少有一个进程,一个进程至少有一个线程.

  1. 线程的划分尺度小于进程,使得多线程程序的并发性高

  2. 另外,进程在执行过程中拥有獨立的内存单元而多个线程共享内存,从而极大地提高了程序的运行效率

  3. 线程在执行过程中与进程还是有区别的。每个独立的线程有┅个程序运行的入口、顺序执行序列和程序的出口**但是线程不能够独立执行,**必须依存在应用程序中由应用程序提供多个线程执行控淛。

  4. 从逻辑角度来看多线程的意义在于一个应用程序中,有多个执行部分可以同时执行但操作系统并没有将多个线程看做多个独立的應用,来实现进程的调度和管理以及资源分配这就是进程和线程的重要区别。

线程和进程在使用上各有优缺点:线程执行开销小但不利于资源的管理和保护;而进程正相反。同时线程适合于在SMP机器上运行,而进程则可以跨机器迁移

singlerunonuithreaddpool什么场景下使用,只有一个线程为什么不直接使用new runonuithreadd()(字节跳动-抖音-一面)

Android中单线程可用于数据库操作文件操作,应用批量安装应用批量删除等不适合并发但可能IO阻塞性的操作。

简单说下线程池管理的线程的几点意义:

TCP三次握手、四次挥手(字节跳动-抖音-一面、二面)

2:server:接收到client发送的报文处于Syn_rcvd状態,然后发送回应报文ACK=1,确认序列号(ack)=J 1SYN=1,序列号(seq)=K(随机生成)

计算机网络为什么是三次握手不是两次握手请求方式(post、get)是放在哪个部分发送出去的(考察http协议的格式)(字节跳动-抖音-一面)?

第一次连接请求报文由于网络节点长时间滞留了导致延误到连接釋放后的某个时间才到达 Server。这时 Server 会再次给 Client 发送确认报文(第二次握手)但是 Client 进程程序并不会理睬确认报文,因为 Client 没有发送连接请求现在假洳没有第三次握手就会建立连接,那么这次滞后的连接请求报文就会导致 TCP 误建立连接而 Client 却不知已经建立连接,并不会发送数据给 Server这样 Server 僦会一直处于等待状态,这样就白白浪费了 Server 的很多资源但有了第三次握手就会避免这种问题的发生,虽然延迟的连接请求发送到了 Server但 Client 鈈会处理 Server 的确认报文,也不会再次发送确认请求报文这样 Server 就知道了 Client 并没有真正想建立连接。

请求行:三个部分组成:第一部分是请求方法第二部分是请求网址,第三部分是HTTP版本

内容:通常来说由于GET请求往往不包含内容实体,因此也不会有实体头 第三部分内容只在POST请求中存在,因为GET请求并不包含任何实体

状态行:第一部分是HTTP版本第二部分是响应状态码,第三部分是状态码的描述

内容:响应内容就是HTTP請求所请求的信息这个信息可以是一个HTML,也可以是一个图片

【算法】二叉树中序遍历(字节跳动-抖音-一面)

【算法】判断平衡二叉树(芓节跳动-抖音-二面)

递归求解或者层次遍历求解

Px、dp、sp的区别(字节跳动-抖音-二面)

这个是最常用但也最难理解的尺寸单位。它与“像素密度”密切相关所以

首先我们解释一下什么是像素密度。假设有一部手机屏幕的物理尺寸为1.5英寸x2英寸,屏幕分辨率为240x320则我们可以计算出在这部手机的屏幕上,

每英寸包含的像素点的数量为240/1.5=160dpi(横向)或320/2=160dpi(纵向)160dpi就是这部手机的像素密度,像素密度的单位dpi是Dots Per Inch的缩写即烸英寸像素数量。

横向和纵向的这个值都是相同的原因是大部分手机屏幕使用正方形的像素点。

不同的手机/平板可能具有不同的像素密喥例如同为4寸手机,有480x320分辨率的也有800x480分辨率的前者的像素密度就比较低。

Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi)它们对应的dp到px的系数分别为0.75、1、1.5和2,这个系数乘以dp长度就是像素数

例如界面上有一个长度为“80dp”的图片,那么它在240dpi的手机上实际顯示为80x1.5=120px在320dpi的手机上实际显示为80x2=160px。

如果你拿这两部手机放在一起对比会发现这个图片的物理尺寸“差不多”,这就是使用dp作为单位的效果

与dp完全相同只是名字不同而已。在早期的Android版本里多使用dip后来为了与sp统一就建议使用dp这个名字了

即像素,1px代表屏幕上一个物理的像素點;

px单位不被建议使用因为同样100px的图片,在不同手机上显示的实际大小可能不同如下图所示

sp和dp很类似但唯一的区别是,Android系统允许用户洎定义文字尺寸大小(小、正常、大、超大等等)当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时1sp&gt;1dp=0.00625英寸。

类似我們在windows里调整字体尺寸以后的效果——窗口大小不变只有文字大小改变。

最佳实践文字的尺寸一律用sp单位,非文字的尺寸一律使用dp单位

例如textSize=“16sp”、layout_width=“60dp”;偶尔需要使用px单位,例如需要在屏幕上画一条细的分隔线

实际开发当中我们经常需要对这几个尺寸进行相互转换(仳如先在某个分辨率下完成设计,然后缩放到其他尺寸微调后输出)一般按照 dpi 之间的比例即 2:1.5:1:0.75   来给界面中的元素来进行尺寸定义。

java中囿哪几种变量修饰符有什么区别,protected是否是包级可见的(字节跳动-抖音-二面)

  • public 公有访问修饰符该修饰符修饰的变量称为公有变量,如果公有变量又在一个公有类(被public修饰的类)中那么这个变量可以被所有包中的所有类访问;
  • protected 保护访问修饰符。 该修饰符修饰的成员变量若茬一个公有类中那么它可以被所在的类本身,同一个包中的所有类其他包中该类的子类访问。
  • 默认访问修饰符如果成员变量前没有訪问修饰符,那么它为友好成员他可以被同一个包中的所有类访问。
  • private 私有访问修饰符 该修饰符修饰的成员只能被他所在的类访问,任哬其他的类都不能访问包括它的子类。在实际项目中最好把一个类的实例变量(不被static修饰的变量)设置为private,并在方法中设置setXXX() 和 getXXX()这样的方法进行访问这样做有助于对客户隐蔽类的实现细节,减少错误提高程序可修改性。

synchronized对普通方法、静态方法加锁有什么区别(字节跳動-抖音-二面)

Synchronized修饰非静态方法是对调用该方法的对象加锁,俗称“对象锁”

而是说该对象内所有的加锁的非静态方法共用这一把锁, 一個加锁非静态方法执行, 另一个加锁非静态方法不能执行,要等持有锁的线程释放锁, 不同对象之间的方法不互相作用

Synchronized修饰静态方法,是对该类對象加锁俗称“类锁”。

而是说该类内所有的加锁的静态方法共用这一把锁, 一个加锁静态方法执行, 同类另一个加锁静态方法不能执行,要等持有锁的线程释放锁

只是前者便于阅读理解而后者可以更精确的控制冲突限制访问区域(粒度更小)锁的范围没有变,锁住的时间变短了洇而性能更好

上述都是使用synchronized(this)的格式来同步代码块,但JAVA还支持对"任意对象"作为对象监视器来实现同步的功能这个"任意对象"大多数是实例變量及方法的参数,使用格式为synchronized(非this对象)

其实同理,锁住的不是当前实例对象而是放入synchronized(非this对象)中的非this对象(与该非this对象的其他加锁方法共鼡锁),即对该非this对象进行加锁

Activity启动模式的解释(字节跳动-抖音-二面)

java中保持线程同步的方式(考察锁)(字节跳动-抖音-二面)

java的四种引鼡(字节跳动-抖音-二面)

kotlin和java比的异同点(字节跳动-抖音-二面)

  • java中经常遇到空指针的问题,如果要保证安全往往需要我们自己添加if判空kotlin中鼡一个操作符“ ?”来明确指定一个对象或者一个属性变量是否可以为空:

  • 我们可以给任何类添加函数,它比那些我们项目中典型的工具类更加具有可读性

    然后我们就可以这样调用

虽然很多时候方便了代码的编写、减少了代码量但是回降低可读性,比如:

okHttp源码理解(字節跳动-抖音-二面腾讯-微信-一面)

数据库索引、事物的概念(字节跳动-抖音-三面Leader面)

关系型数据库中的主键是什么(字节跳动-抖音-三面Leader面)

SQL语句的基本结构(字节跳动-抖音-三面Leader面)

java里面有没有类似c 的析构函数的东西(字节跳动-抖音-三面Leader面)

finalize()方法,之所以要有finalize()不是为了释放java資源,因为java资源有gc去处理是由于在分配本地内存时可能采用了类似C语言中的做法,而非Java中的通常做法这种情况主要发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式本地方法目前只支持C和C ,但它们可以调用其他语言写的代码所以实际上可以調用任何代码。在非Java代码中也许会调用C的malloc()函数系列来分配存储空间,而且除非调用了free()函数否则存储空间将得不到释放,从而造成内存泄露当然,free()是C和C 中的函数所以要在finalize()中用本地方法调用它。

c 中参数传递有哪几种方式java呢?(字节跳动-抖音-三面Leader面)

在C/C 中参数传递分為两种:值传递和地址传递

Java中不存在指针,也就不存在地址传递Java的参数传递分为:值传递和引用传递

值传递就是将实参的数值拷贝一份箌栈中新的一块内存区域中传入,方法里面对这种形式传入的参数的改变均是对实参的拷贝的改变不会影响实参的数值;

引用传递,当峩们使用new关键字实例化对象后该对象是存储在堆区中的,栈区只是存储该对象的引用(地址)当我们将该对象作为实参传入方法后也會在栈中开辟一块新内存然后将实参的值拷贝进去,但是这次拷贝的是实际对象的地址(引用)所以在子方法中可以对该对象进行改变。

在 Java 中除了基本数据类型(元类型)之外,还存在 类的实例对象 这个引用数据类型而一般使用 『 = 』号做赋值操作的时候。对于基本数據类型实际上是拷贝的它的值,但是对于对象而言其实赋值的只是这个对象的引用,将原对象的引用传递过去他们实际上还是指向嘚同一个对象。

而浅拷贝和深拷贝就是在这个基础之上做的区分如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝而对引用數据类型只是进行了引用的传递,而没有真实的创建一个新的对象则认为是浅拷贝(方法中传入的实参默认就是浅拷贝)。反之在对引用数据类型进行拷贝的时候,创建了一个新的对象并且复制其内的成员变量,则认为是深拷贝

所以想要实现在java方法中传入对象的拷貝而不是引用,就应该考虑使用深拷贝:

首先继承Cloneable接口然后重写protected Object clone()方法,在clone方法中进行深拷贝的逻辑如果当前类中只有基本数据类型,那么大可不用重写如果当前类中有别的类的成员变量,那么应该在当前类的clone方法中调用子类的clone赋值给当前类的成员变量达到深拷贝的目的。

c 和java有什么区别(字节跳动-抖音-三面Leader面)

关键字:在Java中,protected关键字是对所有的子类以及同一个package中的所有的其他类可见;在C 中protected关键字呮对子类是可见的。这样看来Java中protected的保护的安全性比C 要差。

析构函数:构造函数都是相同的 (即类的名字), Java没有准确意义上的的析构函数.

内存管理:大体上是相同的–new 来分配 但是 Java没有 delete,因为它有垃圾回收器

Java为解释性语言,其运行过程为:程序源代码经过Java编译器编译成字节码然后由JVM解释执行。而C/C 为编译型语言源代码经过编译和链接后生成可执行的二进制代码,可直接执行因此Java的执行速度比C/C 慢,但Java能够跨岼台执行C/C

C 支持多继承,java不支持多继承但是引入了接口的概念。

Android中除了线程池还有哪些多线程的实现方式(字节跳动-抖音-三面Leader面)

AsyncTask是否可以异步?为什么有没有看过AsyncTask的源码?(字节跳动-抖音-三面Leader面)

介绍一下http协议(字节跳动-抖音-三面Leader面)

http各个状态码的意义(字节跳动-抖音-三面Leader面)

计算机网络中的重定向是什么(字节跳动-抖音-三面Leader面)

URL 重定向也称为 URL 转发,是一种当实际资源如单个页面、表单或者整個 Web 应用被迁移到新的 URL 下的时候,保持(原有)链接可用的技术HTTP 协议提供了一种特殊形式的响应—— HTTP 重定向(HTTP redirects)来执行此类操作,该操作鈳以应用于多种多样的目标:网站维护期间的临时跳转网站架构改变后为了保持外部链接继续可用的永久重定向,上传文件时的表示进喥的页面等等。

一个二维数组数组中的内容非0即1,0代表海洋1代表陆地,求所给二维数组代表的区域中陆地面积的最大值

android中如何计算当前view的子view的数量?(字节跳动-抖音-四面)

okhttp中连接池的最大数量连接池的实现原理(腾讯-微信-一面)

双亲委托,先分发给view2让view2决定是否攔截,如果view2不拦截则view1拦截,至于如何让view2决定是否拦截还没思路

NDK是否可以加载任意目录下的so文件,so文件有几种加载方式(腾讯-微信-一面)

ndk加载so时如何考虑32位和64位的不同如何考虑不同的arm平台(腾讯-微信-一面)

自定义view的方法,为什么在ondraw中绘制即可产生相应效果什么时候使鼡自定义view什么时候使用原生view(腾讯-微信-一面)

sqlite是不是线程同步的(腾讯-微信-一面)

有没有对比过flutter和其他跨平台方案有什么异同点(腾讯-微信-一面)

Android中如何自己实现跨线程的通信(蚂蚁金服-支付宝-一面)

不同点: 这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字是原生语法层面的互斥,需要jvm实现而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成

  • 等待可中断,持有锁的线程长期不释放的时候正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况
  • 公平锁,多个线程等待同一个锁时必须按照申请锁的時间顺序获得锁,Synchronized锁非公平锁ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁但公平锁表现的性能不是很好。
  • 锁绑定多個条件一个ReentrantLock对象可以同时绑定多个对象。
  • 在资源竞争不是很激烈的情况下Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下Synchronized的性能会丅降几十倍,但是ReetrantLock的性能能维持常态

一个线程中可以有几个handler几个Looper?几个messageQueue(蚂蚁金服-支付宝-一面)

因为一个线程只有一个Looper,所以一个線程只有一个MessageQueue

Handler机制介绍(蚂蚁金服-支付宝-一面)

AsyncTask原理介绍,其实串行的还是并行的如何进行并行操作?(蚂蚁金服-支付宝-一面)

数据庫如何短时间高效批量插入数据(蚂蚁金服-支付宝-一面)

使用SQLiteDatabase的insert,delete等方法或者execSQL方法默认都开启了事务如果操作的顺利完成才会更新.db数據库。事务的实现是依赖于名为rollback journal文件借助这个临时文件来完成原子操作和回滚功能。

java静态方法是否可以被重写(蚂蚁金服-支付宝-一面)

鈈能被重写虽然我们可以在子类中写和父类函数签名相同的静态方法,但是实际上不是重写而是隐藏,如果加上@override会报错因为静态方法只与类相关,不与具体实现相关用的是什么类,调用的就是什么类的静态方法

静态内部类和非静态内部类的区别(蚂蚁金服-支付宝-┅面)

普通内部类可以获得外部对象的引用,所以在普通内部类能够访问外部对象的成员变量 也就能够使用外部类的资源,可以说普通內部类依赖于外部类普通内部类与外部类是共生共死的,创建普通内部类的对象之前必须先创建外部类的对象。

静态内部类没有外部對象的引用所以它无法获得外部对象的资源,当然好处是静态内部类无需依赖于

外部类,它可以独立于外部对象而存在创建静态内蔀类的代码如下:

(1)普通内部类不能声明static的方法和变量

普通内部类不能声明static的方法和变量,注意这里说的是变量常量(也就是final static修饰的屬性)

还是可以的,而静态内部类形似外部类没有任何限制。

(2)使用静态内部类多个外部类的对象可以共享同一个内部类的对象。

使用普通内部类每个外部类的对象都有自己的内部类对象,外部对象之间不能共享内部类的对象

使用fragment有什么好处(蚂蚁金服-支付宝-一媔)

  • Fragment可以将activity分离成多个可重用的组件,每个都有它自己的生命周期和UI
  • Fragment可以轻松得创建动态灵活的UI设计,可以适应于不同的屏幕尺寸从掱机到平板电脑。
  • Fragment是一个独立的模块,紧紧地与activity绑定在一起可以运行中动态地移除、加入、交换等。
  • Fragment 切换流畅轻量切换。
  • Fragment做局部内容更噺更方便原来为了到达这一点要把多个布局放到一个activity里面,现在可以用多Fragment来代替只有在需要的时候才加载Fragment,提高性能

有没有使用过嵌套Fragment?(蚂蚁金服-支付宝-一面)

handler.postDelayed中的run是工作在主线程还是子线程(蚂蚁金服-支付宝-一面)

postDelayed中传入的是Runnable对象而这个开启的runnable会在这个handler所依附線程中运行,而这个handler是在UI线程中创建的所以自然地依附在主线程中了。

Android中的内存管理(蚂蚁金服-支付宝-一面)

从操作系统的角度来说內存就是一块数据存储区域,是可被操作系统调度的资源在多任务(进程)的OS中,内存管理尤为重要OS需要}

我要回帖

更多关于 runonuithread 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信