随笔 - 224  文章 - 41  trackbacks - 0
<2010年5月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

享受编程

常用链接

留言簿(11)

随笔分类(159)

随笔档案(224)

文章分类(2)

文章档案(4)

经典c++博客

搜索

  •  

最新评论

阅读排行榜

评论排行榜

可参考下面的文章:http://www.ibm.com/developerworks/cn/opensource/os-cn-android-actvt/index.html

原文地址:http://blog.csdn.net/lihaifeng555/archive/2009/09/27/4599691.aspx

在Android里,应用程序是通过清单目录定义的。每个应用程序都是定义在AndroidManifest.xml里,其声明了其进入点(Entry Point)、通讯层(Communication Layer)、授权(Permission),以及活动(Activity)和意图(Intent)等。其中,有4个基础组件,我们称之为Android的主要组件,他们组成了丰富的Android应用程序。

Activity: Android 应用程序的UI(User Interface)基本组件。

Intent receiver: 可随时被启动来处理Intent,并执行其任务。

Service: 非UI功能的后台处理组件。

Content provider: 跨程序的共享资料之存储者。

Android vs. Java ME vs. BREW

一个BREW应用程序,在所有绝大多数情况下,是由一个单独的小程序组成,这个小程序是通过接收和发送活动与手机的其他部分通信的。另一方面,你可以将一个Java ME应用看做Midlet类的扩展。这个Midlet有启动、停止、暂停、键处理(key handling)的功能,并且可以完成任何手机和应用的交互。一个Java ME应用程序通常由一个单独的Midlet组成。

Android应用程序有许多活动,通过AndroidManifest.xml文件,这些活动可以被注册在手机中。 在面向Android的开发与面向其他手机开发工具包的开发之间,Android的multiactivity架构或许是的他们之间主要的区别。正是这个事实使编写模块化、分割的代码(modular, compartmentalized code)更容易。在BREW和Java ME中,开发人员可以执行在Midlet或小程序范围内的大部分功能。在Android中,你可以写一个活动、内容处理程序(content handler)、意图接收器(intent receiver)、或服务以应对几乎任何东西。一旦你编写了编辑文本文件的活动,通过发送和接收意向的行动,您可以引用这个活动在您将来所有编写的应用中。这个这并不是说,这种架构在BREW或Java ME中是不能实现的,他们只是必须在Java和C或C++编程的基础上,或在BREW中通过繁琐的扩展实现,而不是被平滑地集成到应用框架中。

 


Functionality

就像Midlet,活动使用了一系列的功能与外面的世界进行交换。在他的基础上,你编写的活动必须重写方法OnCreate,你还要重写其他功能,包括:onStop、onPause、onResume和onKeyDown。这几个功能可以让最大限度地将你开发的活动绑定到Android手机中。在默认情况下,在Eclipse中创建新的Android应用程序将执行一个“Hello,World”应用程序。我会告诉你如何从这个基本应用到功能齐全的画面。

如何添加图片(Image)资源

首先将图片资源(例如menu_background.jpg)直接拷贝到/res/drawable文件夹中。此时,Eclipse的Android插件(Android Plug-In)会自动将一个新的ID值添加到R.java里。所以R.java文档中会多加了一行指令如下:

public static final int menu_background=0x7f020001;

在应用程序将就用此ID值来取得这个图标文件,并显示或处理它。

如何定义XML布局 (Layout) 文件

刚才已经新增了一个图片资源文件。此时,在定义布局XML文件中,就可以引用此图片。这些布局XML文件都放在在/res/layout文件夹中,其中Eclipse的Android插件已经生成了一个main.xml文件。现在,你可利用Eclipse的 File>New>File菜单选项来生成新布局XML文件,例如:splash.xml。然后,以main.xml內容为模板,将之拷贝到新的splash.xml里,下一步移动<TextView>并且增加<ImageView>,内容如下:

<ImageView android:src="@drawable/menu_background"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ImageView>

在Android的XML布局文件里,使用@drawable/就能轻松地引用/res文件夹中的资源,例如上面的的android:src="@drawable/menu_background"。此外,layout_width和layout_height 则说明这个ImageButton显示出來的大小(Size)。splash.xml也成為一項新的資源。所以在R.java裡也會自動產生新的一行,如下:

public static final int splash=0x7f030001;


绘制启动画面

 

现在,你的初始画面被定义完成,可以激活和显示。你现有的Android活动已制定了main.xml,所以你要转移到新的初始布局。为了切换,更改OnCreate方法中的代码:

