2018.03.十二、Android知识点-Android篇

一、Activity相关:

一、Activity的生命周期

image


二、Activity的启动模式以及使用场景

启动模式javascript

  1. standard:默认的启动模式,每次建立都会产生新的实例,谁启动了该模式的Activity,该Activity就属于启动它的Activity的任务栈中
  2. singleTop:栈顶复用模式,若是新的activity已经位于栈顶,那么这个Activity不会被重写建立,同时它的onNewIntent(Intent intent)方法会被调用,经过此方法的参数咱们能够去除当前请求的信息,该 Activity的实例不在该栈或者不在栈顶 时,其行为同standard启动模式
  3. singleTask:栈内复用模式,若是栈中存在这个Activity的实例就会复用这个Activity,无论它是否位于栈顶,复用时,会将它上面的Activity所有出栈,而且会回调该实例的onNewIntent方法。
  4. singleInstance:全局惟一模式,具有singleTask模式的全部特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具备全局惟一性,即整个系统中就这么一个实例,因为栈内复用的特性,后续的请求均不会建立新的Activity实例,除非这个特殊的任务栈被销毁了,当复用该实例 会回调onNewIntent方法

三、Activity的启动过程(不要回答生命周期)

Activity 启动流程图

Activity的启动过程 必须掌握的Activity启动过程html

四、在Activity中如何保存/恢复状态?

分别调用onSaveInstanceState(Bundle outState)和 
onRestoreInstanceState(Bundle outState)  2个方法保存和恢复状态。
复制代码

五、在Activity中如何保存/恢复状态?

  • 不设置Activity的android:configChanges时,切屏会从新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次;
  • 设置Activity的android:configChanges="orientation"时,切屏仍是会从新调用各个生命周期,切横、竖屏时只会执行一次;
  • 设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会从新调用各个生命周期,只会执行onConfigurationChanged方法;

六、Activity上有Dialog的时候按Home键时的生命周期?

按Home键,再开启activity. java

七、Application 和 Activity 的 Context 对象的区别

  • 一、生命周期不一样,Application的context随应用存在而存在,activity的context随该activity的存在而存在。
  • 二、适用范围不一样,Application的context 不能用在 show dialog()、start activity()、Layout inflation().ativity 可使用。

二、Service相关

1. Service的startService(Intent)启动方式

  • 使用这种start方式启动的Service的生命周期以下: onCreate()--->onStartCommand()(onStart()方法已过期) ---> onDestory()
  • 若是服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和onStartCommand()
  • 服务中止的时候调用 onDestory()。服务只会被中止一次。
  • 特色:一旦服务开启跟调用者(开启者)就没有任何关系了。 开启者退出了,开启者挂了,服务还在后台长期的运行。 开启者不能调用服务里面的方法。

2. 采用bind的方式开启服务

  • 使用这种start方式启动的Service的生命周期以下:onCreate() --->onBind()--->onunbind()--->onDestory()
  • bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。 绑定者能够调用服务里面的方法

3.service和activity怎么进行数据交互?

一种是使用broadcast,另外一种是使用bindService。android

  • 一、经过广播:在service中发送广播,在activity中建立一个BroadcastReceive()接收;
  • 二、bindService:activity经过Intent传值给service,并建立ServiceConnection()对象,得到BindService.MyBind。

4.怎么保证service不被杀死?

  • 1.onStartCommand方法,返回START_STICKY,当service因内存不足被kill,当内存又有的时候,service又被从新建立。
  • 2.提高service优先级,在AndroidManifest.xml文件中对于intent-filter能够经过android:priority = "1000"这个属性设置最高优先级,1000是最高值,若是数字越小则优先级越低
  • 三、提高service进程优先级
  • 四、service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,从新启动service;
  • 五、两个守护进程

三、Broadcast相关

一、Broadcast注册方式与区别

  1. Manifest.xml中静态注册:
//new出上边定义好的BroadcastReceiver
MyBroadCastReceiver yBroadCastReceiver = new MyBroadCastReceiver();

//实例化过滤器并设置要过滤的广播  
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");

//注册广播   
myContext.registerReceiver(smsBroadCastReceiver,intentFilter, 
             "android.permission.RECEIVE_SMS", null);

复制代码
  1. 代码中动态注册:

直接在Manifest.xml文件的节点中配置广播接收者web

