android 架構分為三層:
(1)最底層是linux內核,主要是各種硬件的驅動,如相機驅動(Camera Driver),閃存驅動(Flash Memory Driver),wifi驅動(Wifi Driver)等
(2)中間一層是庫包(libraries)和android運行環境(android runtime),其中庫包主要包括一些協議和浏覽器內核(webkit)等,android運行環境主要包括核心庫包和Dalvik虛擬機
(3)最上面一層是應用層,應用層主要是跟用戶直接打交道的各種應用了,如聯系人,浏覽器,電話等.
這裡重點要注意的是dalvik虛擬機,這裡簡單的和JVM做個比較:
兩者區別:
(1)編譯後文件格式:
jvm: .java->.class->.jar
dalvik vm: .java->.class->.dex->.odex
(2)基於的架構
jvm:基於棧的架構
dalvik vm:基於寄存器的架構
注:基於寄存器的虛擬機對於更大的程序來說,在它們編譯的時候,花費的時間更短。
(3)字節碼格式
jvm:零字節地址格式
dalvik vm: 二/三地址的混合形式
注:二/三地址的混合形式執行的效率要高些,但操作需要更多的load/store指令(指令分配次數和內存訪問次數),二/三地址占內存多些,但操作更少,訪問內存執行數度是一個瓶頸.dalvik vm在編譯時優化代碼,而不是在運行時,將多個文件整合成一個,整體減少文件個數i/o操作,常量池的引入,提高類查詢的速度
2.配置filter
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
這裡對應在手機界面中生成程序圖標,對生成程序圖標這一事件進行監聽.
二.如何導入已有android項目(以apidemos為例)
1.ctrl+n==>選擇Android Sample Project
2.選擇要導入的Android sdk sample,這裡選擇2.2
3.選擇具體的sample,這裡選擇ApiDemos.
4.點擊Finish後,出現下圖所示sample
5.然後ctrl+F11運行到模擬器上.
注:如果啟動過程中出現如下類似錯誤,那麼查看項目下一個依賴包 Android Dependencies,在eclipse中右鍵這個文件夾,在Build Path選項中選擇 remove it from build path,然後ctrl+F11運行到模擬器上.
[2014-02-25 00:53:19 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
[2014-02-25 00:53:19 - HelloWorld] Conversion to Dalvik format failed: Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
與導入sample非常類似,導入其他項目,選擇Android Project form Existing Code==>項目路徑==>next===>finish即可.如下圖所示:
二、案例 android下的電話撥號器
新建一個名稱為and的android項目,以android 2.2 sdk為底包進行開發
然後一直Next直至finish
1、效果截圖
1)初始界面:
2).輸入110,點擊撥打
3)通話記錄
2、代碼分析
/and/res/layout/activity_main.xml
復制代碼
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="@+id/et_dial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:phoneNumber="true"
android:singleLine="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="54dp"
android:hint="@string/hint"
android:ems="10" >
<requestFocus />
</EditText>
<!-- 方法四 -->
<Button
android:id="@+id/bt_dial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/et_dial"
android:layout_below="@+id/et_dial"
android:onClick="dial"
android:text="撥 打" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/et_dial"
android:layout_alignParentTop="true"
android:layout_marginTop="32dp"
android:clickable="true"
android:onClick="info"
android:text="@string/info" />
</RelativeLayout>
復制代碼
注:LinearLayout (線性布局)、AbsoluteLayout(絕對布局)、RelativeLayout(相對布局)、TableLayout(表格布局)、FrameLayout(幀布局),這裡采用的是相對布局.
android:onClick="xxx" ,這裡xxx對應的是MainActivity.java中的xxx方法,當點擊時觸發此方法.
/and/res/values/strings.xml
復制代碼
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">and</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="hint">在這裡輸入手機號碼</string>
<string name="info">請輸入要撥打的手機號碼:</string>
</resources>
復制代碼
注:這裡主要用來配置一些常量,供其它程序調用.
/and/AndroidManifest.xml
復制代碼
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.amos.and"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="8" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.amos.and.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
復制代碼
注:注意權限分配問題
/and/src/com/amos/and/MainActivity.java
復制代碼
package com.amos.and;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
/**
* @ClassName: MainActivity
* @Description: android開發實例,自定義實現電話撥號器
* @author: amosli
* @email:
[email protected]
* @date 2014年2月25日 下午6:53:29
*/
public class MainActivity extends Activity implements OnClickListener{
public static String tag = "MainActivity";
//以內部成員變量的方式定義輸入框,在加載主界面的時候就把此變量加載到內存中去,避免多次加載
private EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mEditText = (EditText) MainActivity.this.findViewById(R.id.et_dial);
//得到了activity界面上的button的引用
Button button = (Button) this.findViewById(R.id.bt_dial);
/*
button.setOnClickListener(new OnClickListener() {
//方法二,使用匿名內部類的方式注冊一個onClick監聽事件
@Override
public void onClick(View arg0) {
String phonenum = mEditText.getText().toString();
Log.i(tag, phonenum);// 輸出手機號碼
Log.e(tag, "error");
Log.d(tag, "debug");
Log.v(tag, "verbose");
Log.w(tag, "warn");
System.out.println("assert:"+Log.ASSERT);
Intent intent = new Intent();// 意圖,代表要執行動作的一個意圖
// 撥打動作,110代表的是一個data
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+phonenum));
startActivity(intent);
}
});*/
//方法三:使用全局定義的switch進行事件的監聽
// button.setOnClickListener(this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//方法三:使用全局定義的switch進行事件的監聽,企業中一般常用此方法
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_dial:
String phonenum = mEditText.getText().toString();
Log.i(tag, phonenum);// 輸出手機號碼
Log.e(tag, "error");
Log.w(tag, "這是方法三");
Intent intent = new Intent();// 意圖,代表要執行動作的一個意圖
// 撥打動作,110代表的是一個data
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + phonenum));
startActivity(intent);
break;
}
;
}
public void dial(View v){
String phonenum = mEditText.getText().toString();
Log.i(tag, phonenum);// 輸出手機號碼
Log.e(tag, "error");
Log.d(tag, "debug");
Log.v(tag, "verbose");
Log.w(tag, "warn");
System.out.println("assert:"+Log.ASSERT);
Intent intent = new Intent();// 意圖,代表要執行動作的一個意圖
// 撥打動作,110代表的是一個data
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+phonenum));
startActivity(intent);
}
public void info(View v){
Log.i(tag, "提示信息被點擊了一次!") ;
}
//方法一,自定義實現OnclickListener的內部類
private class MyButtonOnClickListner implements OnClickListener {
@Override
public void onClick(View v) {
String phonenum = mEditText.getText().toString();
Log.i(tag, phonenum);// 輸出手機號碼
Log.e(tag, "error");
Log.d(tag, "debug");
Log.v(tag, "verbose");
Log.w(tag, "warn");
System.out.println("assert:"+Log.ASSERT);
Intent intent = new Intent();// 意圖,代表要執行動作的一個意圖
// 撥打動作,110代表的是一個data
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+phonenum));
startActivity(intent);
}
}
}
復制代碼
注:這裡主要實現了用戶輸入號碼後,點擊撥打按鈕後,電話撥出情形. 這裡用了四種方法去實現撥打動作,推薦第三次方法,更靈活,維護更方便,具體實現可以參見注釋.
3、實現過程中出現的問題及解決辦法
出現如下所示的提示信息:
復制代碼
02-25 18:03:45.164: E/AndroidRuntime(681): FATAL EXCEPTION: main
02-25 18:03:45.164: E/AndroidRuntime(681): java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.CALL dat=tel:xxx-xxx-xxxx cmp=com.android.phone/.OutgoingCallBroadcaster } from ProcessRecord{40592aa8 681:com.amos.and/10034} (pid=681, uid=10034) requires android.permission.CALL_PHONE
02-25 18:03:45.164: E/AndroidRuntime(681): at android.os.Parcel.readException(Parcel.java:1322)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.os.Parcel.readException(Parcel.java:1276)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:1351)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1374)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.app.Activity.startActivityForResult(Activity.java:2827)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.app.Activity.startActivity(Activity.java:2933)
02-25 18:03:45.164: E/AndroidRuntime(681): at com.amos.and.MainActivity$MyButtonOnClickListner.onClick(MainActivity.java:49)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.view.View.performClick(View.java:2485)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.view.View$PerformClick.run(View.java:9080)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.os.Handler.handleCallback(Handler.java:587)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.os.Handler.dispatchMessage(Handler.java:92)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.os.Looper.loop(Looper.java:123)
02-25 18:03:45.164: E/AndroidRuntime(681): at android.app.ActivityThread.main(ActivityThread.java:3683)
02-25 18:03:45.164: E/AndroidRuntime(681): at java.lang.reflect.Method.invokeNative(Native Method)
02-25 18:03:45.164: E/AndroidRuntime(681): at java.lang.reflect.Method.invoke(Method.java:507)
02-25 18:03:45.164: E/AndroidRuntime(681): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-25 18:03:45.164: E/AndroidRuntime(681): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-25 18:03:45.164: E/AndroidRuntime(681): at dalvik.system.NativeStart.main(Native Method)
02-25 18:03:45.214: W/ActivityManager(97): Force finishing activity com.amos.and/.MainActivity
02-25 18:03:45.814: W/ActivityManager(97): Activity pause timeout for HistoryRecord{40747168 com.amos.and/.MainActivity}
復制代碼
仔細一看是權限問題,權限是用來保護用戶隱私的,當用戶安裝應用時會提示所需要的權限