setContentView(R.layout.main);

setContentView(R.layout.splash);

运行应用程序,看着你新创建的启动画面。到目前为止,如果你得到了错误信息,检查以确认你的名字是否匹配。如果图片没有显示,确保它被正确地放置在res/rawable文件夹,并splash.xml应用了正确的名称和文件。

   

时间可以解决任何问题

 

启动屏幕开始展现,但启动画面单独作无聊的应用程序,所以你需要进入主菜单。你会使用简单的内嵌定义线程来完成的定时器,有一些常数需要在定义线程前初始化。为了看上去完整,我将包括全部的OnCreate方法。代码如下。

Code Listing 2-1. Timing the Splash Screen

long m_dwSplashTime = 3000;

boolean m_bPaused = false ;

boolean m_bSplashActive = true ;

public void onCreate(Bundle icicle)

{

super .onCreate(icicle);

//Draw the splash screen

setContentView(R.layout.splash);

//Very simple timer thread

Thread splashTimer = new Thread()

{

public void run()

{

try

{

//Wait loop

long ms = 0;

while (m_bSplashActive && ms < m_dwSplashTime)

{

sleep(100);

//Advance the timer only if we're running.

if (!m_bPaused)

ms += 100;

}

//Advance to the next screen.

startActivity(new Intent(

"com.google.app.splashy.CLEARSPLASH"));

}

catch (Exception e)

{

Log.e("Splash", e.toString());

}

finally

{

finish();

}

}

};

splashTimer.start();

}

  

到现在 , 你才开始看到一些 Java 代码。这个简单的线程直到运行时间计数器超过 m_dwSplashTime 才停止。虽然有实现一个计时器多种方式,选择这种方式有两个原因:


此计数器可以暂停。该计时器只有m_bPaused标志为false时才推动。正如你将看到在一分钟内,如果你调用活动的OnPause方法,可以方便暂停计时器。这并不总是对启动画面的需求,这对其他以时间为基础的业务是重要的。
 


移动到下一个屏幕很简单,只要改变的m_bSplashActive标记为false。推进到下一个屏幕,如果你执行这在时尚,不要求你作出的行动,然后取消更传统的计时器。
 

有了这个代码,只要你以毫秒为单位设置m_dwSplashTime,你应该看到启动画面。当时间到了或用户使用按键中断了启动画面,startActivity将被调用。finish可以关闭启动活动,使用户不必通过从主菜单上选择Back返回。你需要执行一项活动,接受CLEARSPLASH意图的行动。与此同时,让我们回顾一些其他重要活动的方法你需要重写。

 

暂停,恢复,冲洗,重复

由于呼入电话,短信或其他中断,你的活动被挂起时,暂停启动计时器,如下:

protected void onPause()

{

super.onPause();

m_bPaused = true;

}

对于这些大部分覆盖的方法 , 在做任何事情之前 , 你需要调用超类。如果你查看计时器线程,如果m_bPaused是true,你会看到负责跟踪时间的MS计数器保持时间没有前进。在这一点上,我相信你可以猜测onResume的样子:

protected void onResume()

{

super.onResume();

m_bPaused = false;

}

当你的应用程序恢复,计时器线程添加时间恢复到MS计数器。

 

基础的 Key Handling

在活动内,Key Handling是处理覆盖onKeyDown方法。我们将使用此功能允许用户取消你不完美的启动画面。正如在本节开始你看到的计时器线程,通过m_bSplashActive设置,你在计时器循环中了异常语句。为了异常处理,你只需要重写onKeyDown方法使之切换启动标记为false。下面的代码需要添加:

public boolean onKeyDown(int keyCode, KeyEvent event)

{

//if we get any key, clear the splash screen

super .onKeyDown(keyCode, event);

m_bSplashActive = false ;

return true;

}

现在 , 当用户按下任意键 , 屏幕将被推进到下一个路程通过计时器循环。

 

Clear intent

有一件事你需要在启动画面之前做 , 我相信你想知道有关 startActivity 方法调用。这里应该简单介绍一下intent。Intent是一个对象,在两个或两个以上活动、内容处理(content handlers)、意图接收器(intent receiver)、或服务之间,可以作为一个通讯事件。你会使用com.google.app.splashy.CLEARSPLASH调用 startActivity 。当startActivity被调用时,Android搜索所有配置清单文件,寻找已注册为CLEARSPLASH Intent action节点。

