Android 应用开发 2010 年 8 月 13 日
Android 平台架构 Android 环境配置和开发 Android 应用程序构成 如何开发一个例子 目录
Android 平台架构 JNI JAVA C/ 汇编
简介 Linux 核心 : Android 依赖 Linux 2.6 来 提供核心的 服务 ,例如 存储 管理、 进程 (Process) 管理等 Android Runtime : Java 语言层级的 Virtual Machine Libraries : Android 里已经 提供的 C/C++ 组 件。例如, SQLite 、 OpenGL 3D 等 。 应用 框架 (Application Framework,) : 这是结合 A pplications 和 Libraries 的主架 构 , 让 Libraries 組件能不 断 地 为 Applications 所 重复 使用 应用程序 (Applications) : 根据用户 的 期望而将 AF 的 组件 及 Libraries 组件组合 而成的 服务 。
用汉堡比喻 Android  平台架构
目录 Android 环境配置和开发 Android 平台架构 Android 应用程序构成 如何开发一个例子
如何安装  Android SDK  和 Eclipse  插件 所需开发环境 : JDK 5  或  JDK 6 ( 仅有 JRE 不够 )  Eclipse 3.5 (galileo) 下载 ADT  的 Eclipse  插件  http://dl.google.com/android/ADT-0.9.5.zip 安装  Eclipse  插件  (ADT) 启动  Eclipse ,选择  Help > Install New Software ,在出现的对话框里,点击 Add 按钮,在对话框的 name 一栏输入“ ADT” , 然后点击 Archive... ,浏览和选择已经下载的 ADT 插件 压缩文件。  点击  OK. 。返回可用软件的视图,你会看到这个插件,然后选择 Developer Tools ( 会选中下面的“ Android Developer Tools” 和 “ Android Editors“) ,点击  Next ,最后重启  Eclipse 。 下载 Android SDK : http://dl.google.com/android/android-sdk_r04-windows.zip 下载完 SDK 后,把 .zip 文件解压到你电脑上合适位置。启动  Eclipse ,选择 window->preferences ,在打开的视图左边点击 android ,在右边的 SDK Location 中选择 Android SDK 所在位置。
开发第一个 Android 应用 打开 Eclipse ,新建项目 ( 点击 File  New  Project) ,在项目列表中展开 Android 目录,选择 Android Project ,如下图:
开发第一个 Android 应用
开发第一个 Android 应用 点击” finish” 即可完成项目的创建,创建后的项目已经是一个可运行的 Android 应用,我们可以通过下面方式运行此应用: 点击工具栏上手机形状的虚拟设备管理器(简称“ AVD“ ),如下:
开发第一个 Android 应用 在打开的虚拟设备管理器中创建一个虚拟手机:
开发第一个 Android 应用 在项目上右键点击 run as   Android application ,如下图:
Android 应用程序架构 src/   java 原代码存放目录 gen/  自动生成目录 gen  目录中存放所有由 Android 开发工具自动生成的文件。目录中最重要的就是 R.java 文件。 这个文件由 Android 开发工具自动产生的。 Android 开发工具会自动根据你放入 res 目录的 xml 界面文件、图标与常量,同步更新修改 R.java 文件。正因为 R.java 文件是由开发工具自动生成的,所以我们应避免手工修改 R.java 。 R.java 在应用中起到了字典的作用,它包含了界面、图标、常量等各种资源的 id ,通过 R.java ,应用可以很方便地找到对应资源。另外编绎器也会检查 R.java 列表中的资源是否被使用到,没有被使用到的资源不会编绎进软件中,这样可以减少应用在手机占用的空间。 res /  资源 (Resource) 目录 在这个目录中我们可以存放应用使用到的各种资源,如 xml 界面文件,图片或数据。具体请看 ppt 下方备注栏。 AndroidManifest.xml   功能清单文件 这个文件列出了应用程序所提供的功能,在这个文件中,你可以指定应用程序使用到的服务 ( 如电话服务、互联网服务、短信服务、 GPS 服务等等 ) 。另外当你新添加一个 Activity 的时候,也需要在这个文件中进行相应配置,只有配置好后,才能调用此 Activity 。 default.properties   项目环境信息 ,一般是不需要修改此文件
目录 Android 环境配置和开发 Android 平台架构 Android 应用程序构成 如何开发一个例子
Android 应用程序构成 Activity Service Broadcast Receiver Content Provider Intent
Activity A visual user interface 通过 view 管理 UI 每一个有用户界面的应用至少包含一个 activity 一个应用可以有多个 activity ,其中一个作为 main activity 用于启动显示 Activity 通过 startActivity 或 startActivityForResult 启动另外的 activity
Activity 生命周期 Activity 通过 onCreate 被创建 当一个 activity 失去焦点,该 activity 将进入 pause 状态,系统在内存不足时会将其终止 当一个 activity 被另一个 activity 覆盖,该 activity 将进入 stop 状态,系统在需要内存的时候会将其终止
Intent 类似于消息、事件通知 Intent 构成: action 、 category 、 data Activity 、 Service 、 broadcast receiver 之间的桥梁 Intent activity service Broadcast receiver
Intent 两类 intent: 显式:指定具体的目标组件处理 startActivity( new Intent(ActivityLifecycle.this, AnotherActivity.class)); 隐式:由系统接受并决定如何处理 startActivity( new Intent(Intent. ACTION_DIAL));  在 AndroidManifest.xml 中定义 activity 、 service 、 broadcast receiver 接受的 intent
Intent Intent filter: action、category、data framework Component name Action Data Category intent component activity service Broadcast receiver
实例 action -- DIAL data -- tel:01038639592 action -- VIEW data -- http://www.google.cn
Service 没有 UI ,启动之后一直运行于后台 例子:音乐播放器 与应用程序的其他模块(例如 activity )一同运行于主线程中 通过 startService 或 bindService 创建 Service 通过 stopService 或 stopSelf 终止 Service 一般的,在 activity 中启动和终止 service
Service 生命周期 Context.stopService() Serivce.stopSelf() Context.startService() Context.bindService()
服务 --Service Android 中的服务和 windows 中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下: 第一步:继承 Service 类 public class SMSService extends Service { }
服务 --Service 第二步:在 AndroidManifest.xml 文件中的 <application> 节点里对服务进行配置 : <service android:name=&quot;.SMSService&quot; /> 服务不能自己运行 ,需要通过调用 Context.startService() 或 Context.bindService() 方法启动服务。这两个方法都可以启动 Service ,但是它们的使用场合有所不同。使用 startService() 方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用 bindService() 方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。 如果打算采用 Context.startService() 方法启动服务 ,在服务未被创建时,系统会先调用服务的 onCreate() 方法,接着调用 onStart() 方法。如果调用 startService() 方法前服务已经被创建, 多次调用 startService() 方法并不会导致多次创建服务 ,。 采用 startService() 方法启动的服务 ,只能调用 Context.stopService() 方法结束服务,服务结束时会调用 onDestroy() 方法。
服务 --Service 如果打算采用 Context.bindService() 方法启动服务 ,在服务未被创建时,系统会先调用服务的 onCreate() 方法,接着调用 onBind() 方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的 onUnbind() 方法,接着调用 onDestroy() 方法。如果调用 bindService() 方法前服务已经被绑定,多次调用 bindService() 方法并不会导致多次创建服务及绑定 ( 也就是说 onCreate() 和 onBind() 方法并不会被多次调用 ) 。如果调用者希望与正在绑定的服务解除绑定,可以调用 unbindService() 方法,调用该方法也会导致系统调用服务的 onUnbind()-->onDestroy() 方法。
服务 --Service 服务常用生命周期回调方法如下: onCreate()  该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次 startService() 或 bindService() 方法,服务也只被创建一次。 onDestroy() 该方法在服务被终止时调用。 与采用 Context.startService() 方法启动服务有关的生命周期方法 onStart()  只有采用 Context.startService() 方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用 startService() 方法尽管不会多次创建服务,但 onStart()  方法会被多次调用。 与采用 Context.bindService() 方法启动服务有关的生命周期方法 onBind() 只有采用 Context.bindService() 方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用 Context.bindService() 方法并不会导致该方法被多次调用。 onUnbind() 只有采用 Context.bindService() 方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
采用 startService() 启动服务 采用 Context.startService() 方法启动服务的代码如下: public class HelloActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) {  ...... Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(HelloActivity.this, SMSService.class); startService(intent); }});  } }
采用 bindService () 启动服务 采用 Context.startService() 方法启动服务的代码如下: public class HelloActivity extends Activity { ServiceConnection conn = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { } public void onServiceDisconnected(ComponentName name) { } }; @Override public void onCreate(Bundle savedInstanceState) {  Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(HelloActivity.this, SMSService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); //unbindService(conn);// 解除绑定 }});  } }
何为 Content provider 什么是 Content provider ? Content Provider  是 Android 应用程序的四大组成部分之一 是 android 中的跨应用访问数据机制 为何需要 content provider ? Android 中每一个 app 的资源是私有的 app 通过 content provider 和其他 app 共享私有数据
如何使用 content provider 通过 content resolver 访问 Context.getContentResolver() app ContentResolver ContentProvider A ContentProvider B ContentResolver ContentResolver app app
如何使用 content provider URI 定位资源 content://contacts/people content://call_log 类似关系数据库的访问方式 以二维数据表的格式暴露数据,缺省都包含 _id 字段 delete(Uri url, String where, String[] selectionArgs) insert(Uri url, ContentValues values) query (Uri uri, String[] projection, String selection,  String[] selectionArgs, String sortOrder) update(Uri uri, ContentValues values, String where,  String[] selectionArgs)
定义自己的 content provider
Android 的存储 一般的,应用程序的数据(包括文件)都是私有的 四种持久存储方式 Preferences—— 类似 properties , xml 文件 Files Database——SQLite Network
Broadcast receiver 接收和处理 android 的广播消息 Android 的广播机制 系统事件——例如变换时区、电量低等 应用程序发出广播消息: sendBroadCast 广播消息: intent android app Broadcast receiver Send broadcast
创建 Broadcast Receiver 实现一个 BroadcastReceiver public class MyAndroidReceiver extends BroadcastReceiver override onReceive(Context context, Intents Intents)  注册 BroadcastReceiver 在 AndroidManifest.xml 文件当中进行注册 在代码当中直接进行注册 <receiver Android:name=“MyAndroidReceiver&quot;> <Intents-filter> <action Android:name=”com.eoeAndroid.action.NEW_BROADCAST”/> </Intents-filter> </receiver> IntentsFilter filter = new IntentsFilter(NEW_BROADCAST ); MyAndroidReceiver MyAndroidReceiver = new MyAndroidReceiver(); registerReceiver(MyAndroidReceiver , filter);
Broadcast receiver 生命周期 Broadcast receiver 对象在 onReceive 返回后被销毁 onReceive 中不适合处理异步过程。例如弹出对话框与用户交互,可使用消息栏替代。
Android 权限控制 在 AndroidManifest.xml 中描述一个 app 的权限 例如: <manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; package=&quot;com.android.app.myapp&quot; > <uses-permission android:name=&quot;android.permission.RECEIVE_SMS&quot; /> </manifest> 权限举例 ( 参考 android.  Manifest.permission) 权限名称 权限描述 接收短信 android.permission.RECEIVE_SMS 拨打电话 android.permission.CALL_PHONE 系统启动完毕通知 android.permission.RECEIVE_BOOT_COMPLETED 读取联系人信息 android.permission.READ_CONTACTS 修改联系人信息 android.permission.WRITE_CONTACTS
目录 Android 环境配置和开发 Android 平台架构 Android 应用程序构成 如何开发一个例子
从 Internet 获取数据 利用 HttpURLConnection 对象 , 我们可以从网络中获取网页数据 . URL url = new URL(&quot;http://www.sina.com&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(6* 1000);// 设置连接超时 if (conn.getResponseCode() != 200) throw new RuntimeException(&quot; 请求 url 失败 &quot;); InputStream is = conn.getInputStream();// 得到网络返回的输入流 String result =  readData(is, &quot;GBK&quot;); conn.disconnect(); System.out.println(result); // 第一个参数为输入流 , 第二个参数为字符集编码 public static String readData(InputStream inSream, String charsetName) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while( (len = inSream.read(buffer)) != -1 ){ outStream.write(buffer, 0, len); } byte[] data = outStream.toByteArray(); outStream.close(); inSream.close(); return new String(data, charsetName); }
从 Internet 获取数据 利用 HttpURLConnection 对象 , 我们可以从网络中获取文件数据 . URL url = new URL(&quot;http://sinaapp.com/Img269812337.jpg&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(6* 1000); if (conn.getResponseCode() != 200) throw new RuntimeException(&quot; 请求 url 失败 &quot;); InputStream is = conn.getInputStream(); readAsFile(is, &quot;Img269812337.jpg&quot;);  public static void readAsFile(InputStream inSream, File file) throws Exception{ FileOutputStream outStream = new FileOutputStream(file); byte[] buffer = new byte[1024]; int len = -1; while( (len = inSream.read(buffer)) != -1 ){ outStream.write(buffer, 0, len); } outStream.close(); inSream.close(); }
向 Internet 发送请求参数 利用 HttpURLConnection 对象 , 我们可以向网络发送请求参数 . String requestUrl = &quot;http://localhost:8080/itcast/contanctmanage.do&quot;; Map<String, String> requestParams = new HashMap<String, String>(); requestParams.put(&quot;age&quot;, &quot;12&quot;); requestParams.put(&quot;name&quot;, &quot; 中国 &quot;); StringBuilder params = new StringBuilder(); for(Map.Entry<String, String> entry : requestParams.entrySet()){ params.append(entry.getKey()); params.append(&quot;=&quot;); params.append(URLEncoder.encode(entry.getValue(), &quot;UTF-8&quot;)); params.append(&quot;&&quot;); } if (params.length() > 0) params.deleteCharAt(params.length() - 1); byte[] data = params.toString().getBytes(); URL realUrl = new URL(requestUrl); HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
向 Internet 发送请求参数 conn.setDoOutput(true);// 发送 POST 请求必须设置允许输出 conn.setUseCaches(false);// 不使用 Cache conn.setRequestMethod(&quot;POST&quot;);   conn.setRequestProperty(&quot;Connection&quot;, &quot;Keep-Alive&quot;);// 维持长连接 conn.setRequestProperty(&quot;Charset&quot;, &quot;UTF-8&quot;); conn.setRequestProperty(&quot;Content-Length&quot;, String.valueOf(data.length)); conn.setRequestProperty(&quot;Content-Type&quot;,&quot;application/x-www-form-urlencoded&quot;); DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); outStream.write(data); outStream.flush(); if( conn.getResponseCode() == 200 ){ String result = readAsString(conn.getInputStream(), &quot;UTF-8&quot;); outStream.close(); System.out.println(result); }
= 向 Internet 发送 xml 数据 利用 HttpURLConnection 对象 , 我们可以向网络发送 xml 数据 . StringBuilder xml =  new StringBuilder(); xml.append(&quot;<?xml version=\&quot;1.0\&quot; encoding=\&quot;utf-8\&quot; ?>&quot;); xml.append(&quot;<M1 V=10000>&quot;); xml.append(&quot;<U I=1 D=\&quot;N73\&quot;> 中国 </U>&quot;); xml.append(&quot;</M1>&quot;); byte[] xmlbyte = xml.toString().getBytes(&quot;UTF-8&quot;); URL url = new URL(&quot;http://localhost:8080/itcast/contanctmanage.do?method=readxml&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(6* 1000); conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false);// 不使用 Cache conn.setRequestMethod(&quot;POST&quot;);   conn.setRequestProperty(&quot;Connection&quot;, &quot;Keep-Alive&quot;);// 维持长连接 conn.setRequestProperty(&quot;Charset&quot;, &quot;UTF-8&quot;); conn.setRequestProperty(&quot;Content-Length&quot;, String.valueOf(xmlbyte.length)); conn.setRequestProperty(&quot;Content-Type&quot;, &quot;text/xml; charset=UTF-8&quot;); DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); outStream.write(xmlbyte);// 发送 xml 数据 outStream.flush(); if (conn.getResponseCode() != 200) throw new RuntimeException(&quot; 请求 url 失败 &quot;); InputStream is = conn.getInputStream();// 获取返回数据 String result = readAsString(is, &quot;UTF-8&quot;); outStream.close();
HTTP 多线程断点下载应用程序   多线程下载:        
HTTP 多线程断点下载应用程序 如何才能从文件的指定位置处开始下载文件?(比如从 50MB 开始)这一点我们可以通过 HTTP 请求信息头来设置, 可以使用 HTTP 请求信息头的“ Range” 属性 。 例如:只要在请求头中加入以下代码就可以只请求部分数据:  Content-Range: bytes 20000-40000/47000 , 即从第 20000 字节请求到第 40000 个字节 ,( 文件长度是 47000 字节 )
HTTP 多线程断点下载应用程序 如何 支持断点下载。就是将下载的进度保存到文件中,但在 Android 中却不能这么做。在 Android 平台中,我们需要向文件中写出下载的文件数据, 我们 通过数据库的方式保存下载进度
谢谢!

Android应用开发简介

  • 1.
    Android 应用开发 2010年 8 月 13 日
  • 2.
    Android 平台架构 Android环境配置和开发 Android 应用程序构成 如何开发一个例子 目录
  • 3.
  • 4.
    简介 Linux 核心: Android 依赖 Linux 2.6 来 提供核心的 服务 ,例如 存储 管理、 进程 (Process) 管理等 Android Runtime : Java 语言层级的 Virtual Machine Libraries : Android 里已经 提供的 C/C++ 组 件。例如, SQLite 、 OpenGL 3D 等 。 应用 框架 (Application Framework,) : 这是结合 A pplications 和 Libraries 的主架 构 , 让 Libraries 組件能不 断 地 为 Applications 所 重复 使用 应用程序 (Applications) : 根据用户 的 期望而将 AF 的 组件 及 Libraries 组件组合 而成的 服务 。
  • 5.
  • 6.
    目录 Android 环境配置和开发Android 平台架构 Android 应用程序构成 如何开发一个例子
  • 7.
    如何安装 AndroidSDK 和 Eclipse 插件 所需开发环境 : JDK 5 或 JDK 6 ( 仅有 JRE 不够 ) Eclipse 3.5 (galileo) 下载 ADT 的 Eclipse 插件 http://dl.google.com/android/ADT-0.9.5.zip 安装 Eclipse 插件 (ADT) 启动 Eclipse ,选择 Help > Install New Software ,在出现的对话框里,点击 Add 按钮,在对话框的 name 一栏输入“ ADT” , 然后点击 Archive... ,浏览和选择已经下载的 ADT 插件 压缩文件。 点击 OK. 。返回可用软件的视图,你会看到这个插件,然后选择 Developer Tools ( 会选中下面的“ Android Developer Tools” 和 “ Android Editors“) ,点击 Next ,最后重启 Eclipse 。 下载 Android SDK : http://dl.google.com/android/android-sdk_r04-windows.zip 下载完 SDK 后,把 .zip 文件解压到你电脑上合适位置。启动 Eclipse ,选择 window->preferences ,在打开的视图左边点击 android ,在右边的 SDK Location 中选择 Android SDK 所在位置。
  • 8.
    开发第一个 Android 应用打开 Eclipse ,新建项目 ( 点击 File  New  Project) ,在项目列表中展开 Android 目录,选择 Android Project ,如下图:
  • 9.
  • 10.
    开发第一个 Android 应用点击” finish” 即可完成项目的创建,创建后的项目已经是一个可运行的 Android 应用,我们可以通过下面方式运行此应用: 点击工具栏上手机形状的虚拟设备管理器(简称“ AVD“ ),如下:
  • 11.
    开发第一个 Android 应用在打开的虚拟设备管理器中创建一个虚拟手机:
  • 12.
    开发第一个 Android 应用在项目上右键点击 run as  Android application ,如下图:
  • 13.
    Android 应用程序架构 src/ java 原代码存放目录 gen/ 自动生成目录 gen 目录中存放所有由 Android 开发工具自动生成的文件。目录中最重要的就是 R.java 文件。 这个文件由 Android 开发工具自动产生的。 Android 开发工具会自动根据你放入 res 目录的 xml 界面文件、图标与常量,同步更新修改 R.java 文件。正因为 R.java 文件是由开发工具自动生成的,所以我们应避免手工修改 R.java 。 R.java 在应用中起到了字典的作用,它包含了界面、图标、常量等各种资源的 id ,通过 R.java ,应用可以很方便地找到对应资源。另外编绎器也会检查 R.java 列表中的资源是否被使用到,没有被使用到的资源不会编绎进软件中,这样可以减少应用在手机占用的空间。 res / 资源 (Resource) 目录 在这个目录中我们可以存放应用使用到的各种资源,如 xml 界面文件,图片或数据。具体请看 ppt 下方备注栏。 AndroidManifest.xml 功能清单文件 这个文件列出了应用程序所提供的功能,在这个文件中,你可以指定应用程序使用到的服务 ( 如电话服务、互联网服务、短信服务、 GPS 服务等等 ) 。另外当你新添加一个 Activity 的时候,也需要在这个文件中进行相应配置,只有配置好后,才能调用此 Activity 。 default.properties 项目环境信息 ,一般是不需要修改此文件
  • 14.
    目录 Android 环境配置和开发Android 平台架构 Android 应用程序构成 如何开发一个例子
  • 15.
    Android 应用程序构成 ActivityService Broadcast Receiver Content Provider Intent
  • 16.
    Activity A visualuser interface 通过 view 管理 UI 每一个有用户界面的应用至少包含一个 activity 一个应用可以有多个 activity ,其中一个作为 main activity 用于启动显示 Activity 通过 startActivity 或 startActivityForResult 启动另外的 activity
  • 17.
    Activity 生命周期 Activity通过 onCreate 被创建 当一个 activity 失去焦点,该 activity 将进入 pause 状态,系统在内存不足时会将其终止 当一个 activity 被另一个 activity 覆盖,该 activity 将进入 stop 状态,系统在需要内存的时候会将其终止
  • 18.
    Intent 类似于消息、事件通知 Intent构成: action 、 category 、 data Activity 、 Service 、 broadcast receiver 之间的桥梁 Intent activity service Broadcast receiver
  • 19.
    Intent 两类 intent:显式:指定具体的目标组件处理 startActivity( new Intent(ActivityLifecycle.this, AnotherActivity.class)); 隐式:由系统接受并决定如何处理 startActivity( new Intent(Intent. ACTION_DIAL)); 在 AndroidManifest.xml 中定义 activity 、 service 、 broadcast receiver 接受的 intent
  • 20.
    Intent Intent filter:action、category、data framework Component name Action Data Category intent component activity service Broadcast receiver
  • 21.
    实例 action --DIAL data -- tel:01038639592 action -- VIEW data -- http://www.google.cn
  • 22.
    Service 没有 UI,启动之后一直运行于后台 例子:音乐播放器 与应用程序的其他模块(例如 activity )一同运行于主线程中 通过 startService 或 bindService 创建 Service 通过 stopService 或 stopSelf 终止 Service 一般的,在 activity 中启动和终止 service
  • 23.
    Service 生命周期 Context.stopService()Serivce.stopSelf() Context.startService() Context.bindService()
  • 24.
    服务 --Service Android中的服务和 windows 中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下: 第一步:继承 Service 类 public class SMSService extends Service { }
  • 25.
    服务 --Service 第二步:在AndroidManifest.xml 文件中的 <application> 节点里对服务进行配置 : <service android:name=&quot;.SMSService&quot; /> 服务不能自己运行 ,需要通过调用 Context.startService() 或 Context.bindService() 方法启动服务。这两个方法都可以启动 Service ,但是它们的使用场合有所不同。使用 startService() 方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。使用 bindService() 方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。 如果打算采用 Context.startService() 方法启动服务 ,在服务未被创建时,系统会先调用服务的 onCreate() 方法,接着调用 onStart() 方法。如果调用 startService() 方法前服务已经被创建, 多次调用 startService() 方法并不会导致多次创建服务 ,。 采用 startService() 方法启动的服务 ,只能调用 Context.stopService() 方法结束服务,服务结束时会调用 onDestroy() 方法。
  • 26.
    服务 --Service 如果打算采用Context.bindService() 方法启动服务 ,在服务未被创建时,系统会先调用服务的 onCreate() 方法,接着调用 onBind() 方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的 onUnbind() 方法,接着调用 onDestroy() 方法。如果调用 bindService() 方法前服务已经被绑定,多次调用 bindService() 方法并不会导致多次创建服务及绑定 ( 也就是说 onCreate() 和 onBind() 方法并不会被多次调用 ) 。如果调用者希望与正在绑定的服务解除绑定,可以调用 unbindService() 方法,调用该方法也会导致系统调用服务的 onUnbind()-->onDestroy() 方法。
  • 27.
    服务 --Service 服务常用生命周期回调方法如下:onCreate() 该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次 startService() 或 bindService() 方法,服务也只被创建一次。 onDestroy() 该方法在服务被终止时调用。 与采用 Context.startService() 方法启动服务有关的生命周期方法 onStart() 只有采用 Context.startService() 方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用 startService() 方法尽管不会多次创建服务,但 onStart() 方法会被多次调用。 与采用 Context.bindService() 方法启动服务有关的生命周期方法 onBind() 只有采用 Context.bindService() 方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用 Context.bindService() 方法并不会导致该方法被多次调用。 onUnbind() 只有采用 Context.bindService() 方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
  • 28.
    采用 startService() 启动服务采用 Context.startService() 方法启动服务的代码如下: public class HelloActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ...... Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(HelloActivity.this, SMSService.class); startService(intent); }}); } }
  • 29.
    采用 bindService ()启动服务 采用 Context.startService() 方法启动服务的代码如下: public class HelloActivity extends Activity { ServiceConnection conn = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { } public void onServiceDisconnected(ComponentName name) { } }; @Override public void onCreate(Bundle savedInstanceState) { Button button =(Button) this.findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { Intent intent = new Intent(HelloActivity.this, SMSService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); //unbindService(conn);// 解除绑定 }}); } }
  • 30.
    何为 Content provider什么是 Content provider ? Content Provider 是 Android 应用程序的四大组成部分之一 是 android 中的跨应用访问数据机制 为何需要 content provider ? Android 中每一个 app 的资源是私有的 app 通过 content provider 和其他 app 共享私有数据
  • 31.
    如何使用 content provider通过 content resolver 访问 Context.getContentResolver() app ContentResolver ContentProvider A ContentProvider B ContentResolver ContentResolver app app
  • 32.
    如何使用 content providerURI 定位资源 content://contacts/people content://call_log 类似关系数据库的访问方式 以二维数据表的格式暴露数据,缺省都包含 _id 字段 delete(Uri url, String where, String[] selectionArgs) insert(Uri url, ContentValues values) query (Uri uri, String[] projection, String selection,  String[] selectionArgs, String sortOrder) update(Uri uri, ContentValues values, String where,  String[] selectionArgs)
  • 33.
  • 34.
    Android 的存储 一般的,应用程序的数据(包括文件)都是私有的四种持久存储方式 Preferences—— 类似 properties , xml 文件 Files Database——SQLite Network
  • 35.
    Broadcast receiver 接收和处理android 的广播消息 Android 的广播机制 系统事件——例如变换时区、电量低等 应用程序发出广播消息: sendBroadCast 广播消息: intent android app Broadcast receiver Send broadcast
  • 36.
    创建 Broadcast Receiver实现一个 BroadcastReceiver public class MyAndroidReceiver extends BroadcastReceiver override onReceive(Context context, Intents Intents) 注册 BroadcastReceiver 在 AndroidManifest.xml 文件当中进行注册 在代码当中直接进行注册 <receiver Android:name=“MyAndroidReceiver&quot;> <Intents-filter> <action Android:name=”com.eoeAndroid.action.NEW_BROADCAST”/> </Intents-filter> </receiver> IntentsFilter filter = new IntentsFilter(NEW_BROADCAST ); MyAndroidReceiver MyAndroidReceiver = new MyAndroidReceiver(); registerReceiver(MyAndroidReceiver , filter);
  • 37.
    Broadcast receiver 生命周期Broadcast receiver 对象在 onReceive 返回后被销毁 onReceive 中不适合处理异步过程。例如弹出对话框与用户交互,可使用消息栏替代。
  • 38.
    Android 权限控制 在AndroidManifest.xml 中描述一个 app 的权限 例如: <manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; package=&quot;com.android.app.myapp&quot; > <uses-permission android:name=&quot;android.permission.RECEIVE_SMS&quot; /> </manifest> 权限举例 ( 参考 android. Manifest.permission) 权限名称 权限描述 接收短信 android.permission.RECEIVE_SMS 拨打电话 android.permission.CALL_PHONE 系统启动完毕通知 android.permission.RECEIVE_BOOT_COMPLETED 读取联系人信息 android.permission.READ_CONTACTS 修改联系人信息 android.permission.WRITE_CONTACTS
  • 39.
    目录 Android 环境配置和开发Android 平台架构 Android 应用程序构成 如何开发一个例子
  • 40.
    从 Internet 获取数据利用 HttpURLConnection 对象 , 我们可以从网络中获取网页数据 . URL url = new URL(&quot;http://www.sina.com&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(6* 1000);// 设置连接超时 if (conn.getResponseCode() != 200) throw new RuntimeException(&quot; 请求 url 失败 &quot;); InputStream is = conn.getInputStream();// 得到网络返回的输入流 String result = readData(is, &quot;GBK&quot;); conn.disconnect(); System.out.println(result); // 第一个参数为输入流 , 第二个参数为字符集编码 public static String readData(InputStream inSream, String charsetName) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while( (len = inSream.read(buffer)) != -1 ){ outStream.write(buffer, 0, len); } byte[] data = outStream.toByteArray(); outStream.close(); inSream.close(); return new String(data, charsetName); }
  • 41.
    从 Internet 获取数据利用 HttpURLConnection 对象 , 我们可以从网络中获取文件数据 . URL url = new URL(&quot;http://sinaapp.com/Img269812337.jpg&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(6* 1000); if (conn.getResponseCode() != 200) throw new RuntimeException(&quot; 请求 url 失败 &quot;); InputStream is = conn.getInputStream(); readAsFile(is, &quot;Img269812337.jpg&quot;); public static void readAsFile(InputStream inSream, File file) throws Exception{ FileOutputStream outStream = new FileOutputStream(file); byte[] buffer = new byte[1024]; int len = -1; while( (len = inSream.read(buffer)) != -1 ){ outStream.write(buffer, 0, len); } outStream.close(); inSream.close(); }
  • 42.
    向 Internet 发送请求参数利用 HttpURLConnection 对象 , 我们可以向网络发送请求参数 . String requestUrl = &quot;http://localhost:8080/itcast/contanctmanage.do&quot;; Map<String, String> requestParams = new HashMap<String, String>(); requestParams.put(&quot;age&quot;, &quot;12&quot;); requestParams.put(&quot;name&quot;, &quot; 中国 &quot;); StringBuilder params = new StringBuilder(); for(Map.Entry<String, String> entry : requestParams.entrySet()){ params.append(entry.getKey()); params.append(&quot;=&quot;); params.append(URLEncoder.encode(entry.getValue(), &quot;UTF-8&quot;)); params.append(&quot;&&quot;); } if (params.length() > 0) params.deleteCharAt(params.length() - 1); byte[] data = params.toString().getBytes(); URL realUrl = new URL(requestUrl); HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
  • 43.
    向 Internet 发送请求参数conn.setDoOutput(true);// 发送 POST 请求必须设置允许输出 conn.setUseCaches(false);// 不使用 Cache conn.setRequestMethod(&quot;POST&quot;); conn.setRequestProperty(&quot;Connection&quot;, &quot;Keep-Alive&quot;);// 维持长连接 conn.setRequestProperty(&quot;Charset&quot;, &quot;UTF-8&quot;); conn.setRequestProperty(&quot;Content-Length&quot;, String.valueOf(data.length)); conn.setRequestProperty(&quot;Content-Type&quot;,&quot;application/x-www-form-urlencoded&quot;); DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); outStream.write(data); outStream.flush(); if( conn.getResponseCode() == 200 ){ String result = readAsString(conn.getInputStream(), &quot;UTF-8&quot;); outStream.close(); System.out.println(result); }
  • 44.
    = 向 Internet发送 xml 数据 利用 HttpURLConnection 对象 , 我们可以向网络发送 xml 数据 . StringBuilder xml = new StringBuilder(); xml.append(&quot;<?xml version=\&quot;1.0\&quot; encoding=\&quot;utf-8\&quot; ?>&quot;); xml.append(&quot;<M1 V=10000>&quot;); xml.append(&quot;<U I=1 D=\&quot;N73\&quot;> 中国 </U>&quot;); xml.append(&quot;</M1>&quot;); byte[] xmlbyte = xml.toString().getBytes(&quot;UTF-8&quot;); URL url = new URL(&quot;http://localhost:8080/itcast/contanctmanage.do?method=readxml&quot;); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(6* 1000); conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false);// 不使用 Cache conn.setRequestMethod(&quot;POST&quot;); conn.setRequestProperty(&quot;Connection&quot;, &quot;Keep-Alive&quot;);// 维持长连接 conn.setRequestProperty(&quot;Charset&quot;, &quot;UTF-8&quot;); conn.setRequestProperty(&quot;Content-Length&quot;, String.valueOf(xmlbyte.length)); conn.setRequestProperty(&quot;Content-Type&quot;, &quot;text/xml; charset=UTF-8&quot;); DataOutputStream outStream = new DataOutputStream(conn.getOutputStream()); outStream.write(xmlbyte);// 发送 xml 数据 outStream.flush(); if (conn.getResponseCode() != 200) throw new RuntimeException(&quot; 请求 url 失败 &quot;); InputStream is = conn.getInputStream();// 获取返回数据 String result = readAsString(is, &quot;UTF-8&quot;); outStream.close();
  • 45.
    HTTP 多线程断点下载应用程序 多线程下载:       
  • 46.
    HTTP 多线程断点下载应用程序 如何才能从文件的指定位置处开始下载文件?(比如从50MB 开始)这一点我们可以通过 HTTP 请求信息头来设置, 可以使用 HTTP 请求信息头的“ Range” 属性 。 例如:只要在请求头中加入以下代码就可以只请求部分数据: Content-Range: bytes 20000-40000/47000 , 即从第 20000 字节请求到第 40000 个字节 ,( 文件长度是 47000 字节 )
  • 47.
    HTTP 多线程断点下载应用程序 如何支持断点下载。就是将下载的进度保存到文件中,但在 Android 中却不能这么做。在 Android 平台中,我们需要向文件中写出下载的文件数据, 我们 通过数据库的方式保存下载进度
  • 48.

Editor's Notes

  • #4 Android 框架分为四层: kernel 、 libraries 、 framework 、 applications 1. 最低层是 linux kernel ,主要负责内存管理、进程调度等系统管理以及终端的硬件驱动。 Binder driver , google 为 android 设计的一个增强系统的进程间通信能力的模块。 2. Kernel 的上一层是 libraries ,包含了核心库、第三方库和 android 虚拟机。 android 并没有直接采用传统的 j2se 或 j2me 的 java 虚拟机,而是自己建立了一个称为 dalvik 的虚拟机,号称更节省字节码的空间,性能更好。但这也成为了 google 与 sun 关于 java 版权争议点。 以上两层是采用 C 语言或汇编语言实现的。 3. Framework 是 android 为应用开发者设计的一套软件框架,提供了丰富的 api 和一些现成的开发元素。 Framework 是采用 java 语言实现的。在 NDK 出来之前, android 应用开发者基本上只能用 java 来开发应用。 Android 使用 JNI( Java Native Interface ) 连接了 libraries 和 framework 。 4. Application 就是在 framework 的基础上开发的各种应用。 以上是 android 系统的总体框架。
  • #14 res/drawable 专门存放 png 、 jpg 等图标文件。在代码中使用 getResources().getDrawable(resourceId) 获取该目录下的资源。 res/layout 专门存放 xml 界面文件, xml 界面文件和 HTML 文件一样,主要用于显示用户操作界面。 res/values 专门存放应用使用到的各种类型数据。不同类型的数据存放在不同的文件中,如下: · strings.xml 定义字符串和数值,在 Activity 中使用 getResources().getString(resourceId) 或 getResources().getText(resourceId) 取得资源。它的作用和 struts 中的国际化资源文件一样。 &lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&gt; &lt;resources&gt; &lt;string name=“itcast”&gt;****&lt;/string&gt; &lt;/resources&gt; · arrays.xml 定义数组。 &lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&gt; &lt;resources&gt; &lt;string-array name=&amp;quot;colors&amp;quot;&gt; &lt;item&gt;red&lt;/item&gt; &lt;item&gt;yellow&lt;/item&gt; &lt;item&gt;green&lt;/item&gt; &lt;item&gt;blue&lt;/item&gt; &lt;/string-array&gt; &lt;/resources&gt; · colors.xml 定义颜色和颜色字串数值,你可以在 Activity 中使用 getResources().getDrawable(resourceId) 以及 getResources().getColor(resourceId) 取得这些资源。例子如下: &lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&gt; &lt;resources&gt; &lt;color name=&amp;quot;contents_text&amp;quot;&gt;#ff000000&lt;/color&gt; &lt;/resources&gt; · dimens.xml 定义尺寸数据,在 Activity 中使用 getResources().getDimension(resourceId) 取得这些资源 &lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&gt; &lt;resources&gt; &lt;dimen name=&amp;quot;key_height&amp;quot;&gt;50dip&lt;/dimen&gt; &lt;/resources&gt; · styles.xml 定义样式。 &lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&gt; &lt;resources&gt; &lt;style name=&amp;quot;itcastText&amp;quot; parent=&amp;quot;@style/Text&amp;quot;&gt; &lt;item name=&amp;quot;android:textSize&amp;quot;&gt;18px&lt;/item&gt; &lt;item name=&amp;quot;android:textColor&amp;quot;&gt;#008&lt;/item&gt; &lt;/style&gt; &lt;/resources&gt; res/anim/ 编译成帧动画的 XML 文件。 res/xml/ 在 Activity 中使用 getResources().getXML() 读取该目录下的 XML 资源文件。 res/raw/ 该目录下的文件将直接被复制到设备上。编译软件时,这些数据不会被编译,它们被直接加入到程序安装包里。 为了在程序中使用这些资源,你可以调用 getResources().openRawResource(ID) , 参数 ID 形式: R.raw. somefilename 。
  • #16 下面具体看看一个 android 应用程序的框架。 包含了 5 个部分: activity , service , intent , broadcast receiver , content provider
  • #18 当 activity 处于 pause 或者 stop 状态时,都可能被系统终止并回收。因此,有必要在 onPause 和 onStop 方法中将应用程序运行过程中的一些状态,例如用户输入等,保存到持久存储中。如果程序中启动了其他后台线程,也需要注意在这些方法中进行一些处理,例如在线程中打开了一个进度条对话框,如果不在 pause 或 stop 中 cancel 掉线程,则当线程运行完 cancel 掉对话框时就会抛出异常。 Project : ActivityLifecycle
  • #19 Intent 可以理解为应用程序向系统表达的一种意愿 : 希望系统做什么。 一个 Activity 可以通过 intent 来启动另外的 activity 或 service 实例,或者通过 intent 来发起一个广播。 Service 可以通过 intent 来启动一个 activity 或另一个 service 实例,也可以通过 intent 发起一个广播。 Broadcast receiver 通过获取 intent 取得其关注的广播消息。
  • #20 显式的,应用程序向系统发出 intent ,指明需要哪一个 component 处理。 隐式的,应用程序向系统发出一个 intent ,但没有具体指明该 intent 的接收者,由系统匹配最合适的接收者负责处理。如果存在多个匹配,那么系统会弹出对话框给用户选择处理的应用。 系统如何知道哪些 component 可以处理哪些 intent ?在 androidmanifest.xml 文件中定义 intent-filter
  • #21 Filter 分三类, action 、 category 、 data 在 filter 中定义相关的匹配规则,告知系统对应的 component 可以接受哪些 intent
  • #22 ACTION_CALL 拨出 Data 里指定的电话号码 ACTION_EDIT 打开编辑 Data 里指定数据相对应的应用程序 ACTION_MAIN 主程序入口,不会接收数据,结束后也不返回数据 ACTION_SYNC 在 Android 平台和服务器之间同步数据 ACTION_VIEW 根据 Data 类型的不同,打开相对应的应用程序以显示数据 ACTION_DIAL 启动 Dialer 或其他拨号程序,并显示 Data 里指定的电话号码 ACTION_SENDTO 向 Data 里描述的目标地址发送数据 ACTION_TIME_TICK 系统时间每过一分钟发出的广播 ACTION_TIME_CHANGED 系统时间通过设置发生了变化 ACTION_TIMEZONE_CHANGED 时区改变 ACTION_BOOT_COMPLETED 系统启动完毕 ACTION_PACKAGE_ADDED 新的应用程序 apk 包安装完毕 ACTION_PACKAGE_CHANGED 现有应用程序 apk 包改变 ACTION_PACKAGE_REMOVED 现有应用程序 apk 包被删除 ACTION_UID_REMOVED 用户 id 被删除
  • #24 一个 service 也有其生命周期,从创建到启动,到最后的撤销。 上一页 ppt 提到两种创建 service 的方法, startService 或者 bindService ,他们的区别就在于, startService 是创建并启动 service ,而 bindService 只是创建了一个 service 实例并取得了一个与该 service 关联的 binder 对象,但没有启动它。 Project: local service controller
  • #31 在 android 中,系统对资源和数据的管理机制是这样的: 每一个应用的资源是私有的,如果应用本身没有开放这些资源,其他应用是无法访问到这些资源的。 Android 通过将每一个应用视为一个 linux 用户来实现这一机制。 那么,如果一个应用希望它所拥有的资源和数据可以被其他应用使用,那么就需要通过 content provider 来对外提供访问接口。
  • #32 如何使用 content provider ? Android 使用了 content resolver 和 uri 数据表示方式,提供对 content provider 的统一访问。 应用在使用 content resolver 访问需要的数据时,系统 content resolver 根据传入的 uri ,定位到该 uri 对应的 content provider ,完成相应的操作。 Content provider 提供了一种类似于数据库二维表的数据展现和访问方式。 从图中也可以看到,一个 content provider 被注册之后,它就可以被所有的应用通过 content resolver 访问了。
  • #33 Content resolver 如何定位具体要访问哪个 content provider 呢? Android 使用 uri 来定位资源,即 content resolver 依靠 uri 来找到要访问的 content provider 。 两个例子:通信录联系人的 uri ,第二个是通话记录的 uri 。 Android 提供了一种类似数据库访问的方式来使用 content resolver ,并且以二维表的形式表现访问的数据。
  • #35 Preference 提供了一种轻量级的存取机制,主要是可以通过关键字读取和存储某个 Preference value, 比如载系统启动的时候得到上次系统退出时候保存的值。 File 机制你可以直接存储一个文件到你手机文件系统路径比如 SD 卡中 Network 通过网络来存储数据,使用下面两个包的 java class. java.net.*    android.net.* 
  • #38 Android 在接收到一个广播 intent 之后,找到了处理该 intent 的 broadcast receiver ,创建一个对象来处理 intent 。 然后,调用被创建的 broadcast receiver 对象的 onReceive 方法进行处理,然后就撤销这个对象。 需要注意的是,对象在 onReceive 方法返回之后就被撤销,所以在 onReceive 方法中不宜处理异步的过程。
  • #39 有时候我们的应用需要使用一些系统提供的能力,例如拨打电话,接收短信等。这时我们就需要向系统申请使用这些能力的权限了。 android 通过在 androidmanifest 文件中申明一系列的 &lt;uses-permission&gt; 来向应用程序开放指定的权限。