Android-收集-持续更新中...

2018-01-31  本文已影响27人  FDoubleman

1、Activity相关:

1、Activity的生命周期

image

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

启动模式

  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方法

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

Activity 启动流程图

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

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

分别调用onSaveInstanceState和onRestoreInstanceState 2个方法保存和恢复状态。

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


2、Service相关

1、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、Broadcast相关

1、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文件的<application>节点中配置广播接收者

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


2、两种注册广播的不同

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

3、发送广播的两种方式

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

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


补1、ContentProvider相关:

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

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

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

Android ContentProvider基本用法

4、网络相关

1、HttpClient与HttpUrlConnection的区别 2

  1. 功能上:

2.性能上:

3.选用:


2、HTTPS和HTTP的区别 2

1、什么是 HTTPS

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

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


2、HTTPS 和 HTTP 的区别

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


5、View相关

1、view的Touch事件传递机制

1、和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()


6、动画相关

1、Android中有几种动画?

Android3.0之前有2种,3.0后有3种。

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

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


2、属性动画

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 a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);  
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);  
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
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里设置属性才会生效。

Android应用开发之所有动画使用详解

7、Android中跨进程通讯

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

如调用系统通话应用
Intent callIntent=new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);

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

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

虽然Content Provider也可以在同一个应用程序中被访问,但这么做并没有什么意义。Content Provider存在的目的向其他应用程序共享数据和允许其他应用程序对数据进行增、删、改操作。
Android系统本身提供了很多Content Provider,例如,音频、视频、联系人信息等等。我们可以通过这些Content Provider获得相关信息的列表。这些列表数据将以Cursor对象返回。因此,从Content Provider返回的数据是二维表的形式。

如访问系统相册
广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。例如获取手机电量信息

2、AIDL理解

1、定义: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)服务。


3、Binder理解

1、什么是binder:

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

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

区别:

  1. 进程间,用户空间的数据不可共享,所以用户空间 = 不可共享空间
  2. 进程间,内核空间的数据可共享,所以内核空间 = 可共享空间
  1. 进程隔离:保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的
  2. 跨进程通信( IPC ):隔离后,由于某些需求,进程间 需要合作 / 交互
  3. 跨进程间通信的原理
3、Binder 跨进程通信机制 模型
  1. 模型原理:
image
4、优点

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


image

Binder学习指南

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


8、Handler相关

1、handler 消息传递分析

作用:Handle 进行消息传递

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

Android 消息传递机制分析


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


9、热修复相关

1、热修复包含:

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

2、资源替换方法:

思路:Andorid APP默认的类加载是PathClassLoader,这个只能加载自己APK的dex文件,所以我们需要使用DexClassLoader。我们用DexClassLoader加载外部的APK之后,通过反射获取对应的资源。


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

  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 热修复(全网最简单的热修复讲解)


4、SO补丁:


10、图片加载缓存相关

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

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


11、内存泄露及管理

1、内存泄漏:


2、内存:


3、内存优化

  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;
    }
}

2、静态变量导致内存泄露

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不能被回收,这就导致了内存泄露。

3、非静态内部类导致内存泄露

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

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内存泄露。

4、未取消注册或回调导致内存泄露

5、Timer和TimerTask导致内存泄露

6、集合中的对象未清理造成内存泄露

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

7、资源未关闭或释放导致内存泄露

在使用IO、File流或者Sqlite、Cursor等资源时要及时关闭。这些资源在进行读写操作时通常都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以致发生内存泄露。因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄露。

8、属性动画造成内存泄露

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

@Override
protected void onDestroy() {
    super.onDestroy();
    mAnimator.cancel();
}

9、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();
}

10、总结

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

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

12、android 屏幕适配

image

支持多种屏幕

面向多种屏幕的设计

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

13、HybridJAVA 与JS交互

webView.loadUrl("javascript:javacalljs()");

  2、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);
  }});
}
webView.addJavascriptInterface(MainActivity.this,"android");

  2、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交互

14、单例模式(手写)

//懒汉式
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;
    }
}

14、ANR相关

1、什么是ANR

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


2、ANR产生的原因

ANR产生的根本原因是APP阻塞了UI线程


3、ANR产生的原因

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


ANR完全解析

15、SharedPreference相关

1、 Activity类中的getPreferences(int mode)文件自动命名为当前活动的类名。
2、 Context类中getSharedPreferences("fileName", int mode) 此方法可以指定文件名,mode同上。
3、PreferenceManager类中的getDefaultSharedPreferences(Context context)它只接收一个context参数。
文件用当前应用程序的包名和PreferenceActivity一起来命名。属于整个应用程序
SharedPreference获得方法对比

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

17、其他

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

2、glide 源码

3、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组件。

4、线程池的相关知识。

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

Android开发之线程池使用总结

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

1、计算一张图片的大小

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

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

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

3、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行代码不到...)

上一篇下一篇

猜你喜欢

热点阅读