你要增加一个新类MainMenu,其作为主菜单activity。它要继承Activity类,实现OnCreate方法,在R.layout.main中调用setContentView方法。你要打开的AndroidManifest.xml并增加新的 activity 元素。在 </activity> 结束符之后, 你应该插入以下内容:

<activity android:name=".MainMenu"

android:label="@string/app_name">

<intent-filter>

<action android:name=

"com.google.app.splashy.CLEARSPLASH"/>

<category android:name=

"android.intent.category.DEFAULT"/>

</intent-filter>

</activity>

确定活动的名称为 .MainMenu 。这会告诉 Android 加载和运行 Java 类。在 Intent filer 标签中 , 注册为 com.apress.splash.CLEARSPLASH 的 Intent Action 。在现实中,名称意图可能是beef.funkporium.swizzle,只要名称在startActivity调用和前面的Android配置清单中一致,所有正确的事情应继续发生。

 

一项活动的生命周期

Activity的生命周期被包括在Google的文档中。但是,如果你先仔细考虑生产Activity的底层原理,你不能错过这个重要的信息。在这一点,你的启动画面,你应该准备好推出。

为了说明,我还增加了以功能在启动画面活动中:

protected void onStop()

{

super.onStop();

}

protected void onDestroy()

{

super.onDestroy();

}

如果你方断点在上面活动的所有功能,在调试模式下运行它,你会看到断点与下面顺序一致:

1. onCreate

2. onStart

3. onResume

4. 在这一点上,你的活动目前已经运行。在三秒钟内,计时器线程将达到结束,并调用startActivity结算的意图。下一步,它将调用finish,它告诉Android关闭启动画面活动。

5. onPause

6. onStop

7. onDestroy

5. onPause

6. onStop

7. onDestroy

从开始到结束 Activity , 这是一般的生命周期来。你可以找到对生命和时代的 Android 活动更全面地披露 , 在谷歌的文档活动中 http://code.google.com/android/reference/android/app/ Activity.html 。你甚至可以找到漂亮图形。从本质上讲,手机使用了以前的组合功能提醒你的主要事件可以发生在你的应用程序:启动,关闭,暂停和恢复。我已经讨论过,Activity将要成为任何传统应用的的核心组件;他们给你控制了屏幕,能够接收用户输入。

 

总结

到目前为止,我已经探讨了活动如何成在手机中,他们如何启动和停止,以及他们如何与基础层沟通。我演示了如何显示一个简单的XML视图屏幕,以及如何活性之间切换两个反应都在一个关键的事件和结束时的一个指定的时间量。在短期内,你需要了解更多有Android如何使用意向,意图接收器,过滤器和意图沟通。要做到这一点,你需要一个示例应用程序。

 

创建一个Intent Receiver

Intent Receiver是Android重要的组成部分,从它的名字可以看出其作用。它的作用是等待接收注册的Intent Action,Android是按照BREW的通知模式实现的。我们将使用一个简单的应用,展现一个复杂的Intent Receiver任务:输入文本消息的接收和响应。

 

事情的起因

我们开始设想这样一幅画面:一天下午,当你回到你的办公桌,你发现你的办公桌,从地毯到天花板与可爱的粉红色的图片,铺满最令人讨厌的图画。你知道这是谁在做,现在是你报复的时候了。你也知道你的工程部副总裁最厌恶一首特殊的歌。这首歌是 “ La Bamba “ 。让你决定通过一个休眠程序操纵你同事的Android手机。我会告诉你如何制作一个Android应用程序,收到特定的短信后,播放这种耻辱效应的音频文件。这会使你的副总对你的新敌人产生强烈的愤慨。同时,你要给他一个机会关闭声音了。这种恶作剧程序要求Intent Receiver,Activity,Service,以及所有三种方式进行通信。

   

这有什么实际的通途吗?这可能有吗?

这是一个很好的问题。虽然表面上看来不是很实用应用,我相信,如果有一点想像力,你可以发现其很多重要的现实用途:从推送电子邮件通知到内部电话应用通信。

你将向前迈进四个阶段。在每个阶段,你将了解更多关于Intent receives,services,所有这些应用程序之间的相互作用件:


通知收到一个短信
 


打开短信的内容和找到特殊的净荷
 


当短信到达Activity启动,并且意识到启动发生在接收器的控制下
 


开始一个新的服务,将播放音频文件
 

   

使用Intent Receiver

