一个Handler类的对象就不会提示,java不能函数式编

2019-10-05 02:39栏目:美高梅开户送58元官网
TAG:

  • java不能函数式编程
  • java匿名内部类只能单线程运行
  • 匿名内部类缺陷:
    1. 语法复杂
    2. this容易混淆
    3. 不能引用外部变量
    4. 不能抽象化来控制流程

封装
1.概念:将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
2.好处:a.只能通过规定的方法访问数据
b.隐藏类的实例细节,方便修改和实现
3.封装的实现步骤

探讨一下为什么Android Studio会提示handler类要写成static的。

图片 1

下面这张图是匿名内部类创建一个对象(本质上是继承了Handler然后覆写了它的方法)。定义一个非静态内部类然后再new也会有这个提示。(为什么直接new 一个Handler类的对象就不会提示,因为不会持有外部类的引用)。

  • 在lambda中,可以使用方法内部变量 ,但是不能改变它的值

image.png

图片 2

封装就是JavaBean思想 你可以理解为 通过某个方法调用封装在类的隐藏属性,就像我把不同颜色的糖果封装在看不见的盒子里,你只有通过我特定的方法才能拿出来某个颜色的糖果,你看不见糖果 ,而且你不通过我你拿不到糖果 这就是封装
为什么封装?这么说吧,你买台电视,你是希望通过遥控按几个按钮就可以控制电视还是直接用一堆密密麻麻的电路板控制?封装的思想隐藏了具体实现的细节,用户只需了解使用的方法就行了,这样就算出错,也只用在用户层面的代码修改就行,而且用户可以直接访问数据,代码会变得一团糟,c++的封装,多态,继承,和java基本都差不多,

image.png

