============问题描述============
最近在看百度地图的api demo,发现大神的写法跟屌丝的想法有所区别。他的layout里面声明了RadioGroup和CheckBox,但是根本没有在Activity类里声明这两个控件,而是直接写在方法里用id找。我不理解那几个方法是在哪里调用的,是不是通过findViewById就和主进程关联了?
public class LayersDemo extends Activity {
/**
* MapView 是地图主控件
*/
private MapView mMapView;
private BaiduMap mBaiduMap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layers);
mMapView = (MapView) findViewById(R.id.bmapView);
mBaiduMap = mMapView.getMap();
}
/**
* 设置底图显示模式
*
* @param view
*/
public void setMapMode(View view) {
boolean checked = ((RadioButton) view).isChecked();
switch (view.getId()) {
case R.id.normal:
if (checked)
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL);
break;
case R.id.statellite:
if (checked)
mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
break;
}
}
/**
* 设置是否显示交通图
*
* @param view
*/
public void setTraffic(View view) {
mBaiduMap.setTrafficEnabled(((CheckBox) view).isChecked());
}
@Override
protected void onPause() {
// MapView的生命周期与Activity同步,当activity挂起时需调用MapView.onPause()
mMapView.onPause();
super.onPause();
}
@Override
protected void onResume() {
// MapView的生命周期与Activity同步,当activity恢复时需调用MapView.onResume()
mMapView.onResume();
super.onResume();
}
@Override
protected void onDestroy() {
// MapView的生命周期与Activity同步,当activity销毁时需调用MapView.destroy()
mMapView.onDestroy();
super.onDestroy();
}
}
问题是,setMapType()和setTraffic()这两个函数为啥要传view进去,怎么传进去的,传进去如何起作用的,因为点它们确实有效果
============解决方案1============
在setTraffic(View view)插入断电、然后你可以看到以下的栈信息,因为是先进后出,执行顺序是从下面主线程的main()开始执行
LayersDemo.setMapMode(View) line: 37
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object...) line: 515
View$1.onClick(View) line: 3850
RadioButton(View).performClick() line: 4470
RadioButton(CompoundButton).performClick() line: 100
View$PerformClick.run() line: 18593
Handler.handleCallback(Message) line: 733
ViewRootImpl$ViewRootHandler(Handler).dispatchMessage(Message) line: 95
Looper.loop() line: 157
ActivityThread.main(String[]) line: 5867
执行步骤大概是:
ViewRootHandler分发消息过来,触发View的点击事件,然后得知这个View是RadioButton类型(继承View而来),接着是Method.invokeNative,这个不用管,这里面执行的是c/c++的代码,估计是百度在算法方面做跨平台节省开发成本,iOS也是用这里面的代码,重点来了,setTraffic(View view)是怎么传View的?我找到了这个代码
<CheckBox
android:id="@+id/traffice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:checked="false"
android:onClick="setTraffic"
android:text="交通图" />
也就是里面onClick="setTraffic"起的作用,Activity里面有执行setContentView(R.layout.activity_layers);这里执行的其实是一个解析xml和然后根据解析结果调用Java代码的过程,当读到<CheckBox..../>这段代码的时候就会在渲染树里面new一个CheckBox对象,当读到android:onClick="setTraffic"这句属性的时候会执行
checkBox.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
// TODO Auto-generated method stub
Activity.this.setTraffic(view);
}
})
这样就把View传进来来,其实Activity.this.setTraffic(view);也不是这么直接执行的,我这里写的就当是伪代码吧,应该是JVM虚拟机有个查找函数的机制,根据"setTraffic"这个名字去查找当前Activity的setTraffic成员函数,如果找不到这个函数执行到这里报错崩溃,希望你能理解
起初我也不懂这些机制,也是弄游戏开发后才慢慢懂得GUI框架大概的原理,以前也好奇XML是怎么表现成界面的,其实最终还是动态调用Java代码实现,搭成一棵渲染树一层层得把每个View渲染出来