本文共 5997 字,大约阅读时间需要 19 分钟。
在OPhone平台上,捕获用户在界面上的触发事件有很多种方法。一般来讲,开发者会从用户交互的特定的View对象(例如Button、TextView等)中捕捉事件,并使用View类提供方法来实现。前文中我们分析了软件的第一个功能的构成形式,在界面方面,由按钮和菜单两部分组成,初始化代码如下:
public class CallAST extends Activity implements OnClickListener{
private Button btn1, btn2,btn3; private TextView tv; private EditText edit1,edit2; private SharedPreferences contact; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); btn1 = (Button)findViewById(R.id.Button01); btn2 = (Button)findViewById(R.id.Button02); btn3 = (Button)findViewById(R.id.Button03); contact = getSharedPreferences("contact",0); btn1.setText(contact.getString("Button01name","")); btn2.setText(contact.getString("Button02name","")); btn3.setText(contact.getString("Button03name","")); tv = (TextView)findViewById(R.id.TextView01); btn1.setOnClickListener(this); btn2.setOnClickListener(this); btn3.setOnClickListener(this); } 上述代码在界面上添加3个按钮,并从SharedPreferences中读取按钮的标题。菜单用于实现按钮标题的修改,采用BT1、BT2、BT3的菜单名称分别对应3个按钮。代码如下:@Override
public boolean onCreateOptionsMenu(Menu menu) { int i; for(i=1;i<=3;i++) menu.add(0,i,i,"BT"+Integer.toString(i)); return super.onCreateOptionsMenu(menu); } 在上述代码中,与以往程序最大的不同之处在于:在Class的声明中多了implements OnClickListener。根据MVC模式的设想,该功能用于实现(implements)单击响应的接口(interface)。在单击按钮时,软件呼叫该按钮对应的联系人号码。它的定义是:abstract void onClick(View v)
代码如下:
public void onClick(View arg0) {
String callnum=""; contact = getSharedPreferences("contact",0); if (arg0==btn1) callnum = contact.getString("Button01num",""); if (arg0==btn2) callnum = contact.getString("Button02num",""); if (arg0==btn3) callnum = contact.getString("Button03num",""); if (!(callnum.equals(""))) startActivity(new Intent( Intent.ACTION_CALL, Uri.parse("tel:"+callnum))); } 知识点:Event Listener和Event Hanlder当相应的事件在该对象上发生时,这些方法被OPhone的框架所呼叫。例如:当一个View(如一个Button)被单击,onTouchEvent方法会在该对象上被调用,为了响应该事件,我们必须extend该Class,并且override这个方法。这就是View类还包含一系列通用接口和回调的原因,以便于用户可以统一地定义和管理。这些接口(例如上面代码中的OnClickListener接口),就称为event listener,是我们捕捉用户行为的工具。
当我们使用event listener来监听用户行为时,如果确实有需要extend一个view来建立一个特定的组件,在这种情况下,你可以使用event handler来为该class定义默认的事件行为,如onKeyDown、onKeyUp、onTouchEvent、onTrackballEvent、onFocusChanged。
弹出对话框
在此之前的所有代码,都是从SharedPreferences中取出数据(按钮标题和呼叫号码),但是我们还没有看到写入数据的过程——在菜单中编辑SharedPreferences的数据。在单击菜单时,软件弹出窗口,用户在弹出的窗口中输入标题和呼叫号码。Windows使用Messagebox函数来管理对话框,在OPhone中,需要使用AlertDialog.Builder来建立对话框并实现数据的提交。在onCreate中需要新建AlertDialog.Builder对象,代码如下:
builder = new AlertDialog.Builder(this);
@Override public boolean onOptionsItemSelected(MenuItem item) { final int itid = item.getItemId(); LinearLayout layout = new LinearLayout(CallAST.this); //新建对话框布局用于放置文本框和按钮 layout.setOrientation(LinearLayout.VERTICAL); //设置控件走向 LinearLayout.LayoutParams param = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT); edit1 = new EditText(CallAST.this); edit2 = new EditText(CallAST.this); layout.addView(edit1, param); //在layout上添加文本框 layout.addView(edit2, param); builder.setView(layout); //将layout和对话框相关联 builder.setPositiveButton("OK",new DialogInterface.OnClickListener() { @Override //添加OK按钮及其响应 public void onClick(DialogInterface arg0, int arg1) { writetosp(itid,edit1.getText().toString(), edit2.getText().toString());} //将按钮标题和呼叫号码写入后台配置文件 }); builder.show(); return super.onOptionsItemSelected(item); }保存输入数据
在弹出窗口的代码中,我们对LinearLayout很熟悉,因为在main.xml的界面描述中,layout是不可缺少的元素。但是在这里,layout是作为一个界面对象存在的,开发者对layout对象进行初始化和编辑,并将其视图(View)显示在builder上。我们在前文中提到,builder是一个对话框管理器,负责对话框的界面和按钮响应。对话框的“OK”按钮调用了一个叫做writetosp的方法,该方法将对话框中的数据写入SharedPreferences,供按钮的标题和呼叫响应提取。代码如下:
private void writetosp(int spid,String name,String num){
contact = getSharedPreferences("contact",0); contact.edit().putString("Button0"+Integer.toString(spid)+ "name",name).commit(); contact.edit().putString("Button0"+Integer.toString(spid)+ "num",num).commit(); switch(spid){ case 1:{ btn1.setText(name); break; } case 2:{ btn2.setText(name); break; } case 3:{ btn3.setText(name); break; } }}上述代码将每个按键的参数,如Button01name、Button01num的形式存入SharedPreferences。在写入按键参数之后,后台的数据发生了变化,但是按钮的标题并没有更新,所以需要在后面的switch-case部分,实时更新按钮标题。在输入以上代码后,第一个功能基本完成,运行效果如图4-7所示,单击“张三”后,程序出现错误。
如何使用permission
在Debug视图中查看日志,可以看到一大串的错误信息,第一条是Permission Denial:starting Intent{action=android.intent.action. CALL data=tel: 13912345678 comp={com.android.phone/com.android.phone.InCallScreen}} from ProcessRecord{43bc7a20 1601:oms.CallAST/10040}(pid=1601,uid= 10040)requires android.permission.CALL_PHONE,如图4-8所示。
日志跟踪结果中指出:“系统不允许呼叫,需要许可证(Permission)—android. permission.CALL_PHONE”。那究竟什么是系统允许的操作,什么是系统禁止的操作?这就要涉及OPhone系统的安全许可机制。OPhone系统在默认的情况下,应用程序不允许访问可能影响操作系统或者其他应用程序的API。这些API都是敏感操作,如访问语音网络、数据网络、访问硬件等。如果开发者希望程序访问这些敏感API,必须在AndroidManifest.xml中添加请求。对于用户来说,在安装该软件时,系统会显示出敏感API的列表,可以使用户看到该软件对系统的影响,并选择是否继续安装。这和手机Java平台不同,J2ME在安装时不作提示,但是在运行时,例如访问网络时会弹出对话框询问是否允许访问网络。OPhone在程序安装时就设置好规则,让用户在使用时具备更好的体验。为了让系统允许呼叫操作,开发者需要在AndroidManifest.xml的permissions选项卡中添加安全许可,如图4-9所示。
单击“Add”按钮,选择“Uses Permission”,如图4-10所示。在右侧下拉列表中选择android.permission. CALL_PHONE,完成安全许可的添加,如图4-11所示。在AndroidManifest.xml文件的文本标签中可以看到文件多了一行“Uses Permission”。 知识点:常用Permission列举l ACCESS_FINE_LOCATION:精确位置信息获取,如GPS应用等。
l ACCESS_NETWORK_STATE/CHANGE_NETWORK_STATE:获取/改变网络状态信息。
l ACCESS_WIFI_STATE/CHANGE_WIFI_STATE:获取/改变WiFi等WLAN无线网络的状态。
l RECEIVE_MMS/RECEIVE_SMS/SEND_SMS:收彩信,收发短信。
l BATTERY_STATS:获取Android平台上电池设备信息。
l CAMERA:摄像头权限控制。
l INTERNET:访问网络。
完成Permission的添加之后,再次运行程序,单击“张三”按钮,可以看到软件界面切换至拨号界面,电话被拨出,如图4-12所示。在OPhone中,一个应用程序的进程就是一个安全的沙盒。它不能干扰其他应用程序,除非显式地声明了“Permissions”,以便它能够获取基本沙盒所不具备的额外的能力。它请求的这些权限“Permissions”可以被各种各样的操作处理,如自动允许该权限或者通过用户提示或者证书来禁止该权限。应用程序需要的那些“Permissions”是静态的,在程序中声明,所以他们会在程序安装时就被知晓,并不会再改变。
知识点:什么是沙盒?
沙盒(Sandbox,也称为沙箱)是一种容器,所谓容器,也就是通过某种保护层之类的东西与外界隔离开。在军事上,人们常用沙盒按照一定的比例制作地形模型以及放置代表军队与武器布置的模型或图案,不用了可将沙子推倒重来。在现在的计算机领域中,沙盒是一种安全软件,可以将一个程序放入沙盒运行,这样它所创建、修改、删除的所有文件和注册表都会被虚拟化重定向,也就是说所有操作都是虚拟的,真实的文件和注册表不会被改动,这样可以确保病毒无法对系统关键部位进行改动而破坏系统。