Android第三章

这章主要就是讲android的消息响应的,学Windows的时候接触了回调函数,学java的时候接触了监听器,现在Android就是把这2个集合起来罢了,没其他了。

先来看设置监听器的,无非就是组件对象setXxxx();设置监听器,在监听器类实现响应,就这样。


对于回调函数,每个组件里面都有负责处理不同事件的回调函数,我们要做的就是重写这些组件的回调函数,然后产生响应的时间,系统就会自动去调用这些回调函数了。


这样重写了回调函数之后,就不用再注册监听器就能得到响应。


还有一个问题就是顺序问题,一般都是监听器先处理---->回调函数处理----->Activity处理(这里涉及到那个处理函数最后返回的boolean值,如果是true表明时间已经完全处理好,不用再传了,如果是false就继续传下去处理)



系统响应事件:

Configuration cfg=getResources().getConfiguration();获得的配置对象包含了系统的配置信息。



cfg.orientation==ORIENTATION_LANDSCAPE?"横屏中":“竖屏中”;       像这样应用

如果系统的配置变化就会回调Activity的onConfigurationChanged()函数,所以可以在这里响应系统配置变化的操作。



如果想动态地改变横竖屏,可以调用Activity的setRequestedOrientation(int);


Handler类

最后来的是最难理解的Handler类了,首先android的UI组件都是非线程安全的,通常主线程--acticity上所有组件都在同一个线程上,我们叫这个线程做UI线程,但是当我们需要做一些耗时的操作的时候,如果也在UI线程上做,就会令UI线程不能及时响应UI组件的请求,出现ANR错误。因此一般不在UI线程上做耗时的工作,而是另起一个线程负责,但是UI组件非线程安全意味着另起的这个线程不能操纵UI组件,这个时候就需要用到Handler类了。

先来看一张图:


这图片里面涉及了几个东西:Thread  ,   Handler   ,    Looper   ,    MessageQueue   ,    Message

1.Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。对于UI线程,它是自动帮你弄好了Looper对象的,但是其他线程就需要你自己去弄,怎么弄?先Looper.prepare();   这个函数就确保当前线程只有一个Looper,除此之外还需要Looper.loop();   这个函数启动Looper,使其不断地从MessageQueue中去消息,交由handler处理。

2.Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。这里要注意的就是handler是与线程配套的,从图可以看出线程包含着handler和Looper对象,这意味着UI线程有它自己的Looper和handler,新创的子线程也有它自己的Looper和handlerde 。

3. Message Queue(消息队列):用来存放线程放入的消息。

Message:

message.arg1 = 1;  
message.arg2 = 2;  
message.obj = "Demo";  
message.what = 3;  
Bundle bundleData = new Bundle();  
bundleData.putString("Name", "Lucy");  
message.setData(bundleData);
arg1和arg2是int,obj是Object对象,这意味着这个项可以穿任意的数据了,最后的Bundle我暂时还不会用,感觉有obj这项还需要用到这个么?把所有数据包装成一个类传不就行了么?


下面是一个示例,这个示例是我自己写的,先讲讲大体上的:一个EditText叫你输入一个数字,下面是确定按钮(按下去就计算输入的数为上限的所有质数,结果显示在界面最下面的TextView中),再来一个next按钮(这个按钮控制一个ImageView,显示下一张图片),下面就是一个ImageView显示图片,在下面就是一个TextView来显示质数结果

先看看XML布局文件:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" 
        android:gravity="center_horizontal">
        <EditText 
            android:id="@+id/edittext"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输出要计算的质数的上限"/>
        <Button 
            android:id="@+id/ok_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="确定"/>
        <Button 
            android:id="@+id/next_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下一张图片"/>
        <ImageView 
            android:id="@+id/imageview"
            android:layout_width="200px"
            android:layout_height="200px"
            android:src="@drawable/a"
            android:scaleType="fitCenter"/>
        <TextView 
            android:id="@+id/show"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="结果显示在这里"/>
    </LinearLayout>
    

</ScrollView>
因为怕结果显示过长就加个ScrollView可以滚动看。
对应的java文件:

一部分一部分地来:

先处理线程无关的地方,next按钮的处理,把显示的图片全部放到数组中,按一个next就显示数组中的下一张图,循环显示:

next_btn.setOnClickListener(new View.OnClickListener()
		{
			
			@Override
			public void onClick(View arg0)
			{
				// TODO Auto-generated method stub
				imageview.setImageResource(images[index]);
				index=(index+1)%images.length;
			}
		});
完成这个部分之后再来弄子线程部分:

子线程要弄的就是为子线程弄好那张图片中的东西,包括了子线程的Looper和Handler:

class CalThread extends Thread
	{
		private Handler cal_handler;//子线程的Handler的引用
		@Override
		public void run()
		{
			// TODO Auto-generated method stub
			Looper.prepare();//先保证好子线程有1个Looper
			cal_handler=new Handler()//先写好Handler再开始拿消息
			{

				@Override
				public void handleMessage(Message msg)
				{
					// TODO Auto-generated method stub
					if(msg.what==0x123)//通过这个来辨认消息的来源
					{
						Vector<Integer> vector=new Vector<>();//用于保存求出来的质数的vector
						int limit=msg.arg1,i,j;//用msg.arg1来传递那个EditText的上限的值
						//String string=new String();
						for(i=2;i<limit;i++)
						{
							for(j=2;j<Math.sqrt(i);j++)
							{
								if(i%2==0)
									break;
							}
							if(j>=Math.sqrt(i))
							{
								vector.addElement(i);
								//string+=i+" ";
							}
						}//上面的循环来求2到上限的所有质数,结果都保存到vector中了
						try
						{
							Thread.sleep(10000);//睡眠10秒钟,在这10秒内,UI线程的换图功能仍然能使用就证明没出现ANR错误,不会影响到UI线程响应组件了
						} catch (InterruptedException e)
						{
							// TODO: handle exception
						}
						Message msg1=new Message();//封装一个0x233的消息,包含所有质数的vector的消息,发送到UI线程中
						msg1.what=0x233;
						msg1.obj=vector;
						uiHandler.sendMessage(msg1);//发送到UI线程,利用的是UI线程的Handler来发送
						Toast toast=Toast.makeText(MainActivity.this, "计算完毕", Toast.LENGTH_LONG);
						toast.show();
					}
				}
				
			};
			Looper.loop();//开启Looper取消息
		}
		
	}
在UI线程里面创这个类对象,并且start(),它就会一直利用它的线程的Looper从Looper管理的MessageQueue中提取消息,遇到0x123消息就进入处理,并且把处理结果发送到UI线程的消息队列中,并且回调UI线程的Handler来处理,所以接下来我们做的就是写UI线程的Handler:

Handler uiHandler=new Handler()
	{

		@Override
		public void handleMessage(Message msg)
		{
			// TODO Auto-generated method stub
			if(msg.what==0x233)
			{
				Vector<Integer> vector=(Vector<Integer>)msg.obj;
				String string=new String();
				for(int i=0;i<vector.size();i++)
				{
					string+=vector.elementAt(i)+" ";
				}
				show.setText(string);
			}
		}
		
	};
就这样,2个线程的双向发消息,并回调各自的Handler处理消息,子线程处理过程中还保证了UI线程能顺利响应到UI组件的要求。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值