在你开始编写Intent Receiver之前,你需要了解你为什么会使用他。Intent Receriver没有或几乎没有内存占用、linkage和系统开销。在启动时,一个活动必须将所有大量的引入的类加载,Intent Receriver则没有这些约束。由于某种类型的新Intent可以达到破碎频率(例如网络状态更新),一个轻量级的对象必须在分析数据的第一阶段。如果它是一个适当的时间唤醒一个更大的用户界面程序或大幅后台服务,意图接收机应采取这种行动。

 

提示:意图接收器可以经常的启动和关闭(这依靠他们的监听),试图让它们变地重量轻,使用尽可能少的类库。你的用户不会高兴,如果他们电话在缓慢地爬行,因为你已经插入到太多特定的事件处理开销。

 

编写Intent Receiver

第一件事首先你需要创建一个这个小恶作剧应用程序建立新项目。在源目录中,创建一个新类,将成为新的Intent Receiver。在第一阶段,它看起来应该像这样:

public class PrankSMSReceiver extends IntentReceiver

{

public void onReceiveIntent

(Context context, Intent intent)

{

return;

}

}

现在你已经设定了阶级 , 你必须告诉你想要 Android 接收 SMS 事件。你可以通过修改 AndroidManifest.xml 文件给你许可和登记 RECEIVE_SMS 的 Intent action 。

 

权限

运营商,用户,甚至开发人员可能不希望给Android应用自由支配,贯穿其手机和网络的特权层。因此,谷歌推出一种被移动发人员认可的权限概念。为了能够接收短信息,你需要通知手机你可以接收。

在Android中,所有元素的权限声明在特别的配置文件中,你添加的权限在<manifest>标记后(代码2-2)。该示例应用程序将被称为PrankApp。其活动主要是rankActivity。

Code Listing 2-2. Adding Permissions to Receive SMS Messages

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android=

"http://schemas.android.com/apk/res/android"

package="com.apress.book.PrankApp">

<uses-permission android:name=

"android.permission.RECEIVE_SMS" />

没有权限标志,Android将你的应用程序无法启动当它接收到一个短信。还有其他的权限我需要涵盖你向前看。在此期间 , 你可以找到所有在列表的权限 Android 的文件资料 http://code.google.com/android/reference/android/ Manifest.permission.html 。

 

向我发送短信!

现在,你已经允许进行与手机的SMS层交互,你必须告诉手机做什么,当一个新的文本信息到达时。要做到这一点,你必须打开AndroidManifest.xml文件,添加一个新的Intent Receiver。代码清单2-3显示了要插入的代码。

Code Listing 2-3. Registering the New Intent Receiver for

Incoming SMSs

</activity>

<receiver android:name=

"PrankSMSReceiver"android:enabled="true">

<intent-filter>

<actionandroid:name="android.provider.Telephony.SMS_RECEIVED"

/>

<categoryandroid:name="android.intent.category.DEFAULT" />

</intent-filter>

</receiver>

这就是你每次必须要接受的 Intent notification , 当手机得到一个接收到的 SMS 。

 

   

在 Action 中分析 Intent Receiver

要完成这个要比我们想象的有一点困难。一个进程必须在一个 DDMS 中运行 。但在大多数情况下,你不想让应用程序运行,除非新的事件触发它。这问题的解决方案在Eclipse IDE中只是一个小小的把戏。当你一步一步往下走时,这可能会一点一点变得复杂。

在你的onReceiveIntent方法中放置一个断点。开始调试应用程序,并让模拟器位于“Hello World,PrankActivity”屏幕上。在Eclipse中,切换视图到DDMS。你可以按这命令+ F8键几次或选择菜单 Window 􀁨 Open Perspective 􀁨 DDMS 。

 

沿着左边窗口,在Device选项卡上,你现在应该看有一个绿色bug图标在你的应用旁边。这是DDMS告诉你调试器附加到你的PrankApp进程中。在它的下面是Emulator Control选项卡。在这里你可以发送短信消息。首先输入任何一个电话号码,选择SMS,键入一个测试消息,并按下Send。

 

如果你的配置正确,你应该看到Eclipse切换到Debug透视图,并停止在你的新设置断点上。

 

注意:如果没有发生,首先确保你设置了权限正确。如果他们不正确,你应该看到一个失败的权限信息显示在DDMS屏幕底部的LogCat标签中。此外,请确保你的应用程序已经在运行,并在Devices选项卡有绿色调试图标在它的旁边。如果所有这些都不奏效,比较你的项目与文中的示例。

 