<receiver android:name=".MyBroadCastReceiver">  
            <!-- android:priority属性是设置此接收者的优先级(从-1000到1000) -->
            <intent-filter android:priority="20">
            <actionandroid:name="android.provider.Telephony.SMS_RECEIVED"/>  
            </intent-filter>  
</receiver>

复制代码

二、两种注册广播的不一样

  • 第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
  • 第二种是常驻型,也就是说当应用程序关闭后,若是有信息广播来,程序也会被系统调用自动运行。

三、发送广播的两种方式

  • 无序广播:全部的接收者都会接收事件,不能够被拦截,不能够被修改。
  • 有序广播:按照优先级,一级一级的向下传递,接收者能够修改广播数据,也能够终止广播事件。

Android 两种注册、发送广播的区别算法


补一、ContentProvider相关:

ContentProvider的基本使用方法和做用。ContentValue的使用方法,他和HashMap的区别是什么?数据库

ContentProvider 是Android系统中提供的专门用户不一样应用间进行数据共享的组件,提供了一套标准的接口用来获取以及操做数据,准许开发者把本身的应用数据根据需求开放给其余应用进行增删改查,而无须担忧直接开放数据库权限而带来的安全问题。数组

ContentValue: 存储数据封装的HashMap,提供 put、get等方法浏览器

一、说说ContentProvider、ContentResolver、ContentObserver 之间的关系?

  • 1.ContentProvider 内容提供者,用于对外提供数据
  • 2.ContentResolver 内容解析者,用于获取内容提供者提供的数据
  • 3.ContentObserver 内容监听器,能够监听数据的改变状态
  • 4.ContentResolver.notifyChange(uri)发出消息
  • 5.ContentResolver.registerContentObserver()监听消息。

二、ContentProvider与数据库(SQL)的区别?

  • 一、ContentProvider 屏蔽了数据存储细节,能够在不一样应用间进行数据操做。
  • 二、SQL也有增删改查的方法,只能对本应用的数据进行操做。

Android ContentProvider基本用法缓存

四、网络相关

一、HttpClient与HttpUrlConnection的区别 2

  1. 功能上:
  • Http Client:适用于web浏览器,拥有大量灵活的API,提供了不少工具,封装了http的请求头,参数,内容体,响应,还有一些高级功能,代理、COOKIE、鉴权、压缩、链接池的处理正所以,在不破坏兼容性的前提下,其庞大的API也令人难以改进。
  • HttpURLConnection: 对于大部分功能都进行了包装,Http Client的高级功能代码会较复杂,

2.性能上:

  • HttpURLConnection直接支持GZIP压缩,默认添加"Accept-Encoding: gzip"头字段到请求中,并处理相应的回应,
  • 而Http Client虽然支持,但须要本身写代码处理。

3.选用:

  • Volley里用的哪一种请求方式(2.3前HttpClient,2.3后HttpUrlConnection)

二、HTTPS和HTTP的区别 2

一、什么是 HTTPS

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。

即HTTP下加入SSL (Secure Socket Layer)层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL。


二、HTTPS 和 HTTP 的区别
  • https 用的 443 端口, http 用的 80 端口
  • https协议须要到ca申请证书,通常免费证书不多,须要交费。
  • http是超文本传输协议,信息是明文传输,https 则是具备安全性的ssl加密传输协议。
  • http和https使用的是彻底不一样的链接方式,用的端口也不同,前者是80,后者是443。
  • http的链接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

Android使用OkHttp请求自签名的https网站 Android Https相关彻底解析 当OkHttp遇到Https HTTPS和HTTP的区别


五、View相关

一、view的Touch事件传递机制

一、和touch相关的三个方法
  1. public boolean dispatchTouchEvent(MotionEvent ev); //用来分派event
  2. public boolean onInterceptTouchEvent(MotionEvent ev); //用来拦截event
  3. public boolean onTouchEvent(MotionEvent ev); //用来处理event
方 法 解析
dispatchTouchEvent() 用来分派事件。其中调用了onInterceptTouchEvent()和onTouchEvent(),通常不重写该方法,返回true则表示该事件被消费
onInterceptTouchEvent() 用来拦截事件。ViewGroup类中的源码实现就是{return false;}表示不拦截该事件,事件将向下传递(传递给其子View);若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递,事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法
onTouchEvent() 用来处理事件。返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View);返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处

Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()


六、动画相关

一、Android中有几种动画?

