导航:首页 > 操作系统 > android不能在主线程

android不能在主线程

发布时间:2022-09-26 05:30:57

① 为什么说android主线程是线程不安全的,既然不安全为什么要在主线程中更新UI,有点晕 求大师解答

UI线程及Android的单线程模型原则当应用启动,系统会创建一个主线程(main thread)。这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互。

当App做一些比较重(intensive)的工作的时候,除非合理地实现,否则单线程模型的performance会很poor。特别的是,如果所有的工作都在UI线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞UI线程,导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。

另外,Andoid UI toolkit并不是线程安全的,所以不能从非UI线程来操纵UI组件。必须把所有的UI操作放在UI线程里,所以Android的单线程模型有两条原则:
1.不要阻塞UI线程。
2.不要在UI线程之外访问Android UI toolkit(主要是这两个包中的组件:android.widget and android.view)。

② Android:在一个非主线程内直接调用UI线程的Handler实例,这样没问题吗

我们开发应用程序的时候,处于线程安全的原因子线程通常是不能直接更新主线程(UI线程)中的UI元素的,那么在Android开发中有几种方法解决这个问题,其中方法之一就是利用Handler处理的。

下面说下有关Handler相关的知识。
多线程一些基础知识回顾:
在介绍Handler类相关知识之前,我们先看看在Java中是如何创建多线程的
方法有两种:
通过继承Thread类,重写Run方法来实现
通过继承接口Runnable实现多线程

接下来让我们看看Handler是什么?如何来用

Handler是这么定义的:
主要接受子线程发送的数据, 并用此数据配合主线程更新UI.

Handler的主要作用:主要用于异步消息的处理

Handler的运行过程:
当(子线程)发出一个消息之后,首先进入一个(主线程的)消息队列,发送消息的函数即刻返回,而在主线程中的Handler逐个的在消息队列中将消息取出,然后对消息进行处理。这样就实现了跨线程的UI更新(实际上还是在主线程中完成的)。
这种机制通常用来处理相对耗时比较长的操作,如访问网络比较耗时的操作,读取文大文件,比较耗时的操作处理等。

在大白话一点的介绍它的运行过程:
启动应用时Android开启一个主线程 (也就是UI线程) , 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象(这也就是你在主线程中直接访问网络时会提示你异常的原因,如我们上篇文章所述Android主线程不能访问网络异常解决办法
)。
这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,更新UI只能在主线程中更新.。
这个时候,Handler就出现了,来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据, 这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。

接下来我们看看关于Handler都有哪些方法(它都能干什么):
其中Handler对象的一些主要方法,如下:

post(Runnable) postAtTime(Runnable,long)

postDelayed(Runnable long)

sendEmptyMessage(int)

sendMessage(Message)

sendMessageAtTime(Message,long)

sendMessageDelayed(Message,long)

正如方法名字中看到的,有两类方法:

(1)在某个主线程中执行Runnable
(2)在子线程中发送一个消息,在主线程中检测该消息处理

线程间传递Message对象的sendMessage方法和发送Runnable多线程对象的post方法。正对应着上面所说的两个特性1)、2)

下面开发个Handler实例做说明:
用post的方法执行一个Runnable对象,在该对象中随机产生一个10-100之间的随机数,赋值到UI主线程中的TextView中线程,执行5次,每次相隔5秒, 拼接每次的数字, 最后执行结果应该如:10 22 33 44 61

主要代码如下:
int i = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler.post(run);
}

Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
String s = String.valueOf(msg.what);
TextView tv = (TextView)findViewById(R.id.textView);
tv.setText(tv.getText() + ” ” + s);
}
};

Runnable run = new Runnable(){
@Override
public void run(){
Random r = new Random();
int rnum = r.nextInt((100 – 10) + 1) + 10;
handler.sendEmptyMessage(rnum);
handler.postDelayed(run, 5000);
i++;
if (i==5){
handler.removeCallbacks(run);
}
}
};

③ android 怎么执行主线程