package com.fantJ.JAVA_8;/** * Created by Fant.J. * 2017/12/12 20:58 */public class Lambda_Runnable { public static void main(String[] args) { new Runnable(){ @Override public void run(){ System.out.println("匿名内部类实现Runnable接口"); } }.run(); int i = 1; Runnable r=()->{ System.out.println("lambda实现Runnable接口"); System.out.println; //测试是否可以使用方法内部变量 (匿名内部类只可以使用常量) //i++; //报错 }; r.run(); }}


1.包的作用:a.管理Java文件
b.解决同名文件冲突
2.定义包:package 包名
注:必须放在Java源程序的第一行
包名间可以使用"."号隔开
eg: com.imooc.MyClass

更典型的场景:

图片 3image.png

图片 4

图片 5

package com.fantJ.JAVA_8;/** * Created by Fant.J. * 2017/12/12 21:11 */public class Lambda_Interface { public static void main(String[] args) { new Message() { @Override public void message(String msg) { System.out.println; //打印传参 msg } }.message("用匿名内部类调用自定义的接口"); Message m = (String msg) -> { System.out.println; }; m.message("lambda 调用自定义接口"); } static interface Message { void message(String msg); }}

image.png

image.png

图片 6image.png

3.系统中的包
java.(功能).(类)
java.lang.(类)包含Java语言基础的类
java.util.(类)包含Java语言中的各种工具类
java.io.(类)包含输入、输出相关功能的类
4.包的使用
a.可以通过import关键字,在某个文件使用其他文件中的类
import com.imooc.music.MyClass
b.包的命名规范是全小写字母拼写
c.使用的时候不但可以加载某个包下的所有文件
eg:com.imooc.*
也可以加载某个具体子包下的所有文件
eg:com.imooc.music.*

问题原因

图片 7

image.png

Activity在被结束之后,MessageQueue并不会随之被结束,如果这个消息队列中存在msg,则导致持有handler的引用,但是又
由于Activity被结束了,msg无法被处理,从而导致永久持有handler对象,handler永久持有Activity对象,于是发生内存泄漏。但是为什么为static类型就
会解决这个问题呢?因为在java中所有非静态的对象都会持有当前类的强引用,而静态对象则只会持有当前类的弱引用。声明为静态后,handler将会持
有一个Activity的弱引用,而弱引用会很容易被gc回收,这样就能解决Activity结束后,gc却无法回收的情况。

也就是说这里造成了Activity不能被回收的情况。因为Handler是不应该阻碍Activity回收的(本来就应该是独立的)。

访问修饰符

怎么改

如果改成直接把内部类static class会发生啥大家都知道,就是mTextView不能用了,因为静态内部类不能访问外部对象呀。那总不能把TextView设置成静态的吧。。那TextView可就一直不能被回收了。

所以用弱引用。同样,不仅仅是View,Activity也可以通过弱引用传给Handler。

那么我们这样做吧:

图片 8

image.png

这样可以解除报错,但其实我写的这个例子还不够典型,因为这个例子里TextView是要被更新的,所以Activity被关闭View都没了的话就没有意义了。。那如果WeakReference里包的是一个Activity就更恰当了,因为弱引用非常过分,只要GC遇到了就会回收(GC一般是无向图遍历不到的位置才回收,包括互相引用的两个对象),很适合handleMessage里完全用不到的Activity对象。

图片 9

简单解释

把Handler类写在Activity内部,或者用匿名内部类来声明Handler对象,这个类都会默认持有外部类(比如Activity/Service)的引用。这是由Java编译器在构造函数初始化的时候完成的。那如果外部Activity已经finish了,Activity/Service对象由于被MainLooper->MessageQueue->Message->Handler->Activity/Service这样一个链条持有着,Activity就会一直无法被GC回收。

image.png

Handler导致内存泄露

我看了一篇博客说得比较容易懂,就是为了防止内存泄漏。他举了个例子,

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

但是有一句话表达的不太准确:

图片 10

TIM图片20171017195350.png

首先,图里想表的应该是「静态内部类」。
因为Java中非静态内部类可以访问外部类的成员(非静态内部类持有外部类的this引用),但静态内部类不行。至于为什么:

1 编译器自动为内部类添加一个成员变量, 这个成员变量的类型和外部类的类型相同, 这个成员变量就是指向外部类对象(this)的引用;
2 编译器自动为内部类的构造方法添加一个参数, 参数的类型是外部类的类型, 在构造方法内部使用这个参数为内部类中添加的成员变量赋值;
3 在调用内部类的构造函数初始化内部类对象时,会默认传入外部类的引用。

可以理解成静态内部类就相当于在外面写一个单独的类文件。

什么是WeakReference?

WeakReference弱引用,与强引用(即我们常说的引用)相对,它的特点是,GC在回收时会忽略掉弱引用,即就算有弱引用指向某对象,但只要该对象没有被强引用指向(实际上多数时候还要求没有软引用,但此处软引用的概念可以忽略),该对象就会在被GC检查到时回收掉。对于上面的代码,用户在关闭Activity之后,就算后台线程还没结束,但由于仅有一条来自Handler的弱引用指向Activity,所以GC仍然会在检查的时候把Activity回收掉。这样,内存泄露的问题就不会出现了。

this关键字
1.this关键字代表当前对象
this.属性 操作当前对象的属性
this.方法 调用当前对象的方法
2.封装对象的属性的时候,经常会使用this关键字

其他方法

另外,上面那篇BLOG还提到可以通过程序逻辑来防止内存泄露。

1.在关闭Activity的时候停掉你的后台线程。线程停掉了,就相当于切断了Handler和外部连接的线,Activity自然会在合适的时候被回收。
2.如果你的Handler是被delay的Message持有了引用,那么使用相应的Handler的removeCallbacks()方法,把消息对象从消息队列移除就行了。

ref:
http://blog.csdn.net/lanximu/article/details/40522367
http://blog.csdn.net/shuaishuai123485615/article/details/46708217
http://blog.csdn.net/shuaishuai123485615/article/details/46708217

版权声明:本文由美高梅开户送58元官网发布于美高梅开户送58元官网,转载请注明出处:一个Handler类的对象就不会提示,java不能函数式编