Android3.0以前有2种,3.0后有3种。
复制代码
  • FrameAnimation(逐帧动画):将多张图片组合起来进行播放,相似于早期电影的工做原理,不少App的loading是采用这种方式。
  • TweenAnimation(补间动画):是对某个View进行一系列的动画的操做,包括淡入淡出(AlphaAnimation),缩放(ScaleAnimation),平移(TranslateAnimation),旋转(RotateAnimation)四种模式。
  • PropertyAnimation(属性动画):属性动画再也不仅仅是一种视觉效果了,而是一种不断地对值进行操做的机制,并将值赋到指定对象的指定属性上,能够是任意对象的任意属性。

注1:AnimationSet 继承自Animation,是上面四种的组合容器管理类,没有本身特有的属性,他的属性继承自Animation,因此特别注意,当咱们对set标签使用Animation的属性时会对该标签下的全部子控件都产生影响。

注2:补间动画执行以后并未改变View的真实布局属性值。切记这一点,譬如咱们在Activity中有一个Button在屏幕上方,咱们设置了平移动画移动到屏幕下方而后保持动画最后执行状态呆在屏幕下方,这时若是点击屏幕下方动画执行以后的Button是没有任何反应的,而点击原来屏幕上方没有Button的地方却响应的是点击Button的事件。


二、属性动画

  • ObjectAnimator:继承自ValueAnimator,容许你指定要进行动画的对象以及该对象的一个属性。
  • 大多数的状况使用ObjectAnimator就足够了,由于它使得目标对象动画值的处理过程变得足够简单,不用像ValueAnimator那样本身写动画更新的逻辑
  • ObjectAnimator的动画原理是不停的调用setXXX方法更新属性值,全部使用ObjectAnimator更新属性时的前提是Object必须声明有getXXX和setXXX方法
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0,  1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                //int value = animation.getAnimatedValue();  能够获取当前属性值
                //view.postInvalidate();  能够主动刷新
                //view.setXXX(value);
                //view.setXXX(value);
                //......能够批量修改属性
            }
        });
复制代码
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
复制代码
  • PropertyValuesHolder:多属性动画同时工做管理类。有时候咱们须要同时修改多个属性,那就能够用到此类
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);  
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);  
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
复制代码
  • ValueAnimator:属性动画中的时间驱动,管理着动画时间的开始、结束属性值,相应时间属性值计算方法等。包含全部计算动画值的核心函数以及每个动画时间节点上的信息、一个动画是否重复、是否监听更新事件等,而且还能够设置自定义的计算类型。
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight);  //定义动画
animator.setTarget(view);   //设置做用目标
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation){
        float value = (float) animation.getAnimatedValue();
        view.setXXX(value);  //必须经过这里设置属性值才有效
        view.mXXX = value;  //不须要setXXX属性方法
    }
});
复制代码

特别注意:ValueAnimator只是动画计算管理驱动,设置了做用目标,但没有设置属性,须要经过updateListener里设置属性才会生效。

  • AnimationSet:动画集合,提供把多个动画组合成一个组合的机制,并可设置动画的时序关系,如同时播放、顺序播放或延迟播放。具体使用方法比较简单,以下:

Android应用开发之全部动画使用详解

七、Android中跨进程通信

android系统中应用程序之间不能共享内存。 所以,在不一样应用程序之间交互数据(跨进程通信)就稍微麻烦一些

  • 一、访问其余应用程序的Activity
如调用系统通话应用
Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);
复制代码
  • 二、Content Provider

Content Provider提供了一种在多个应用程序之间数据共享的方式(跨进程共享数据)。应用程序能够利用Content Provider完成下面的工做

  1. 查询数据
  2. 修改数据
  3. 添加数据
  4. 删除数据

虽然Content Provider也能够在同一个应用程序中被访问,但这么作并无什么意义。Content Provider存在的目的向其余应用程序共享数据和容许其余应用程序对数据进行增、删、改操做。 Android系统自己提供了不少Content Provider,例如,音频、视频、联系人信息等等。咱们能够经过这些Content Provider得到相关信息的列表。这些列表数据将以Cursor对象返回。所以,从Content Provider返回的数据是二维表的形式。

如访问系统相册
复制代码
  • 三、广播(Broadcast)
广播是一种被动跨进程通信的方式。当某个程序向系统发送广播时,其余的应用程序只能被动地接收广播数据。这就象电台进行广播同样,听众只能被动地收听,而不能主动与电台进行沟通。例如获取手机电量信息
复制代码
  • 四、AIDL服务