可以。你这个问题是,android 能不能在 非主activity的 类B中,调用activity A的方法。
在B做一个activity的 变量。在B构造函数中 对context参数 保存,记得要对context 强制转换类型 变为主线程的 activity。之后在B中就能靠activity变量调用 A的方法。
不过你这个是多线程,要用synchronize做好共享数据保护工作。

④ 每个Android 都应必须了解的多线程知识点~

进程是系统调度和资源分配的一个独立单位。

在Android中,一个应用程序就是一个独立的集成,应用运行在一个独立的环境中,可以避免其他应用程序/进程的干扰。当我们启动一个应用程序时,系统就会创建一个进程(该进程是从Zygote中fork出来的,有独立的ID),接着为这个进程创建一个主线程,然后就可以运行MainActivity了,应用程序的组件默认都是运行在其进程中。开发者可以通过设置应用的组件的运行进程,在清单文件中给组件设置:android:process = "进程名";可以达到让组件运行在不同进程中的目的。让组件运行在不同的进程中,既有好处,也有坏处。我们依次的说明下。

好处:每一个应用程序(也就是每一个进程)都会有一个内存预算,所有运行在这个进程中的程序使用的总内存不能超过这个值,让组件运行不同的进程中,可以让主进程可以拥有更多的空间资源。当我们的应用程序比较大,需要的内存资源比较多时(也就是用户会抱怨应用经常出现OutOfMemory时),可以考虑使用多进程。

坏处:每个进程都会有自己的虚拟机实例,因此让在进程间共享一些数据变得相对困难,需要采用进程间的通信来实现数据的共享。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。

在Android中,线程会有那么几种状态:创建、就绪、运行、阻塞、结束。当应用程序有组件在运行时,UI线程是处于运行状态的。默认情况下,应用的所有组件的操作都是在UI线程里完成的,包括响应用户的操作(触摸,点击等),组件生命周期方法的调用,UI的更新等。因此如果UI线程处理阻塞状态时(在线程里做一些耗时的操作,如网络连接等),就会不能响应各种操作,如果阻塞时间达到5秒,就会让程序处于ANR(application not response)状态。

1.线程作用

减少程序在并发执行时所付出的时空开销,提高操作系统的并发性能。

2.线程分类

守护线程、非守护线程(用户线程)

2.1 守护线程

定义:守护用户线程的线程,即在程序运行时为其他线程提供一种通用服务
常见:如垃圾回收线程
设置方式:thread.setDaemon(true);//设置该线程为守护线程

2.2 非守护线程(用户线程)

主线程 & 子线程。

2.2.1 主线程(UI线程)

定义:Android系统在程序启动时会自动启动一条主线程
作用:处理四大组件与用户进行交互的事情(如UI、界面交互相关)
因为用户随时会与界面发生交互,因此主线程任何时候都必须保持很高的响应速度,所以主线程不允许进行耗时操作,否则会出现ANR。

2.2.2 子线程(工作线程)

定义:手动创建的线程
作用:耗时的操作(网络请求、I/O操作等)

2.3 守护线程与非守护线程的区别和联系

区别:虚拟机是否已退出,即
a. 当所有用户线程结束时,因为没有守护的必要,所以守护线程也会终止,虚拟机也同样退出
b. 反过来,只要任何用户线程还在运行,守护线程就不会终止,虚拟机就不会退出

3.线程优先级

3.1 表示

线程优先级分为10个级别,分别用Thread类常量表示。

3.2 设置

通过方法setPriority(int grade)进行优先级设置,默认线程优先级是5,即 Thread.NORM_PRIORITY。

4.线程状态

创建状态:当用 new 操作符创建一个线程的时候

就绪状态:调用 start 方法,处于就绪状态的线程并不一定马上就会执行 run 方法,还需要等待CPU的调度

运行状态:CPU 开始调度线程,并开始执行 run 方法

阻塞(挂起)状态:线程的执行过程中由于一些原因进入阻塞状态,比如:调用 sleep/wait 方法、尝试去得到一个锁等

