Android 主线程中 Looper 的轮询死循环为何没阻塞主线程

01.造成ANR的原因

  • 造成ANR的原因一般有两种:
    • 当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了)
    • 当前的事件正在处理,但没有及时完成
  • 为了避免ANR异常,android使用了Handler消息处理机制。让耗时操作在子线程运行。

02.问题描述

阅读更多

Android MessageQueue

01.MessageQueue作用介绍

  • MessageQueue,主要包含2个操作:插入和读取。
    • 读取操作会伴随着删除操作,插入和读取对应的方法分别为enqueueMessage和next,其中enqueueMessage的作用是往消息队列中插入一条消息,而next的作用是从消息队列中取出一条消息并将其从消息队列中移除。
  • 虽然MessageQueue叫消息队列,但是它的内部实现并不是用的队列。
阅读更多

Android Looper 深度解析

01.Activity如何自动绑定Looper

  • 主线程如何自动调用Looper.prepare()

  • ActivityThread,并且在main方法中我们会看到主线程也是通过Looper方式来维持一个消息循环。那么这个死循环会不会导致应用卡死,即使不会的话,它会慢慢的消耗越来越多的资源吗?

    • 对于线程即是一段可执行的代码,当可执行代码执行完成后,线程生命周期便该终止了,线程退出。而对于主线程,我们是绝不希望会被运行一段时间,自己就退出,那么如何保证能一直存活呢?简单做法就是可执行代码是能一直执行下去的,死循环便能保证不会被退出。
阅读更多

Android Handler 深度解析

01.Handler构造方法

  • 首先看看构造方法

    • 可以看出在Handler的构造方法中,主要初始化了一下变量,并判断Handler对象的初始化不应再内部类,静态类,匿名类中,并且保存了当前线程中的Looper对象。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
    final Class<? extends Handler> klass = getClass();
    if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
    (klass.getModifiers() & Modifier.STATIC) == 0) {
    Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
    klass.getCanonicalName());
    }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
    throw new RuntimeException(
    "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
    }
阅读更多

Android 消息机制源码流程

01.Handler发送消息

  • Handler 发送消息的形式主要有以下几种形式,其最终调用的都是 sendMessageAtTime() 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
    }

    public final boolean post(Runnable r){
    return sendMessageDelayed(getPostMessage(r), 0);
    }

    public final boolean sendMessageDelayed(Message msg, long delayMillis){
    if (delayMillis < 0) {
    delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
阅读更多

Android Handler 机制体系

01.Handler必备知识点

  • 作用:
    • 跨线程通信。当子线程中进行耗时操作后需要更新UI时,通过Handler将有关UI的操作切换到主线程中执行。
  • 四要素:
    • Message(消息):需要被传递的消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,最终由Handler处理。
    • MessageQueue(消息队列):用来存放Handler发送过来的消息,通过 Handler 发送的消息并非是立即执行的,需要存入一个消息队列中来依次执行,内部通过单链表的数据结构来维护消息列表,等待Looper的抽取。
阅读更多

Android Handler 基础使用

01.Handler常见使用方式

  • handler机制大家都比较熟悉呢。在子线程中发送消息,主线程接受到消息并且处理逻辑。如下所示

    • 一般handler的使用方式都是在主线程中定义Handler,然后在子线程中调用mHandler.sendXx()方法,这里有一个疑问可以在子线程中定义Handler吗?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class MainActivity extends AppCompatActivity {

    private TextView tv ;

    /**
    * 在主线程中定义Handler,并实现对应的handleMessage方法
    */
    public static Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    if (msg.what == 101) {
    Log.i("MainActivity", "接收到handler消息...");
    }
    }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tv = (TextView) findViewById(R.id.tv);
    tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    new Thread() {
    @Override
    public void run() {
    // 在子线程中发送异步消息
    mHandler.sendEmptyMessage(1);
    }
    }.start();
    }
    });
    }
    }
阅读更多

Android 主题 Theme 的使用总结

目录导向

  • 1.设置全屏【应用广泛】
    • 1.1 style设置
    • 1.2 直接设置
    • 1.3 代码设置
  • 2.Theme主题大全
  • 3.设置窗体透明度,昏暗度,背景模糊处理
    • 3.3 透明度
    • 3.2 昏暗度
    • 3.3 背景模糊

image

阅读更多

Android attr 属性介绍

attr属性的定义/读取/出错/使用

  • 1.1 自定义attr属性与读取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * 初始化。
    *
    * @param context 上下文。
    * @param attributeSet 属性。
    */
    private void initialize(Context context, AttributeSet attributeSet) {
    mPaint.setAntiAlias(true);
    TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.CircleProgressbar);
    if (typedArray.hasValue(R.styleable.CircleProgressbar_circle_color)){
    inCircleColors = typedArray.getColorStateList(R.styleable.CircleProgressbar_circle_color);
    } else{
    inCircleColors = ColorStateList.valueOf(Color.TRANSPARENT);
    }
    circleColor = inCircleColors.getColorForState(getDrawableState(), Color.TRANSPARENT);
    typedArray.recycle();
    }
阅读更多

Android Style 样式汇总

目录介绍

  • 1.简单介绍
  • 2.样式的定义
  • 3.主题

1.简单介绍

  • 整合所有资源,定义成统一的样式。哪些该定义成统一的样式呢?举几个例子吧:
      1. 每个页面标题栏的标题基本会有一样的字体大小、颜色、对齐方式、内间距、外间距等,这就可以定义成样式;
阅读更多