二、AIDL理解

一、定义:Android系统中的进程之间不能共享内存,所以,须要提供一些机制在不一样进程之间进行数据通讯。 为了使其余的应用程序也能够访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现。与不少其余的基于RPC的解决方案同样,Android使用一种接口定义语言(Interface Definition Language,IDL)来公开服务的接口。咱们知道4个Android应用程序组件中的3个(Activity、BroadcastReceiver和ContentProvider)均可以进行跨进程访问,另一个Android应用程序组件Service一样能够。所以,能够将这种能够跨进程访问的服务称为AIDL(Android Interface Definition Language)服务。


三、Binder理解

一、什么是binder:

Binder是Android实现 跨进程通信(IPC)的方式,是一种虚拟的物理设备驱动,实现了IBindler 接口。

二、知识概念
  1. 一个进程空间分为 用户空间 & 内核空间(Kernel),即把进程内 用户 & 内核 隔离开来

区别:

  1. 进程间,用户空间的数据不可共享,因此用户空间 = 不可共享空间
  2. 进程间,内核空间的数据可共享,因此内核空间 = 可共享空间
  1. 进程隔离:保证 安全性 & 独立性,一个进程 不能直接操做或者访问另外一个进程,即Android的进程是相互独立、隔离的
  2. 跨进程通讯( IPC ):隔离后,因为某些需求,进程间 须要合做 / 交互
  3. 跨进程间通讯的原理
  • 先经过 进程间 的内核空间进行 数据交互
  • 再经过 进程内 的用户空间 & 内核空间进行 数据交互,从而实现 进程间的用户空间 的数据交互
    image
  • 而Binder,就是充当 链接 两个进程(内核空间)的通道。
三、Binder 跨进程通讯机制 模型
  1. 模型原理:

image

四、优势

对比 Linux (Android基于Linux)上的其余进程通讯方式(管道、消息队列、共享内存、 信号量、Socket),Binder 机制的优势有:

image

Binder学习指南

图文详解 Android Binder跨进程通讯的原理


八、Handler相关

一、handler 消息传递分析

做用:Handle 进行消息传递

  1. Handle发送的msg经过enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)添加进(MessageQueue)消息队列中.

Android 消息传递机制分析


二、Handle、Message、MessageQueue、Looper之间的关系

  • Handle:主要发送 Message
  • Message:消息
  • MessageQueue:消息队列.保存由Looper发送的消息列表。
  • Looper:用于为线程运行消息循环的类。Thread默认状况下没有与之关联,经过prepare()循环运行在线程中,经过loop(for(;;))来处理消息。

九、热修复相关

一、热修复包含:

  1. 资源替换
  2. 类替换(四大组件、类)
  3. SO补丁

二、资源替换方法:

思路:Andorid APP默认的类加载是PathClassLoader,这个只能加载本身APK的dex文件,因此咱们须要使用DexClassLoader。咱们用DexClassLoader加载外部的APK以后,经过反射获取对应的资源。


三、类替换(四大组件、类):

  1. 经过PathClassLoader 来加载咱们自身App的dex
  2. 经过DexClassLoader来加载咱们的补丁dex文件,这里面就是没有bug的dex
  3. 反射两个classLoader的<DexPathList pathList;>
  4. 接着咱们来继续反射两个classloader中的pathList(注意:是两个!一个是咱们本身应用的,另外一个是咱们补丁的,PathClassLoader和DexClassLoader都继承BaseDexClassLoader),DexPathList里面的<Element[] dexElements;>,没错仍是拿到这个数组的值
  5. 合并两个反射到的Element 数组!这里是重中之重.咱们须要把咱们的补丁dex放在数组的最前面!
  6. 将合并的新的数组,经过Field从新设置到咱们自身App的DexPathList->dexElements.没错!就是合并以后覆盖有bug那个loader的Element 数组!!
  7. 经过Android build-tools 中的dx命令打包一个没有bug的dex

Android 热修复(全网最简单的热修复讲解)


四、SO补丁:


十、图片加载缓存相关

一、设计一套图片异步加载缓存方案

缓存层分为三层:内存层,磁盘层,网络层

  • 内存层:内存缓存相对于磁盘缓存而言,速度要来的快不少,但缺点容量较小且会被系统回收,这里的实现我用到了LruCache。
  • 磁盘层:相比内存缓存而言速度要来得慢不少,但容量很大,这里的实现我用到了DiskLruCache类。
  • 网络层:网络访问实现我用到了开源框架Volley

