1、注册广播有哪几种方式,区别?
a、在代码中注册Broadcast Receiver,影响特定Activity的UI的Brocast Receiver通常在代码中注册。在代码中注册的接收器只会在包含他的应用程序组件运行时响应Broadcast Intent。在接受器用来更新一个Activity中的UI元素时,这样做很有帮助。在这种情况下,在onResume处理程序中注册接收器,并在onPause()中销毁它是一种很好的做法。
private IntentFilter filter = new IntentFilter(LifeformDetectedReceiver.NEW_LIFEFORM);
private LifeformDetectedReceiver receiver = new LifeformDetectedReceiver();
@override
public void onResume() {
super.onResume();
//注册Brocadcast Receiver
registerReceiver(receiver, filter);
}
@override
public void onPause() {
//注销Broadcast Receiver
unregisterReceiver(receiver);
super.onPause();
}
b、在应用程序的manifest中注册Broadcast Receiver,通过这种方式注册Broadcast Receiver总是活动的,并且即使当应用程序被终止或者未启动时,也可以接收Broadcast Intent。
要在应用程序的manifest中包含一个Broadcast Receiver,可以在application节点中添加一个receiver标签,以指定要注册的Broadcast Receiver的类名。接收器节点需要包含一个Intent-filter标签来指定要监听的动作字符串。
<receiver android:name=".LifeformDetectedReceiver">
<intent-filter>
<action android:name="com.paad.alien.action.NEW_LIFEFORM"/>
</intent-filter>
</receiver>
上面的“.LifeformDetectedReceiver"实际上是一个自定义的继承BroadcastReceiver的类,intent-filter标签内的”com.padd.alien.action.NEW_LIFEFORM"则对应代码中的LifeformDetectedReceiver.NEW_LIFEFORM(这其实是LifeformDetectedReceiver类里的一个String变量)
public class MyReceiver extends BroadcastReceiver
{
@override
public void onReceive(Context context, Intent intent)
{
//避免进行耗时操作,该方法存在的时间有些说法是不超过5秒,有些则说不超过10秒
Toast.makeText(context,"接收到的Intent的Action为:" + intent.getAction() + "\n消息内容是:"
+ intent.getStringExtra("msg"), Toast.LENGTH_LONG).show();
}
}
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="org.crazyit.action.CRAZY_BROADCAST" />
</intent>
</receiver>
发送广播
Intent intent = new Intent();
intent.setAction("org.crazyit.action.CRAZY_BROADCAST");
intent.putExtra("msg","simple message");
sendBroadcast(intent);
注册方式其实与Activity和service没多大区别。
2、Service怎样与Activity实现通信
绑定Activtiy并与之通信,通过startService()和stopService()启动、关闭Service时,Service与访问者之间基本不存在太多的关联,因此Service和访问者之间也无法进行通信、数据交换。应该用bindService()和unbindService()方法启动、关闭Service,借助IBinder可实现通信和数据交换。
bindService(Intent service, ServeiceConnection conn, int flags)
service:该参数通过Intent指定要启动的Service。
conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接策划成功时将回调该ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法;如果失败,则回调onServiceDisconnected(ComponentName name)方法。
flags:指定绑定时是否自动创建Service(如果还未创建)。0,不自动创建,BIND_AUTO_CREATE,自动创建。
public class BindService extends Service
{
private MyBinder binder = new MyBinder();
......
//通过继承Binder实现IBinder类
public class MyBinder extends Binder
{
public int getCount()
{
//自定义方法具体实现
}
}
//必须实现的方法,绑定该Service时回调该方法
@override
public IBinder onBind(Intent intent)
{
//其它实现
return binder;
}
//@override
public void onCreate()
{
......
}
@override
public boolean onUnbind(Intent intent)
{
......
}
@override
public void onDestroy()
{
......
}
}
public class BindServericeTest extends Activity
{
BindServiece.MyBinder binder;
private ServiceConnection conn = new ServeiceConnection()
{
//当Activity与Service连接成功时回调该方法
@override
public void onServiceConnected(ComponentName name, IBinder service)
{
binder = (BindService.MyBinder) service;
}
@override
public void onServiceDisconnected(ComponentName name)
{
......
}
};
@override
public void onCreate(Bundle savedInstanceState)
{
......
//创建启动Service的Intent
final Intent itent = new Intent();
intent.setAction("org.crazyit.service.BIND_SERVICE");
......
//指定绑定Service
bindService(intent, conn, Service.BIND_AUTO_CREATE);
//解除绑定unbindService(conn);
}
}
3、Handler通信具体到源码是怎么实现的
Message:Handler接收和处理消息对象
Looper:每个线程只能拥有一个Looper。它的的Loop方法负责读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理。
MessageQueue:消息队列,它采用先进先出的方式来管理Message。程序创建Looper对象时会在它的构造器中创建Looper对象。Looper提供的构造器源代码如下:
private Looper()
{
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
程序在初始化Looper时会创建一个关联的MessageQueue,这个MessageQueue就负责管理消息。被Handler发送的消息必须被送到指定的MessageQueue。也就是说,如果希望Handler正常工作,必须在当前进程中有一个MessageQueue,否则消息就无法保存。所以,希望Handler正常工作,必须在当前进程有一个Looper对象,可分如下两种情况处理:
主UI线程中,系统已经初始化了一个Looper对象,因此程序直接创建Handler即可,然后就可通过Handler来发送、处理消息。
自己启动子进程,必须自己创建一个Looper对象并启动它。创建时调用它的prepare()方法即可。
public static final void prepare()
{
if(sThreadLocal.get() != null)
{
throw new RuntimeException("only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
然后调用Looper的静态loop()方法来启动它。loop()方法用一个死循环不断取出MessageQueue中的消息,交给对应的Handler进行处理。
new Thread(new Runnable() {
public Handler mHandler;
@override
public void run() {
Looper.prepare();
mHandler = new Handler();
{
@override
public void handleMessage(Message msg)
{
..........
}
};
Looper.loop();
}
}.start;
出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android只允许UI线程修改Activity里的UI组件。在实际Android应用开发中,尤其是动画的游戏开发中,需要让新启动的线程周期性地改变界面组件的属性值,这就需要Handler的消息传递机制来实现了。