结束(消亡)状态:run 方法执行完 或者 执行过程中遇到了一个异常

(1)start()和run()的区别

通过调用Thread类的start()方法来启动一个线程,这时此线程是处于就绪状态,并没有运行。调用Thread类调用run()方法来完成其运行操作的,方法run()称为线程体,它包含了要执行的这个线程的内容,run()运行结束,此线程终止,然后CPU再调度其它线程。

(2)sleep()、wait()、yield()的区别

sleep()方法属于Thread类,wait()方法属于Object类。
调用sleep()方法,线程不会释放对象锁,只是暂停执行指定的时间,会自动恢复运行状态;调用wait()方法,线程会放弃对象锁,进入等待此对象的等待锁定池,不调用notify()方法,线程永远处于就绪(挂起)状态。

yield()直接由运行状态跳回就绪状态,表示退让线程,让出CPU,让CPU调度器重新调度。礼让可能成功,也可能不成功,也就是说,回到调度器和其他线程进行公平竞争。

1.Android线程的原则

(1)为什么不能再主线程中做耗时操作
防止ANR, 不能在UI主线程中做耗时的操作,因此我们可以把耗时的操作放在另一个工作线程中去做。操作完成后,再通知UI主线程做出相应的响应。这就需要掌握线程间通信的方式了。 在Android中提供了两种线程间的通信方式:一种是AsyncTask机制,另一种是Handler机制。

(2)为什么不能在非UI线程中更新UI 因为Android的UI线程是非线程安全的,应用更新UI,是调用invalidate()方法来实现界面的重绘,而invalidate()方法是非线程安全的,也就是说当我们在非UI线程来更新UI时,可能会有其他的线程或UI线程也在更新UI,这就会导致界面更新的不同步。因此我们不能在非UI主线程中做更新UI的操作。

2.Android实现多线程的几种方式

3.为何需要多线程

多线程的本质就是异步处理,直观一点说就是不要让用户感觉到“很卡”。

4.多线程机制的核心是啥

多线程核心机制是Handler

推荐Handler讲解视频: 面试总被问到Handler?带你从源码的角度解读Handler核心机制

根据上方提到的 多进程、多线程、Handler 问题,我整理了一套 Binder与Handler 机制解析的学习文档,提供给大家进行学习参考,有需要的可以 点击这里直接获取!!! 里面记录许多Android 相关学习知识点。

⑤ android访问网络状态是否可在主线程中执行

是的,android2.2版本以下是可以在主线程中执行网络访问的,2.2以上就得重起一个线程了。

⑥ android toast必须在主线程吗

不能,Toast只能在 主线程 (UI线程)中使用

⑦ android代码,我无论如何也无法在主线程中等待dialog的出现

自己看看书把,在子线程中发消息出来,然后在主线程接受到消息的时候弹出dialog

⑧ android中 IO操作可以放在主线程么。为什么

Android的io操作就是需要放在主线程中,不过这个操作的过程最好放在其他的线程,这样子才不会是屏幕出现卡顿。如果你直接放在其他线程就会导致出错,android这么规定的

阅读全文

与android不能在主线程相关的资料

热点内容
如何在vps上搭建自己的代理服务器 浏览:742
nginxphp端口 浏览:403
内脏pdf 浏览:150
怎么看云服务器架构 浏览:85
我的世界国际服为什么登不进服务器 浏览:996
微盟程序员老婆 浏览:930
intellij创建java 浏览:110
java连接odbc 浏览:38
启动修复无法修复电脑命令提示符 浏览:359
手机编程是什么 浏览:98
山东移动程序员 浏览:163
苏州java程序员培训学校 浏览:477
单片机液晶驱动 浏览:855
魔拆app里能拆到什么 浏览:131
新预算法的立法理念 浏览:144
wdcpphp的路径 浏览:134
单片机p0口电阻 浏览:926
浏览器中调短信文件夹 浏览:594
五菱宏光空调压缩机 浏览:69
为什么app占用几百兆 浏览:681