十一、内存泄露及管理

一、内存泄漏:

  • 内存泄露:程序在向系统申请分配内存空间后(new),在使用完毕后未释放。结果致使一直占据该内存单元,咱们和程序都没法再使用该内存单元,直到程序结束,这是内存泄露。
  • 内存溢出:程序向系统申请的内存空间超出了系统能给的。好比内存只能分配一个int类型,我却要塞给他一个long类型,系统就出现oom。又好比一车最多能坐5我的,你却非要塞下10个,车就挤爆了。
  • 大量的内存泄露会致使内存溢出(oom)

二、内存:

  • 栈(stack):是简单的数据结构,但在计算机中使用普遍。栈最显著的特征是:LIFO(Last In, First Out, 后进先出),栈中只存放基本类型和对象的引用(不是对象)。
  • 堆(heap):堆内存用于存放由new建立的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。JVM只有一个堆区(heap)被全部线程共享,堆中不存放基本类型和对象引用,只存放对象自己。
  • 方法区(method):又叫静态区,跟堆同样,被全部的线程共享。方法区包含全部的class和static变量。

三、内存优化

  1. 单例致使内存泄露
public class AppSettings {

    private static AppSettings sInstance;
    private Context mContext;

    private AppSettings(Context context) {
        this.mContext = context;
        
        //this.mContext = context.getApplicationContext();
    }

    public static AppSettings getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppSettings(context);
        }
        return sInstance;
    }
}

复制代码

二、静态变量致使内存泄露

public class MainActivity extends AppCompatActivity {

    private static Info sInfo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (sInfo != null) {
            sInfo = new Info(this);
        }
    }
}

class Info {
    public Info(Activity activity) {
    }
}

复制代码

Info做为Activity的静态成员,而且持有Activity的引用,可是sInfo做为静态变量,生命周期确定比Activity长。因此当Activity退出后,sInfo仍然引用了Activity,Activity不能被回收,这就致使了内存泄露。

三、非静态内部类致使内存泄露

非静态内部类(包括匿名内部类)默认就会持有外部类的引用,当非静态内部类对象的生命周期比外部类对象的生命周期长时,就会致使内存泄露。

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 1) {
                // 作相应逻辑
            }
        }
    };
}

复制代码

熟悉Handler消息机制的都知道,mHandler会做为成员变量保存在发送的消息msg中,即msg持有mHandler的引用,而mHandler是Activity的非静态内部类实例,即mHandler持有Activity的引用,那么咱们就能够理解为msg间接持有Activity的引用。msg被发送后先放到消息队列MessageQueue中,而后等待Looper的轮询处理(MessageQueue和Looper都是与线程相关联的,MessageQueue是Looper引用的成员变量,而Looper是保存在ThreadLocal中的)。那么当Activity退出后,msg可能仍然存在于消息对列MessageQueue中未处理或者正在处理,那么这样就会致使Activity没法被回收,以至发生Activity的内存泄露。

一般在Android开发中若是要使用内部类,但又要规避内存泄露,通常都会采用静态内部类+弱引用的方式。

public class MainActivity extends AppCompatActivity {

    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new MyHandler(this);
        start();
    }

    private void start() {
        Message msg = Message.obtain();
        msg.what = 1;
        mHandler.sendMessage(msg);
    }

    private static class MyHandler extends Handler {

        private WeakReference<MainActivity> activityWeakReference;

        public MyHandler(MainActivity activity) {
            activityWeakReference = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = activityWeakReference.get();
            if (activity != null) {
                if (msg.what == 1) {
                    // 作相应逻辑
                }
            }
        }
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mHandler.removeCallbacksAndMessages(null);
}
复制代码

非静态内部类形成内存泄露还有一种状况就是使用Thread或者AsyncTask

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 模拟相应耗时逻辑
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}


复制代码

这种方式新建的子线程Thread和AsyncTask都是匿名内部类对象,默认就隐式的持有外部Activity的引用,致使Activity内存泄露。

四、未取消注册或回调致使内存泄露

  • 在Activity中注册广播,若是在Activity销毁后不取消注册

五、Timer和TimerTask致使内存泄露

  • Timer和TimerTask在Android中一般会被用来作一些计时或循环任务