目前为止,如果你正确地完成了。你的Intent的onReceiveIntent功能被调用,当每一个SMS消息发送到手机上。接下来,你就必须弄清楚如何得到短信的内容。

 

什么是在一个SMS中?

可悲的是,到目前为止Android关于接收和过滤SMS信息的文档只不过是混乱的。我怀疑这不是一项需要告诉开发人员的重要功能。我不同意这些优先事项,但是使我有机会填补空缺。

下面是methodonReceiveIntent的代码,功能是监听新的SMS信息:

public void onReceiveIntent

(Context context, Intent intent)

{

SmsMessage msg[] =

Telephony.Sms.Intents.getMessagesFromIntent(intent);

for(int i = 0; i < msg.length; i++)

{

String msgTxt = msg[i].getMessageBody();

if (msgTxt.equals("0xBADCAT0_Fire_The_Missiles!"))

{

//Start the pranking here

}

}

return;

}

你还需要输入两个类库来完成这项工作:

Import android.telephony.gsm.SmsMessage;

Import android.provider.Telephony;

getMessageFromIntent 方法是在 Telephony 类中 , 这将返回 SMS 信息的数组。现在剩下的就是得到短信的有效载荷。你要找的触发恶作剧活动的特殊代码为文本

“ 0xBADCAT0_Fire_The_Missiles ! ”

它必须是一个适当的独特组合,以便它不会被触发事故。你不会希望自己的恶作剧失火并提醒受害人太早的。

注意:在Android里,没有记载的功能是很可能还没有完成。由于接收短信的文档几乎不存在,你应该会有些变化在如何处理手机简讯上。更可能的是整体的方法应该是相似的,但它有把握地认为其中的一些细节将改变SDK的前到达它的最终版本。这个例子是有关学习如何使用意图接收器多是有关文本的消息通信资料。

 

触发活动

重要的是要记住,意图接收器的生命周期短,只有只要方法调用onReceiveIntent。一旦出于这一职能,Android是免费杀死进程中运行你的应用程序。任何异步功能会死去,如果是一个十分棘手的死亡开始。如果你想要做超越了简单的处理方法内的任何事情,你需要启动服务或活动。既然你要同时播放音乐和警报你的受害者,他们去过了,你需要启动的一项活动。你完成此情况如下:

if (msgTxt.equals("0xBADCAT0_Fire_The_Missiles!"))

{

//Start the Activity

Intent startActivity = new Intent();

startActivity.setLaunchFlags(Intent.NEW_TASK_LAUNCH);

startActivity.setAction("com.apress.START_THE_MUSIC");

context.startActivity(startActivity);

}

你会看到这里是增补 NEW_TASK_LAUNCH 在 setLaunchFlags 。你需要做任何你要发送的 Intent action , 将启动一项新的活动。此外,正如你在启动画面示例应用程序,你必须添加一个新的行动,你的Activity的Intent filter。那个过程应该看起来很熟悉:

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<action android:name="com.apress.START_THE_MUSIC" />

<category android:name=

"android.intent.category.LAUNCHER" />

<category android:name=

"android.intent.category.DEFAULT" />

</intent-filter>

现在 , 如果你在前面正确地添加了代码 , 当你从 DDMS 透视图中 发送 SMS 消息时 , 你应该看到你的应用跳出到前台 , 显示 “Hello World ,PrankActivity ” 文本在屏幕上。

 

索具的活动

一个最后的工作你需要添加 , 在得到卑鄙的音乐播放服务之前 : 装配 Activity , 以回应你的 Intent Receiver 发送的活动 。如果应用程序正常启动,你要立即关闭了。同样,如果可以通过菜单启动,这样你的恶作剧的计划就会过早的曝光。要做到这一点,你必须检索发射的Intent,并调用getAction方法来计算出在什么情况下,它已经启动。该PrankActivity的OnCreate方法现在看起来应该代码2-4。

Code Listing 2-4. Launching on a Specific Intent Action

public void onCreate(Bundle icicle)

{

super .onCreate(icicle);

Intent i = getIntent();

String action = i.getAction();

if (action != null &&

action.equals("com.apress.START_THE_MUSIC"))

{

setContentView(R.layout.pranked);

//We'll need to start the music service here

}

else

finish();

}

 

