Hi_Amos
坚持每天都在进步!!

一.基础知识点学习

  1.Android体系结构

如图所示,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:amosli@infomorrow.com
* @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}

仔细一看是权限问题,权限是用来保护用户隐私的,当用户安装应用时会提示所需要的权限

解决方法如下图所示:添加一个permission: <uses-permission android:name="android.permission.CALL_PHONE"/>

 然后保存即可。

 

 

4.将开发好apk安装到自己手机上

从项目bin目录下拷贝apk文件,我这里是: D:\develop\and\bin\and.apk,安装过程中会发现有提示信息说应用会拨打电话。

 

5.关于调试项目 

选择项目==>鼠标右键,Debug As -->Android Application==>在要调试的地方加上断点,即可.

如果要调试真机,而非模拟器,如果出现不能调试的问题,那么,可以参见下图配置:

AndroidManifest.xml-->Application-->Debuggable-->true ,然后保存即可。

 

 

 

6.本文源码:

https://github.com/amosli/android.git

 

 

 

posted on 2014-02-25 23:33  Hi_Amos  阅读(1566)  评论(1编辑  收藏  举报