六、集合中的对象未清理形成内存泄露

若是一个对象放入到ArrayList、HashMap等集合中,这个集合就会持有该对象的引用。当咱们再也不须要这个对象时,也并无将它从集合中移除,这样只要集合还在使用(而此对象已经无用了),这个对象就形成了内存泄露。而且若是集合被静态引用的话,集合里面那些没有用的对象更会形成内存泄露了。因此在使用集合时要及时将不用的对象从集合remove,或者clear集合,以免内存泄漏。

七、资源未关闭或释放致使内存泄露

在使用IO、File流或者Sqlite、Cursor等资源时要及时关闭。这些资源在进行读写操做时一般都使用了缓冲,若是及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以至发生内存泄露。所以咱们在不须要使用它们的时候就及时关闭,以便缓冲能及时获得释放,从而避免内存泄露。

八、属性动画形成内存泄露

动画一样是一个耗时任务,好比在Activity中启动了属性动画(ObjectAnimator),可是在销毁的时候,没有调用cancle方法,虽然咱们看不到动画了,可是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用Activity,这就形成Activity没法正常释放。所以一样要在Activity销毁的时候cancel掉属性动画,避免发生内存泄漏。

@Override
protected void onDestroy() {
    super.onDestroy();
    mAnimator.cancel();
}
复制代码

九、WebView形成内存泄露

关于WebView的内存泄露,由于WebView在加载网页后会长期占用内存而不能被释放,所以咱们在Activity销毁后要调用它的destory()方法来销毁它以释放内存。

@Override
protected void onDestroy() {
    super.onDestroy();
    // 先从父控件中移除WebView
    mWebViewContainer.removeView(mWebView);
    mWebView.stopLoading();
    mWebView.getSettings().setJavaScriptEnabled(false);
    mWebView.clearHistory();
    mWebView.removeAllViews();
    mWebView.destroy();
}

复制代码

十、总结

1).资源对象没关闭形成的内存泄漏 2).构造Adapter时,没有使用缓存的convertView 3).Bitmap对象不在使用时调用recycle()释放内存 4).试着使用关于application的context来替代和activity相关的context 5).注册没取消形成的内存泄漏 6).集合中对象没清理形成的内存泄漏

查找内存泄漏可使用Android Stdio 自带的Android Profiler工具,也可使用Square产品的LeadCanary.

十二、android 屏幕适配

  • 在 XML 布局文件中指定尺寸时使用 wrap_content、match_parent 或 dp 单位 。
  • 不要在应用代码中使用硬编码的像素值
  • 不要使用 AbsoluteLayout(已弃用)
  • 为不一样屏幕密度提供替代位图可绘制对象

image

支持多种屏幕

面向多种屏幕的设计

Android 屏幕适配:最全面的解决方案

1三、HybridJAVA 与JS交互

  • Android 调 JS : 一、java
webView.loadUrl("javascript:javacalljs()");
复制代码

  二、Html

image

**注意:**考虑有返回值状况;Android在4.4以前并无提供直接调用js函数并获取值的方法,因此在此以前,经常使用的思路是 java调用js方法,js方法执行完毕,再次调用java代码将值返回。

// 4.4以后 java代码时用evaluateJavascript方法调用
private void testEvaluateJavascript(WebView webView) {
  webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {

  @Override
  public void onReceiveValue(String value) {
      Log.i(LOGTAG, "onReceiveValue value=" + value);
  }});
}
复制代码
  • JS 调 Android : 一、java
webView.addJavascriptInterface(MainActivity.this,"android");
复制代码

  二、html

<body>
HTML 内容显示 <br/>
<h1><div id="content">内容显示</div></h1><br/>
<input type="button"  value="点击调用java代码" onclick="window.android.startFunction()" /><br/>
<input type="button"  value="点击调用java代码并传递参数" onclick="window.android.startFunction('http://blog.csdn.net/Leejizhou')"  />
</body>
复制代码

Android中Java和JavaScript交互

1四、单例模式(手写)

//懒汉式
public class Singleton {
    private static Singleton singleton;

    private Singleton() {

    }

    public static synchronized Singleton getSingleton() {
        if (singleton == null) {
            singleton = new Singleton();
        }

        return singleton;
    }
}

复制代码
//饿汉式
public class Singleton {
    private static final Singleton singleton = new Singleton();

    private Singleton () {

    }