首先你会得到发起 Activity 的Intent 。使用目前得到的 Intent , 你可以用 getAction 方法检索调用的行动。这个将返回一个包含启动事件的字符串,你核对你的著名音乐行动列在原来的XML。如果在启动事件为你的活动来自正常的方式(从菜单或从启动调试器),该行动字符串将是null。如果是这样的话,你要立即使用finish方法关闭活动。

注意:OnCreate方法被调用当你的应用被首次启动时。如果你已经启动你的应用程序,然后退出(使用返回键),应用程序仍然在后台运行。如果在这时,你发送短信,你的活动将回到前台,但其OnStart方法将调用而不是OnCreat。

 

你今天想羞辱谁呢?

虽然可能有些矫枉过正,你要使用Android的service对象来处理音乐播放。我打算这样做有因为另个原因:

n         􀂃 这是一个好的机会来展示以简单的方式service的使用,在简单的环境。

n         􀂃 潜在的,它会让你启动音乐不用看到应用程序,使你的恶作剧的应用程序更卑鄙。

神经与服务

为什么你要使用的服务?从本质上讲,它意味着是一个对象,与用户界面分离的可运行地过程。这是完美的情况,当一个开发人员希望的功能(无论是网络或多媒体相关)能够独立运行。例子包括:音频播放,网络交易的后台,和邪恶的恶作剧程序。虽然服务允许多个应用程序(打开通信信道)与他们绑定,你会使用它作为一个简单的后台进程。同样,services有很多用途不只是这个简单的例子。

创建service

添加一个新类的源码包。我已经再次调用PrankService(没有点创意)。在最基本的层面,service要重写onBind方法。要获得服务类编译,它必须看,至少有一点点,如代码2-5。

Code Listing 2-5. A Stripped-Down Service

public class PrankService extends Service

{

public IBinder onBind(Intent intent)

{

return null;

}

}

在这个例子中,你不会使用该服务onBind方法进行互动。你可以简单地启动和停止服务在你的主要活动内。要做到这一点,你必须重写两个方法在服务类:

OnStart (Int startId ,Bundle argument )
onDestroy()

当OnStart被调用时,你会开始播放的媒体文件。当服务被破坏,就会明确地停止。这不是必然要求,但你会明白。

启动服务

开始一个新的服务应该类似于开始活动。自从你已经接触到这是几次,我就在给你一段代码,让你整理一下。 调用前面列出的PrankActivity OnCreate方法。简单替换注释“ We’ll need to start the music service here ”用下面的代码行:

startService(new Intent

("com.apress.START_AUDIO_SERVICE"), null );

同样,这个看上去很熟悉。启动Activity和启动service之间唯一的区别是(除了不同的方法调用)是随Intent传递bundle(实际上是一个地图或哈希表)参数的能力。这bundle将被传递到OnCreate方法服务。

启动音乐

BREW和Java一样,Android的媒体播放(简单的播放/停止计算)非常简单易用。当你服务的OnStart函数被调用,你会加载和播放/res/raw 目录中的测试音频文件首先要做的是复制音频样本文件导入/res/raw(如果没有这个目录,继续并创建它)。下一步,放下羞辱,并复制写入尊重,音频文件原始文件夹。如果你使用Eclipse,你应该添加相应的元素R.raw。在你的情况下,它的R.raw.test。

现在你有一个音乐文件的引用,你可以添加程序 PrankService 的要求如下 :

public void onStart(int startId, Bundle arguments)

{

MediaPlayer p;

super .onStart(startId, arguments);

player = MediaPlayer.create(this , R.raw.test);

player.start();

}

请记住 , 是一个重写的 OnStart 方法 , 因此你必须调用父类同一函数或 Android 将变得不稳定。在这一点上,你需要用MediaPlayer的静态类创建一个新的媒体播放器对象。因为service是context的子类,你将一个指针传递给你当前的context和静态变量代表你的测试媒体。在这一点上,你可以调用play,现在你可以开始忙了。播放会继续在后台运行,直到stopService这个方法是由你的主Activity调用。

当stopService被调用时,下面的方法将调用:

public void onDestroy()

{

super.onDestroy();

player.stop();

}

 

同情的行动

既然你是一个不错的爱开玩笑的人 , 你要给你的受害者一个台阶下。正如你之前见过的,Activity是由Intent Receiver触发的,在活动启动服务的时间点上。正如你刚才看到的,service是负责播放噪声激怒你副总工程师。同样,因为你是仁慈的在你的执行回报的同时,你必须为受害者设计关闭音乐方法。添加在你的PrankActivity下面的方法可以实现你善意的行动:

