在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個按鈕。代碼如下:
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);
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);
case 3:{
btn3.setText(name);
}}
上述代碼将每個按鍵的參數,如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,也稱為沙箱)是一種容器,所謂容器,也就是通過某種保護層之類的東西與外界隔離開。在軍事上,人們常用沙盒按照一定的比例制作地形模型以及放置代表軍隊與武器布置的模型或圖案,不用了可将沙子推倒重來。在現在的計算機領域中,沙盒是一種安全軟體,可以将一個程式放入沙盒運作,這樣它所建立、修改、删除的所有檔案和系統資料庫都會被虛拟化重定向,也就是說所有操作都是虛拟的,真實的檔案和系統資料庫不會被改動,這樣可以確定病毒無法對系統關鍵部位進行改動而破壞系統。
本文轉自 wws5201985 51CTO部落格,原文連結:http://blog.51cto.com/wws5201985/817462,如需轉載請自行聯系原作者