小知识:handler/http/https等

Handler

  1. 日常编码的使用:
    使用前初始化Handler对象,重写handleMessage()方法,拿到Message对象后,做延时处理/定时处理/更新UI等操作,通常直接初始化会有警告提示 @SuppressLint(“HandlerLeak”)
    原因:作为匿名内部类的方式使用时,会持有外部类的对象(一般是Activity),当外部类被关闭,GC回收会因为外部类对象还被持有,造成内存泄露
    解决办法:( https://blog.csdn.net/androidsj/article/details/79865091 详解)
    推荐采用静态内部类实现, 并持有Activity 的弱引用,可以避免无法被回收导致内存泄露。
    当然很多时候在写demo的时候,为了方便(懒)可以直接构造匿名内部类,但要在onDestory生命周期中主动释放未处理消息 mHandler.removeCallbacksAndMessages(null).
private MyHandler handler = new MyHandler(this);
    static class MyHandler extends Handler {
        WeakReference weakReference;
        public MyHandler(SecondActivity activity) {
            weakReference = new WeakReference(activity);
        }
 
        @Override
        public void handleMessage(Message msg) {
            
        }
    }
  1. 用的最多的异步更新UI方法(post/postDelayed):
    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

可以看到post方法其实也是sendMessageDelayed – > 最终的enqueueMessage 入队来处理消息。
在这边要注意的是,在子线程中使用时此处的Runnable 只是重写run,在方法内实现自己的目的。
那么所有我们sendMessage等方法是如何一步步处理的呢:
Handler.postDelayed(Runnable r, long delayMillis)
–> Handler.sendMessageDelayed(getPostMessage®, delayMillis)
–> Handler.sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)
–> Handler.enqueueMessage(queue, msg, uptimeMillis)
–> MessageQueue.enqueueMessage(msg, uptimeMillis)

(https://www.cnblogs.com/ldq2016/p/9260783.html 详解)

msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
...
}

在enqueueMessage中 是一个链表,把传递的信息依次入队,如果有delayed时间,则:when < p.when 判断时间,来决定插入顺序,接下来就是Looper.loop()中的循环读取,在一个死循环中,从mQueue中取出Message对象, 调用每个Message对象的msg.target.dispatchMesssge方法:

for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//派发消息到对应的handler
 msg.target.dispatchMessage(msg);
 //无效的资源回收
 msg.recycle();
}

让我们看看next()方法的具体做法:

for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
 
nativePollOnce(ptr, nextPollTimeoutMillis);
 
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
...
}
}

疑问 - -为什么不会阻塞?是因为循环取值为空,则blocked,不会耗费太多性能 之后会调用native中的唤醒方法进行精确唤醒 nativePollOnce(ptr, nextPollTimeoutMillis); 到此为止已经大体流程已经结束。

小结

  1. Looper类用来为一个线程开启一个消息循环。
    默认情况下android中新诞生的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)
    Looper对象通过MessageQueue来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。(如果对一个已经quit的Looper重新start会出现异常)
  2. 通常是通过Handler对象来与Looper进行交互的。Handler可看做是Looper的一个接口,用来向指定的Looper发送消息及定义处理方法。
    默认情况下Handler会与其被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。
    mainHandler = new Handler() 等价于new Handler(Looper.myLooper()).
    Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。
  3. 在非主线程中直接new Handler() 会报如下的错误:
    E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
    E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
    原因是非主线程中默认没有创建Looper对象,需要先调用Looper.prepare()启用Looper。
  4. Looper.loop(); 让Looper开始工作,从消息队列里取消息,处理消息。
    注意:写在Looper.loop()之后的代码不会被执行,这个函数内部应该是一个循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
  5. 基于以上知识,可实现主线程给子线程(非主线程)发送消息。

Http/https

http协议特点:
1.支持客户/服务器模式
2.简单快速:客户向服务端请求服务时,只需传送请求方式和路径。
3.灵活:允许传输任意类型的数据对象。由Content-Type加以标记。
4.无连接:每次响应一个请求,响应完成以后就断开连接。
5.无状态:服务器不保存浏览器的任何信息。每次提交的请求之间没有关联。

https协议:
HTTPS相当于HTTP的安全版本了,是在http的基础之上加上ssl(Secure Socket Layer)

在项目中发现每次开机的https请求都会失败,追溯后发现是时间未同步导致证书验证失败,随即找后端同事增加了安全证书,并本地加载使用。
安全证书:
https://blog.csdn.net/axi295309066/article/details/52494832 详解
自己的总结下次再写。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值