public boolean onKeyDown(int keyCode, KeyEvent event)

{

stopService(new Intent(

"com.apress.START_AUDIO_SERVICE"));

finish();

return true;

}

 

配置文件

下面是表现如下所示 :

<service android:name=".PrankService">

<intent-filter>

<action android:name=

"com.apress.START_AUDIO_SERVICE" />

<category android:name=

"android.intent.category.DEFAULT" />

</intent-filter>

</service>

 

 

禅宗和报复的艺术

通过不光明正大的小恶作剧应用程序的使用 , 你应该明白了 Intents ,Intent Receivers ,services 和Activities 如何 共同在先进的 、 主要是后台 的 应用程序中运行的。我现在要改变一下方式,一步一步做,你做了什么以及如何实现它。

让我做的更好

你做了以下内容:

1。你使用正确的权限和系统接收器的意图级短信的意图安排的对象是PrankSMSReciever每次实例化一个手机上的SMS到达。如果你的Intent Receiver发现一个非常特定的SMS的有效载荷,它将通过发送Intent将启动你的活动。

2。这项活动名为PrankActivity,会监听被PrankSMSReceiver的特定intent action。当它收到确切intent action,你的活动将显示一个“gotcha”消息给受害者。同时,该活动将发出意图旨在启动服务。如果在任何时候受害人/用户按下一个电话上的键,应用程序将退出,音乐服务将终止。

3。服务类,称为PrankService,监听PrankActivity的intent,将启动并开始播放令人讨厌,预定义的音频文件。它将继续播放,直到它被要求停止通过PrankActivity的调用方法stopService。

注意:此示例应用程序不涉及手机的本地短信应用。因为所有的intent receiver传入的通知意图,你的应用将被争夺用户与Android的关注短信收件箱的应用。在生产中,这可能需要相当计时器也许触发文本有效载荷,这是一个微妙多一点 “0xBADCAT0_Fire_The_Missiles !”

 

在Android中移动数据

最后,你需要把重点放在内容解析器。 Android不会给SDK特别的手机文件系统的访问权限,如Brew一样。它也没有提供一个RecordStore,像Java ME一样。在你的Activities、Intent  Receiver和services之间,你传递数据的主要方法是必须通过ContentResolver超类。虽然你可以存储数据通过文件,参数,和其他数据库,可以采取许多形式,Android附带的几个重要内置content resovlers。这里有一个列表,Android的主要content resovlers,你可能要经常互动基础上:


浏览器

书签
搜索历史


电话呼叫
通话记录
最近通话


联系

系统设置
硬件设置(蓝牙,网络设置)
软件设置

Android 的文档提供了非常好的示例 :http://code.google.com/android/ devel /data/contentproviders.html #usingacp 。马上我要给你演示怎样添加一个书签到手机浏览器的书签列表。首先,你要搜索当前的书签列表,查看你的链接是否存在。第二,你要添加书签,如果不存在。

 

注意:可以创建你自己的content provider,作为一种方式,为了公共访问封装Android的SQLite的执行。你将进入如何在后面的章节中这一点。现在你只是去处理content resolver交给的“client”方面。

 

Android采用了自定义的SQLite实现,来存储本地信息。如果你不熟悉SQL的基础知识,现在也许是一个学习的机会。为表述方便,我要假设你了解基本的SQL查询命令。如果你需要进一步提高,Apress上有一个很好的资源http://apress.com/book/ catalog?category=145 。

 

无耻的自我推销

让我们说一下你的应用程序中“about”部分,你想有一个按钮,添加你的商业软件网页到用户的web书签。你要确保它不添加两次,如果你的用户有再次点击该按钮意外。为了使这个实例简单,你将触发这个事件在你示例应用程序中,当用户按下一个键。

注意:在一个有趣的注意,如果你需要证明,作为一个开发人员,Android是还没有完全成熟的,你只要看看比对下文件的android.content.ContentResolver方法getDataFilePath,其中规定: “ 请不要使用此功能!有人说这一点,他们不应该。你没有直接的访问文件内的内容提供商。不要碰这个。走开。 “ 这是好,知道即使是对Android的文档技术作家有幽默感。

 

获取用户的书签

这应该是显而易见的,至少在这一点,开发人员可以做一些非常邪恶的事情,访问用户的书签。目前还不清楚,在这一点,Android会做什么以防止发生这类事情。我想这得由运营商来锁定或监视此行为。在任何情况下,你将使用一个调用方法managedQuery,它将返回一个列表用户的书签:

 

