Android不阻塞的UI线程的方法

Android的UI线程至关重要,直接影响应用体验。为确保流畅,应避免阻塞UI线程并禁止非UI线程直接操作界面。遵循原则包括:不要阻塞UI线程及不在非UI线程访问UI组件。实现方式包括使用新线程执行耗时任务,如通过View.post、Activity.runOnUiThread、View.postDelayed或Handler来安全地更新UI。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android中的UI线程也是应用的主线程。顾名思义,UI线程主要负责界面的刷新与管理,向onKeyDown()这样的系统回调也都在UI线程中(主线程)中被执行。


这个线程是否在流畅的运行直接关系到当前的App的用户体验。例如:如果一个按钮被点击后会执行某个非常耗时间的操作(比如下载),那么用户单击了这个按钮后,界面会发生卡顿现象,直到这个非常耗时间的操作执行完毕界面才会恢复到能与用户交互的状态。如果用户发现他们单击了某个按钮后界面就会死掉,按哪里都没有反应,他们就会觉得你的App出了BUG,然后就很可能会卸载你的应用。


概括来讲,为了UI线程能随时对用户的操作做出反应,你应该遵循下列两个基本原则:

(1) 绝对不要阻塞UI线程

(2) 不要从UI线程以外的线程中访问UI组件。


如果你会使用线程那么第一条原则你就已经能够实现了。是的,如果想让耗时间的操作不阻塞UI线程,就要让这个操作在一个另外一个线程中运行。

例如下面的代码:

public class MainActivity extends Activity {
	private TextView textView;   //UI线程的UI组件

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		textView = (TextView) findViewById(R.id.showText);
	}

	public void onChangeText(View view) { // 界面中的一个按钮onClick()函数
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 1000000000; i++) { // 这是个很耗时的操作
				}
				textView.setText("Finished");
			}

		}).start();

	}
}


像这样通过线程来运行很耗时间的代码就可以不阻塞UI线程了。

但是上面的代码还有问题,因为它不符合第二条原则,那就是它没在UI线程中操作 textView 。


要在非UI线程中操作UI组件,可以通过下面的一些方法:

<1> View.post(Runnable)

public class MainActivity extends Activity {
	private TextView textView;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		textView = (TextView) findViewById(R.id.showText);
	}

	public void onChangeText(View view) {  //界面中的一个按钮onClick()函数
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 1000000000; i++) {   //这是个很耗时的操作
				}
				textView.post(new Runnable() {  //这样textView.setText()就会在UI线程中执行
					public void run() {
						textView.setText("123");
					}
				});
			}
		}).start();
		
	}
}

<2> Activity.runOnUiThread(Runnable)

public class MainActivity extends Activity {
	private TextView textView;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		textView = (TextView) findViewById(R.id.showText);
	}

	public void onChangeText(View view) {     //界面中的一个按钮onClick()函数
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 1000000000; i++) {   //这是个很耗时的操作
				}
				runOnUiThread(new Runnable() {     //这样textView.setText()就会在UI线程中执行
					public void run() {
						textView.setText("123");
					}
				});
			}
		}).start();
		
	}
}

<3> View.postDelayed(Runnable, long) 

View.post(Runnable)的带延迟版。


<4> 使用Handler类

public class MainActivity extends Activity {
	private TextView textView;
	private Handler handler;

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		textView = (TextView) findViewById(R.id.showText);

		handler = new Handler() {  //初始化handler
			@Override
			public void handleMessage(Message msg) { //通过handleMessage()来处理传来的消息
				if (msg.what == 1)
					textView.setText("Finished");
			}
		};
	}

	public void onChangeText(View view) { // 界面中的一个按钮onClick()函数
		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 1000000000; i++) {
				}
				Message msg = new Message();  
				msg.what = 1;
				//通过sendMessage()向handler发送一个消息,这个消息会在
				//handleMessage()中被处理
				handler.sendMessage(msg);  
			}
		}).start();
	}
}


如果转载请注明出处:http://blog.youkuaiyun.com/gophers



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值