    public static Singleton getSingleton() {
        return singleton;
    }
}
复制代码
//double-lock
public class Singleton {
    private volatile static Singleton singleton;

    private Singleton() {

    }

    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized(Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }

        return singleton;
    }
}
复制代码

1四、ANR相关

一、什么是ANR

在Android上,若是你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称做应用程序无响应(ANR:Application Not Responding)对话框。


二、ANR产生的缘由

ANR产生的根本缘由是APP阻塞了UI线程


三、ANR产生的缘由

1:UI线程尽可能只作跟UI相关的工做,但一些复杂的UI操做,仍是须要一些技巧来处理,不如你让一个Button去setText一个10M的文本,UI确定崩掉了,不过对于此类问题,分段加载貌似是最好的方法了。 2:让耗时的工做(好比数据库操做,I/O,链接网络或者别的有可能阻碍UI线程的操做)把它放入单独的线程处理。 3:尽可能用Handler来处理UIthread和别的thread之间的交互。


ANR彻底解析

1五、SharedPreference相关

  • SharedPreference三种得到方法和区别:
一、 Activity类中的getPreferences(int mode)文件自动命名为当前活动的类名。
二、 Context类中getSharedPreferences("fileName", int mode) 此方法能够指定文件名,mode同上。
三、PreferenceManager类中的getDefaultSharedPreferences(Context context)它只接收一个context参数。
文件用当前应用程序的包名和PreferenceActivity一块儿来命名。属于整个应用程序
复制代码

SharedPreference得到方法对比

  • commit和apply的区别:
    1. apply没有返回值而commit返回boolean代表修改是否提交成功。
    2. apply是将修改数据原子提交到内存, 然后异步真正提交到硬件磁盘, 而commit是同步的提交到硬件磁盘,所以,在多个并发的提交commit的时候,他们会等待正在处理的commit保存到磁盘后在操做,从而下降了效率。而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,这样从必定程度上提升了不少效率。
    3. apply方法不会提示任何失败的提示。 因为在一个进程中,sharedPreference是单实例,通常不会出现并发冲突,若是对提交的结果不关心的话,建议使用apply,固然须要确保提交成功且有后续操做的话,仍是须要用commit的。

1六、View,SurfaceView,GLSurfaceView的关系和区别:

  • View:显示视图,内置画布,提供图形绘制函数、触屏事件、按键事件函数等;必须在UI主线程内更新画面,速度较慢。
  • SurfaceView:基于view视图进行拓展的视图类,更适合2D游戏的开发;是view的子类,相似使用双缓机制,在新的线程中更新画面因此刷新界面速度比view快。
  • GLSurfaceView:基于SurfaceView视图再次进行拓展的视图类,专用于3D游戏开发的视图;是SurfaceView的子类,openGL专用。

1七、其余

一、Android 中序列化有哪些方式?区别?

  • Serializable(Java自带): Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象能够在网络上进行传输,也能够存储到本地。
  • Parcelable(android 专用): 不过不一样于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解, 而分解后的每一部分都是Intent所支持的数据类型
  • 区别:
    • Parcelable比Serializable性能高,因此应用内传递数据推荐使用Parcelable
    • Serializable代码量少,写起来方便,缺点是使用了反射,序列化的过程较慢。这种机制会在序列化的时候建立许多的临时对象,容易触发垃圾回收。

二、glide 源码

三、Android中进程的级别,以及各自的区别。

  • 一、前台进程

用户当前正在作的事情须要这个进程。若是知足下面的条件之一,一个进程就被认为是前台进程: 1).这个进程拥有一个正在与用户交互的Activity(这个Activity的onResume()方法被调用)。 2).这个进程拥有一个绑定到正在与用户交互的activity上的Service。 3).这个进程拥有一个前台运行的Service(service调用了方法startForeground()). 4).这个进程拥有一个正在执行其任何一个生命周期回调方法(onCreate(),onStart(),或onDestroy())的Service。 5).这个进程拥有正在执行其onReceive()方法的BroadcastReceiver。 一般,在任什么时候间点,只有不多的前台进程存在。它们只有在达到没法调合的矛盾时才会被杀--如内存过小而不能继续运行时。一般,到了这时,设备就达到了一个内存分页调度状态,因此须要杀一些前台进程来保证用户界面的反应.

  • 二、可见进程

