android菜鸟笔记之UI线程阻塞

最近在学习Android,有些还是需要记录下来,方便以后查询

首先

当一个应用程序启动之后,android系统会为这个应用程序创建一个主线程。这个线程非常重要,它负责渲染视图,分发事件到响 应监听器并执行, 对界面进行轮询的监听。因此,一般也叫做“UI”线程。android系统不会给应用程序的多个元素组件,建立多个线程来执行。一个视图(activity)中的多个view组件运行在同一个UI线程当中。因此,多个view组件的监听器的执行可能会相互影响。


例如:当在UI线程当中执行耗时操作,比如访问网络,访问数据库等。则会导致UI线程阻塞。当UI线程阻塞,则屏幕会出现卡死情况。这样用户体验非常差。当线程阻塞超过5秒以后,android系统有可能进行干预,弹出对话框询问是否关闭应用程序。


新建一个android project Application,

android菜鸟笔记之UI线程阻塞_第1张图片

打开activity_main.xml,添加button1与button2

android菜鸟笔记之UI线程阻塞_第2张图片

在MainActivity.java的onCreate中添加如下代码

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//创建动画按钮
		Button btn1 = (Button)findViewById(R.id.button1);
		TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 0);
		translateAnimation.setRepeatCount(30);//运行次数
		translateAnimation.setDuration(2000);//设置越少运动速度越快
		btn1.setAnimation(translateAnimation);
		
		Button btn2 = (Button)findViewById(R.id.button2);
		btn2.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}
启动运行,当我们点击Button2后,等待片刻后尝试再点击会出现以下

android菜鸟笔记之UI线程阻塞_第3张图片

点击OK将退出程序


Android提供了两个解决方案给我们

android的UI规则

there are simply two rules to Android's single thread model;
Do not block the UI thread
不要阻塞UI线程
Do not access the Android UI toolkit from outside the UI thread
不要在UI线程之外的其他线程中,对视图当中的组件进行设置
//经典异常:
Only the original thread that created a view hierarchy can touch its views.
只有创建view的那个线程才能对其进行修改

解决方案1:post


调整onCreate代码如下:

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//创建动画按钮
		Button btn1 = (Button)findViewById(R.id.button1);
		TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 0);
		translateAnimation.setRepeatCount(30);//运行次数
		translateAnimation.setDuration(2000);//设置越少运动速度越快
		btn1.setAnimation(translateAnimation);
		
		Button btn2 = (Button)findViewById(R.id.button2);
		btn2.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(final View v) {
				// TODO Auto-generated method stub
				
				new Thread(new Runnable(){
					
					@Override
					public void run() {
						System.out.println("线程开始");
						// TODO Auto-generated method stub
						try {
							Thread.sleep(5000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						int i = 20;
						
						v.post(new Runnable(){

							@Override
							public void run() {
								System.out.println("post线程开始");
								// TODO Auto-generated method stub
								TextView tView = (TextView)v;
								tView.setText("" + 100);
							}
							
						});
						System.out.println("线程结束");
					}
				
				}).start();
				
			}
		});
	}

在日志中看到它把修改Button2的放到了主控制之后执行,但其实Post操作还是在主线程中的,并不是新建一个线程进行操作。

而且Sleep(5000)变成了只针对Button2执行。之前是对全局进行操作。

如图:其实View.Post方式,类似于生产者与消费者的模式。每次UI线程都会在任务队列中查找一次操作,同时View.Post在里面放入自己的操作。

android菜鸟笔记之UI线程阻塞_第4张图片

以上代码相当复杂,可读性差,所以官方提供了另一个方法来处理这种问题。

解决方案2:AsyncTask

官方提供了以下片段:

private class DownloadImageTask extends AsyncTask{
/*the system calls this to perform work in a workerdelivers it the parameters given to AsyncTask.execute()*/
	protected Bitmap doInBackground(String... urls){
		return loadImageFromNetwork(urls[0]);
	}
/*The system calls this to perform work in the UI thread and delivers* the result from doInBackground()*/
	protected void onFostExecute(Bitmap result){
		mImageView.setImageBitmap(result);
	}
}

由于要写一个内部类所以需要定义全局变量

private Button btn2 = null;

修改代码如下

private Button btn2 = null;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//创建动画按钮
		Button btn1 = (Button)findViewById(R.id.button1);
		TranslateAnimation translateAnimation = new TranslateAnimation(0, 150, 0, 0);
		translateAnimation.setRepeatCount(30);//运行次数
		translateAnimation.setDuration(2000);//设置越少运动速度越快
		btn1.setAnimation(translateAnimation);
		
		btn2 = (Button)findViewById(R.id.button2);
		btn2.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(final View v) {
				// TODO Auto-generated method stub
				new ChangeButtonText().execute();
				
				
			}
		});
	}
	private class ChangeButtonText extends AsyncTask{
		protected Integer doInBackground(String... urls){
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			int i = 100;
			return i;
		}

		protected void onFostExecute(Integer result){
			btn2.setText("" + result);
		}
	}
最终结果:
android菜鸟笔记之UI线程阻塞_第5张图片

你可能感兴趣的:(android菜鸟笔记之UI线程阻塞)