Cursor bookmarks =

android.provider.Browser.getAllBookmarks

(getContentResolver());

int urlColumn = bookmarks.getColumnIndex(

android.provider.Browser.BookmarkColumns.URL );

Cursor results;

String[] proj = new String[]

{

android.provider.BaseColumns._ID,

android.provider.Browser.BookmarkColumns.URL,

android.provider.Browser.BookmarkColumns.TITLE

};

results =

managedQuery(android.provider.Browser.BOOKMARKS_URI,

proj, null ,

android.provider.Browser.BookmarkColumns.URL

+ " ASC");

现在我将分解每一个操作。你首先要书签网址列索引。再次,因为Android通过SQL格式提供其多数内部数据的访问,你应该习惯于用数据库的方式引你保存的信息。接下来,你将设置游标,一个类似Java ME中RecordStore枚举对象,设置字符串数值的映射。因为你只关心列包含的网址,它保存非常简单。方法调用managedQuery是调用将返回你的数据。你可以通过URI中为书签存储字符串,交给你了简单的映射数值,不需要where语句,并告诉它按降序排列的网址。

 

搜索结果

搜索结果很简单只要迭代游标对象,是通过简单的光标迭代对象和退出一列从URL字符串ID你检索前 :

Cursor results =

android.provider.Browser.getAllBookmarks

(getContentResolver());

int urlColumn =

results.getColumnIndex

(android.provider.Browser.BookmarkColumns.URL);

results.first();

do

{

//url is a method param

//containing what we're looking for

if(results.getString(urlColumn).equals(url))

return false;

} while (results.next());

你可以做更多的基于 URL 的内容 , 但现在你会只是看你的 www.apress.com 链接。很明显,如果此代码的运行是上述Apress网址,你不会找到它。因为用户希望添加贵公司的网址在虚拟的“About” ” 部分中,你也要给他们。

使用Content Resolver添加邪恶公司网址

也许他们不是邪恶,但你加入他们。由于Apress也许是公司最邪恶那里(不是我有偏见,记住),你让他们摆脱它,只此一次。下面是一个美丽的ContentReceiver方式添加书签记录:

ContentValues inputValues = new ContentValues();

inputValues.put

(android.provider.Browser.BookmarkColumns.BOOKMARK,

"1");

inputValues.put

(android.provider.Browser.BookmarkColumns.URL,

"http://www.apress.com/");

inputValues.put

(android.provider.Browser.BookmarkColumns.TITLE,

"Apress, the not so evil company");

ContentResolver cr = getContentResolver();

Uri uri =

cr.insert

(android.provider.Browser.BOOKMARKS_URI,

inputValues);

想大多数软件开发工具包,有不止一种方法来完成相同的任务。早些时候,你有更复杂的方法加书签。这个方法是有用的,因为它给你一个参考如何添加元素通过ContentResolver不具有辅助功能。现在,这里的简单的方法:android.provider.Browser.saveBookmark(this,“Apress”,url);帮助函数会启动一个对话框,要求用户确认增加书签。这可能是最用户友好的方式来添加书签,除非你想控制对话框的模样。

平衡早餐的组成

在过去的三个例子你探讨了Android的所有主要构建模块。一开始你看到了实用的启动画面。这让你探索了基本知识关于启动、维护和移动通过Activity对象。这是你学习intents and interprocess/object communication迈出的第一步。使用和传递意图在活动,服务,内容处理,接收器和意图之间可能是一个最重要的事情,这是Android与其他移动环境的区别。

对于Activity和通信基础知识,你已经有了经验,你继续学习服务和意图接收器。要使用这两个组成部分,你烹调了 狡猾的 恶作剧应用程序,既能强迫你使用所有3个组建(活动,服务,和意图的接收器),使所有三个互相沟通。几乎是旁注,你研究什么需要得到通知时,短信在手机上到达。最后,你探讨如何检索和写入的内容是解析器本机设备:浏览器的书签数据库。事情的证明并非总是按计划进行,Android拒绝加入你在一个新的尝试通过传统的书签内容解析方法,该方法forcedthat我已经介绍的基本知识,现在是时候让手机用户在权衡多一点。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lihaifeng555/archive/2009/09/27/4599691.aspx

posted on 2010-05-10 20:51 漂漂 阅读(1805) 评论(0)  编辑 收藏 引用 所属分类: android 开发

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理