一个进程不拥有运行于前台的组件,可是依然能影响用户所见。知足下列条件时,进程即为可见: 这个进程拥有一个不在前台但仍可见的Activity(它的onPause()方法被调用)。当一个前台activity启动一个对话框时,就出了这种状况。

  • 三、服务进程

一个可见进程被认为是极其重要的。而且,除非只有杀掉它才能够保证全部前台进程的运行,不然是不能动它的。 这个进程拥有一个绑定到可见activity的Service。 一个进程不在上述两种以内,但它运行着一个被startService()所启动的service。 尽管一个服务进程不直接影响用户所见,可是它们一般作一些用户关心的事情(好比播放音乐或下载数据),因此系统不到前台进程和可见进程活不下去时不会杀它。

  • 四、后台进程

一个进程拥有一个当前不可见的activity(activity的onStop()方法被调用)。

  • 五、空进程

一个进程不拥有任何active组件。

四、线程池的相关知识。

Android中的线程池都是之间或间接经过配置ThreadPoolExecutor来实现不一样特性的线程池.Android中最多见的四类具备不一样特性的线程池分别为FixThreadPool、CachedThreadPool、SingleThreadPool、ScheduleThreadExecutor.

  • **FixThreadPool: **只有核心线程,而且数量固定的,也不会被回收,全部线程都活动时,由于队列没有限制大小,新任务会等待执行. 优势:更快的响应外界请求.

  • **SingleThreadPool:**只有一个核心线程,确保全部的任务都在同一线程中按顺序完成.所以不须要处理线程同步的问题.

  • **CachedThreadPool:**只有非核心线程,最大线程数很是大,全部线程都活动时,会为新任务建立新线程,不然会利用空闲线程(60s空闲时间,过了就会被回收,因此线程池中有0个线程的可能)处理任务. 优势:任何任务都会被当即执行(任务队列SynchronousQueue至关于一个空集合);比较适合执行大量的耗时较少的任务.

  • **ScheduleThreadExecutor:**核心线程数固定,非核心线程(闲着没活干会被当即回收)数没有限制. 优势:执行定时任务以及有固定周期的重复任务

Android开发之线程池使用总结

五、怎样计算一张图片的大小,加载bitmap过程(怎样保证不产生内存溢出),二级缓存,LRUCache算法。

一、计算一张图片的大小

图片占用内存的计算公式:图片高度 * 图片宽度 * 一个像素占用的内存大小.因此,计算图片占用内存大小的时候,要考虑图片所在的目录跟设备密度,这两个因素其实影响的是图片的高宽,android会对图片进行拉升跟压缩。

二、加载bitmap过程(怎样保证不产生内存溢出)

因为Android对图片使用内存有限制,如果加载几兆的大图片便内存溢出。
Bitmap会将图片的全部像素(即长x宽)加载到内存中,若是图片分辨率过大,会直接致使内存OOM,只有在BitmapFactory加载图片时使用BitmapFactory.Options对相关参数进行配置来减小加载的像素。

三、BitmapFactory.Options相关参数详解

(1).Options.inPreferredConfig值来下降内存消耗。
  好比:默认值ARGB_8888改成RGB_565,节约一半内存。
(2).设置Options.inSampleSize 缩放比例,对大图片进行压缩 。
(3).设置Options.inPurgeable和inInputShareable:让系统能及时回 收内存。
  A:inPurgeable:设置为True时,表示系统内存不足时能够被回 收,设置为False时,表示不能被回收。
  B:inInputShareable:设置是否深拷贝,与inPurgeable结合使用,inPurgeable为false时,该参数无心义。

(4).使用decodeStream代替其余方法。
decodeResource,setImageResource,setImageBitmap等方法


复制代码

**LRUCache算法:**内部存在一个LinkedHashMap和maxSize,把最近使用的对象用强引用存储在 LinkedHashMap中,给出来put和get方法,每次put图片时计算缓存中全部图片总大小,跟maxSize进行比较,大于maxSize,就将最久添加的图片移除;反之小于maxSize就添加进来。(400行代码不到...)

六、layout、Merge、ViewStub的做用。

  • merge: 它能够删减多余的层级,优化UI。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是若是include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可使用标签优化。

  • ViewStub: 标签最大的优势是当你须要时才会加载,使用他并不会影响UI初始化时的性能。各类不经常使用的布局想进度条、显示错误消息等可使用标签,以减小内存使用量,加快渲染速度。是一个不可见的,大小为0的View。

相关文章
相关标签/搜索