??xml version="1.0" encoding="utf-8" standalone="yes"?>
ADB全称Android Debug Bridge, 是android sdk里的一个工? 用这个工具可以直接操作管理android模拟器或者真实的andriod讑֤(如G1手机).
它的主要功能?
•q行讑֤的shell(命o?
•理模拟器或讑֤的端口映?
•计算机和讑֤之间上传/下蝲文g
•本地apk软g安装x拟器或android讑֤
ADB是一?客户?服务器端 E序, 其中客户端是你用来操作的电脑, 服务器端是android讑֤.
先说安装Ҏ, 电脑上需要安装客L. 客户端包含在sdk? 讑֤上不需要安? 只需要在手机上打开选项settings-applications-development-USB debugging.
对于Mac和Linux用户, 下蝲好的sdk解压? 可以放~或者Q意目? 然后修改~/.bash_profile文g, 讄q行环境指向sdk的tools目录.
具体是打开~/.bash_profile文g(如果没有此文件也可以自行d), 在里面加入一?
export PATH=${PATH}:<你的sdk目录>/tools
例如Q?/p>
然后可以用adb命o?
嫌安装麻烦的同学其实也可以省M面安装步? 直接输入完整路径来用命? 例如:
对于windows xp用户, 需要先安装usb驱动, 然后如果你只打算使用adb而不想下载整个sdk的话, 可以下蝲q个单独的adb工具?下蝲后解? 把里?adb.exe ?AdbWinApi.dll 两个文g攑ֈpȝ盘的 windows/system32 文g多w可以了.
现在说下ADB常用的几个命?br>1. 查看讑֤
•adb devices
q个命o是查看当前连接的讑֤, q接到计机的android讑֤或者模拟器会列出昄
2. 安装软g
•adb install <apk文g路径>
q个命o指定的apk文g安装到设备上
3. 卸蝲软g
•adb uninstall <软g?gt;
•adb uninstall -k <软g?gt;
如果?-k 参数,为卸载Y件但是保留配|和~存文g.
4. d讑֤shell
•adb shell
•adb shell <command命o>
q个命o登录设备的shell.
后面?lt;command命o>是直接q行讑֤命o, 相当于执行远E命?/p>
5. 从电脑上发送文件到讑֤
•adb push <本地路径> <q程路径>
用push命o可以把本机电脑上的文件或者文件夹复制到设?手机)
6. 从设备上下蝲文g到电?
•adb pull <q程路径> <本地路径>
用pull命o可以把设?手机)上的文g或者文件夹复制到本机电?/p>
7. 昄帮助信息
•adb help
q个命o显C帮助信?/p>
8. 更多android命o使用Ҏ,请参考我的另一博?android命o实战手册
先简单说说Widget的原理。Widget是在桌面上的一块显CZ息的东西Q也通过单击Widget跌{C个程序里面。?span class=t_tag onclick=tagshow(event) href="tag.php?name=%E7%B3%BB%E7%BB%9F">pȝ自带的程序,典型的Widget是musicQ这个Android内置的音?span class=t_tag onclick=tagshow(event) href="tag.php?name=%E6%92%AD%E6%94%BE">播放程序。这个是典型的Widget+app应用。就是一个程序既可以通过Widget启动Q也可以通过App启动。Widget是一个AppWidgetProvider+一个UI界面昄Q预先绑定了好多IntentQ,界面上的信息可以通过E序控制而改变,单击WidgetQ上?span class=t_tag onclick=tagshow(event) href="tag.php?name=%E6%8E%A7%E4%BB%B6">控g只能Ȁ发发送一个IntentQ或发出一?span class=t_tag onclick=tagshow(event) href="tag.php?name=Service">Service的启动通知。而AppWidgetProvider可以拦截q个IntentQ而进行相应的处理Q比如显C新的信息)?/p> 我们先来看看AndroidManifest.xml中的代码Q?br>
q个是Widget的显C?span class=t_tag onclick=tagshow(event) href="tag.php?name=%E8%AE%BE%E7%BD%AE">讄Q是对Widget属性的一个配|文件这个android:minHeight是Widget的高Q这个android:minWidth
是Widget的宽。这个android:updatePeriodMillis属性是讄Widget面?br>更新面的时间的频率。而这个android:initialLayout属性是表示的是初始化页面的布局QAndroid里画UI的地斚w是通过xml文gQ也可以通过代码E序来画Q不q这L的太ȝ了?/p>
Z个类BatteryMonitorl承于AppWidgetProviderQ而AppWidgetProviderl承与android.content.BroadcastReceiverQ所以TestAppWidget是一个拦截处理Intent的BroadcastReceiverQ这些Intent只能在Androidmainfest里设|来拦截处理?br>在onUpdate中设|窗口界面:
对于adb shellQ后面可以跟的命令主要来自android-1.5\system\core\toolbox里面Q如下:
ls
mount
cat
ps
kill
ln
insmod
rmmod
lsmod
ifconfig
setconsole
rm
mkdir
rmdir
reboot
getevent
sendevent
date
wipe
sync
umount
start
stop
notify
cmp
dmesg
route
hd
dd
df
getprop
setprop
watchprops
log
sleep
renice
printenv
smd
chmod
chown
mkdosfs
netstat
ioctl
mv
schedtop
top
iftop
id
vmstat
具体的意思就不解释了Q大家可以去看linux手册或者看android的源码。需要说一下的是ps命o,很多时候我们想只列丑և我们需要的q程列表Q例如列丑և所有运行的app。从ps的源码来看,它是支持filter的,ps app应该可以列D出所有以app开头的q程Q但在某些手机里面运行时q个filter又是没用的,可能是这些手Z改了ps的代码?/p>
q有两个比较好用的命令是adb shell am和adb shell pm,q两个命令在frameworks/base/cmds下面。am命o主要用于理ActivityQ例如启动,停止ActivityQeclipse在运行Activity׃用了q个命oQ,发送intentQpm命o则主要用于管理应用package的管理,有点像控刉板的d和删除程序?/p>
am命o的具体用法如下:
usage: am [start|broadcast|instrument|profile]
am start -D INTENT
am broadcast INTENT
am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]
[-w] <COMPONENT>
am profile <PROCESS> [start <PROF_FILE>|stop]
INTENT is described with:
[-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]
[-c <CATEGORY> [-c <CATEGORY>] ...]
[-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]
[--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]
[-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]
[-n <COMPONENT>] [-f <FLAGS>] [<URI>]
The start command starts activity. Use -D option to make 'DebugOption' true.
The broadcast command sends broadcast.
The instrument command starts instrumentation.
Use -r option to make 'rawMode' true.
Use -e option to add the pair of ARG_NAME and ARG_VALUE into Bundle.
Use -p option to specify profileFile.
Use -w option to make 'wait' true in order to new an instance of InstrumentationWatcher.
Use COMPONENT to specify the name of the instrumentation component.
The profile command turn on/off profiling in a particular process specified by PROCESS.
Use start option to turn on and stop to turn off.Use PROF_FILE to specify the file path of profile.
Use -a to set action specified by ACTION to be performed.
Use -d to create a Uri(data) which parses the given encoded URI string DATA_URI.
Use -t to specify the type specified by MIME_TYPE. Use -c to add a new category specified by
CATEGORY to the intent.
Use -e or --es to add extended data to the intent.EXTRA_KEY specifies the name of the extra data and
EXTRA_STRING_VALUE specifies the string data value.
Use --ez to add extended data to the intent. EXTRA_KEY specifies the name of the extra data and
EXTRA_BOOLEAN_VALUE specifies the serializable data value.
Use -e or --ei to add extended data to the intent. EXTRA_KEY specifies the name of the extra data and
EXTRA_INT_VALUE specifies the serializable data value.
Use -n to explicitly set the component specified by COMPONENT to handle the intent.
Use -f to set special flags controlling how this intent is handled.FLAGS specifies the desired flags.
Use URI to create an intent from a URI.
pm命o的具体用法如下:
usage: pm [list|path|install|uninstall]
pm list packages [-f]
pm list permission-groups
pm list permissions [-g] [-f] [-d] [-u] [GROUP]
pm list instrumentation [-f] [TARGET-PACKAGE]
pm path PACKAGE
pm install [-l] [-r] PATH
pm uninstall [-k] PACKAGE
pm enable PACKAGE_OR_COMPONENT
pm disable PACKAGE_OR_COMPONENT
The list packages command prints all packages. Use
the -f option to see their associated file.
The list permission-groups command prints all known
permission groups.
The list permissions command prints all known
permissions, optionally only those in GROUP. Use
the -g option to organize by group. Use
the -f option to print all information. Use
the -s option for a short summary. Use
the -d option to only list dangerous permissions. Use
the -u option to list only the permissions users will see.
The list instrumentation command prints all instrumentations,
or only those that target a specified package. Use the -f option
to see their associated file.
The path command prints the path to the .apk of a package.
The install command installs a package to the system. Use
the -l option to install the package with FORWARD_LOCK. Use
the -r option to reinstall an exisiting app, keeping its data.
The uninstall command removes a package from the system. Use
the -k option to keep the data and cache directories around
after the package removal.
The enable and disable commands change the enabled state of
a given package or component (written as "package/class").
frameworks/base/cmds下面q有一个别的命?如下
dumpstate
dumpsys
ime
input
installd
runtime
service
servicemanager
surfaceflinger
svc
system_server
下面是上q命令的一些输出:
C:\Users\xufan>adb shell dumpstate
========================================================
== dumpstate
========================================================
------ MEMORY INFO ------
MemTotal: 94348 kB
MemFree: 9912 kB
Buffers: 0 kB
Cached: 47876 kB
SwapCached: 0 kB
Active: 47016 kB
Inactive: 29980 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 29156 kB
Mapped: 22948 kB
Slab: 2992 kB
SReclaimable: 796 kB
SUnreclaim: 2196 kB
PageTables: 2180 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 47172 kB
Committed_AS: 658548 kB
VmallocTotal: 876544 kB
VmallocUsed: 8380 kB
VmallocChunk: 859132 kB
------ CPU INFO ------
User 7%, System 23%, IOW 0%, IRQ 0%
User 11 + Nice 0 + Sys 33 + Idle 98 + IOW 0 + IRQ 0 + SIRQ 0 = 142
PID TID CPU% S VSS RSS UID Thread Proc
743 743 26% R 928K 384K shell top top
565 581 1% S 177876K 25384K system er.ServerThread system_server
565 570 0% S 177876K 25384K system Binder Thread # system_server
565 571 0% S 177876K 25384K system Binder Thread # system_server
605 605 0% S 105820K 17540K radio app_process com.android.phone
565 619 0% S 177876K 25384K system er$SensorThread system_server
565 585 0% S 177876K 25384K system PackageManager system_server
565 586 0% S 177876K 25384K system FileObserver system_server
565 589 0% S 177876K 25384K system SyncHandlerThre system_server
565 590 0% S 177876K 25384K system UEventObserver system_server
565 591 0% S 177876K 25384K system PowerManagerSer system_server
565 592 0% S 177876K 25384K system AlarmManager system_server
565 593 0% S 177876K 25384K system WindowManager system_server
565 594 0% S 177876K 25384K system InputDeviceRead system_server
565 595 0% S 177876K 25384K system WindowManagerPo system_server
565 596 0% S 177876K 25384K system InputDispatcher system_server
565 597 0% S 177876K 25384K system ConnectivityThr system_server
565 598 0% S 177876K 25384K system WifiService system_server
565 599 0% S 177876K 25384K system WifiWatchdogThr system_server
565 600 0% S 177876K 25384K system er.ServerThread system_server
565 601 0% S 177876K 25384K system GpsEventThread system_server
565 602 0% S 177876K 25384K system AudioService system_server
565 603 0% S 177876K 25384K system android:unnamed system_server
565 604 0% S 177876K 25384K system android:unnamed system_server
565 609 0% S 177876K 25384K system watchdog system_server
565 640 0% S 177876K 25384K system r.MountListener system_server
565 651 0% S 177876K 25384K system Binder Thread # system_server
565 678 0% S 177876K 25384K system Binder Thread # system_server
605 606 0% S 105820K 17540K radio HeapWorker com.android.phone
605 607 0% S 105820K 17540K radio Signal Catcher com.android.phone
------ PROCRANK ------
C:\Users\xufan>adb shell dumpsys
Provider mms-sms
ContentProviderRecord{436a0040 com.android.providers.telephony.MmsSmsProvide
r}
package=com.android.providers.telephony process=com.android.phone
app=ProcessRecord{43638990 605:com.android.phone/1001}
launchingApp=null
provider=android.content.ContentProviderProxy@436c8c88
name=mms-sms
isSyncable=false
multiprocess=true initOrder=0 uid=1001
clients=[]
externals=0
Published content providers (by class):
Provider android.content.SyncProvider
ContentProviderRecord{435bceb8 android.content.SyncProvider}
package=android process=system
app=ProcessRecord{436236b8 565:system/1000}
launchingApp=null
provider=android.content.ContentProvider$Transport@43634c48
name=sync
isSyncable=false
multiprocess=false initOrder=0 uid=1000
clients=[]
externals=0
Provider com.android.providers.telephony.MmsSmsProvider
ContentProviderRecord{436a0040 com.android.providers.telephony.MmsSmsProvide
r}
package=com.android.providers.telephony process=com.android.phone
app=ProcessRecord{43638990 605:com.android.phone/1001}
launchingApp=null
provider=android.content.ContentProviderProxy@436c8c88
name=mms-sms
isSyncable=false
multiprocess=true initOrder=0 uid=1001
clients=[]
externals=0
Provider com.android.providers.settings.SettingsProvider
ContentProviderRecord{435bda90 com.android.providers.settings.SettingsProvid
er}
package=com.android.providers.settings process=system
app=ProcessRecord{436236b8 565:system/1000}
launchingApp=null
provider=android.content.ContentProvider$Transport@435a2b58
name=settings
isSyncable=false
multiprocess=false initOrder=100 uid=1000
clients=[ProcessRecord{4371bad0 655:com.android.alarmclock/10000}, ProcessRe
cord{43638990 605:com.android.phone/1001}]
externals=0
Provider com.android.providers.userdictionary.UserDictionaryProvider
ContentProviderRecord{436a2398 com.android.providers.userdictionary.UserDict
ionaryProvider}
package=com.android.providers.userdictionary process=android.process.acore
app=ProcessRecord{43645bc0 608:android.process.acore/10004}
launchingApp=null
provider=android.content.ContentProviderProxy@436ccca0
name=user_dictionary
isSyncable=false
multiprocess=false initOrder=0 uid=10004
clients=[]
externals=0
Provider com.android.providers.contacts.ContactsProvider
ContentProviderRecord{436a25e8 com.android.providers.contacts.ContactsProvid
er}
package=com.android.providers.contacts process=android.process.acore
app=ProcessRecord{43645bc0 608:android.process.acore/10004}
launchingApp=null
provider=android.content.ContentProviderProxy@436cd910
name=contacts;call_log
isSyncable=false
multiprocess=false initOrder=0 uid=10004
clients=[]
externals=0
Provider com.android.providers.drm.DrmProvider
ContentProviderRecord{4361c528 com.android.providers.drm.DrmProvider}
package=com.android.providers.drm process=android.process.media
app=ProcessRecord{436e89e8 644:android.process.media/10003}
launchingApp=null
provider=android.content.ContentProviderProxy@435ffed0
name=drm
isSyncable=false
multiprocess=false initOrder=0 uid=10003
clients=[]
externals=0
Provider com.android.launcher.LauncherProvider
ContentProviderRecord{436a2710 com.android.launcher.LauncherProvider}
package=com.android.launcher process=android.process.acore
app=ProcessRecord{43645bc0 608:android.process.acore/10004}
launchingApp=null
provider=android.content.ContentProviderProxy@436cdff0
name=com.android.launcher.settings
isSyncable=false
multiprocess=false initOrder=0 uid=10004
clients=[]
externals=0
Provider com.android.providers.media.MediaProvider
ContentProviderRecord{436e8728 com.android.providers.media.MediaProvider}
package=com.android.providers.media process=android.process.media
app=ProcessRecord{436e89e8 644:android.process.media/10003}
launchingApp=ProcessRecord{436e89e8 644:android.process.media/10003}
provider=android.content.ContentProviderProxy@435ff638
name=media
isSyncable=false
multiprocess=false initOrder=0 uid=10003
clients=[]
externals=0
Provider com.android.providers.downloads.DownloadProvider
ContentProviderRecord{4369e808 com.android.providers.downloads.DownloadProvi
der}
package=com.android.providers.downloads process=android.process.media
app=ProcessRecord{436e89e8 644:android.process.media/10003}
launchingApp=null
provider=android.content.ContentProviderProxy@43600a50
name=downloads
isSyncable=false
multiprocess=false initOrder=0 uid=10003
clients=[]
externals=0
Provider com.android.providers.telephony.MmsProvider
ContentProviderRecord{436a0f28 com.android.providers.telephony.MmsProvider}
package=com.android.providers.telephony process=com.android.phone
app=ProcessRecord{43638990 605:com.android.phone/1001}
launchingApp=null
provider=android.content.ContentProviderProxy@436c93a8
name=mms
isSyncable=false
multiprocess=true initOrder=0 uid=1001
clients=[]
externals=0
Provider com.android.googlesearch.SuggestionProvider
ContentProviderRecord{436a24c0 com.android.googlesearch.SuggestionProvider}
package=com.android.googlesearch process=android.process.acore
app=ProcessRecord{43645bc0 608:android.process.acore/10004}
launchingApp=null
provider=android.content.ContentProviderProxy@436cd288
name=com.android.googlesearch.SuggestionProvider
isSyncable=false
multiprocess=false initOrder=0 uid=10004
clients=[]
externals=0
Provider com.android.providers.telephony.TelephonyProvider
ContentProviderRecord{436a1030 com.android.providers.telephony.TelephonyProv
ider}
package=com.android.providers.telephony process=com.android.phone
app=ProcessRecord{43638990 605:com.android.phone/1001}
launchingApp=null
provider=android.content.ContentProviderProxy@436c9988
name=telephony
isSyncable=false
multiprocess=true initOrder=0 uid=1001
clients=[]
externals=0
Provider com.android.providers.telephony.SmsProvider
ContentProviderRecord{436a1138 com.android.providers.telephony.SmsProvider}
package=com.android.providers.telephony process=com.android.phone
app=ProcessRecord{43638990 605:com.android.phone/1001}
launchingApp=null
provider=android.content.ContentProviderProxy@436ca038
name=sms
isSyncable=false
multiprocess=true initOrder=0 uid=1001
clients=[]
externals=0
Provider com.android.phone.SimProvider
ContentProviderRecord{436a1240 com.android.phone.SimProvider}
package=com.android.phone process=com.android.phone
app=ProcessRecord{43638990 605:com.android.phone/1001}
launchingApp=null
provider=android.content.ContentProviderProxy@436ca648
name=sim
isSyncable=false
multiprocess=true initOrder=0 uid=1001
clients=[]
externals=0
Provider com.android.alarmclock.AlarmProvider
ContentProviderRecord{4371d520 com.android.alarmclock.AlarmProvider}
package=com.android.alarmclock process=com.android.alarmclock
app=ProcessRecord{4371bad0 655:com.android.alarmclock/10000}
launchingApp=null
provider=android.content.ContentProviderProxy@435e2c10
name=com.android.alarmclock
isSyncable=false
multiprocess=false initOrder=0 uid=10000
clients=[]
externals=0
Granted Uri Permissions:
-------------------------------------------------------------------------------
DUMP OF SERVICE activity.senders:
Intent Senders in Current Activity Manager State:
IntentSender IntentSenderRecord{435bb968 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=android.content.syncmanager.SYNC_ALARM }
sent=false canceled=false
IntentSender IntentSenderRecord{4359f4e0 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=android.intent.action.DATE_CHANGED }
sent=false canceled=false
IntentSender IntentSenderRecord{43638b10 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=com.android.service.Watchdog.REBOOT }
sent=false canceled=false
IntentSender IntentSenderRecord{436714c0 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=com.android.server.WifiManager.action.DEVICE_I
DLE }
sent=false canceled=false
IntentSender IntentSenderRecord{435e56d8 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=android.intent.action.TIME_TICK flags=0x400000
00 }
sent=true canceled=false
IntentSender IntentSenderRecord{435adb08 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=android.content.syncmanager.SYNC_POLL_ALARM }
sent=true canceled=false
IntentSender IntentSenderRecord{4359edf0 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { action=com.android.service.Watchdog.CHECKUP }
sent=false canceled=false
IntentSender IntentSenderRecord{436e3198 android broadcastIntent}
packageName=android type=broadcastIntent flags=0x0
activity=null who=null
requestCode=0 requestResolvedType=null
requestIntent=Intent { }
sent=false canceled=false
-------------------------------------------------------------------------------
DUMP OF SERVICE activity.services:
Services in Current Activity Manager State:
-------------------------------------------------------------------------------
DUMP OF SERVICE alarm:
Current Alarm Manager state:
Realtime alarms that are scheduled:
RTC #1:
Alarm{436358a0 type 1 android}
type=1 when=1272931200000 repeatInterval=0 count=0
operation=PendingIntent{43617020 target IntentSenderRecord{4359f4e0 android
broadcastIntent}}
RTC #0:
Alarm{43695080 type 1 android}
type=1 when=1272884280000 repeatInterval=0 count=0
operation=PendingIntent{4358e9d8 target IntentSenderRecord{435e56d8 android
broadcastIntent}}
Elapsed realtime wakeup alarms that are scheduled:
ELAPSED_REALTIME_WAKEUP #0:
Alarm{4361e8e8 type 2 android}
type=2 when=90877805 repeatInterval=0 count=0
operation=PendingIntent{435adc60 target IntentSenderRecord{435adb08 android
broadcastIntent}}
Broadcast ref count: 0
Alarm Stats:
android
4729ms running, 1 wakeups
1 alarms: Intent { action=android.content.syncmanager.SYNC_POLL_ALARM flags=
0x4 (has extras) }
28 alarms: Intent { action=android.intent.action.TIME_TICK flags=0x40000004
(has extras) }
-------------------------------------------------------------------------------
DUMP OF SERVICE appwidget:
Providers: (size=3)
[0] provder=ComponentInfo{com.android.alarmclock/com.android.alarmclock.Analog
AppWidgetProvider} min=(146x146) updatePeriodMillis=0 initialLayout=2130903043 z
ombie=false
[1] provder=ComponentInfo{com.android.camera/com.android.camera.PhotoAppWidget
Provider} min=(146x146) updatePeriodMillis=0 initialLayout=2130903052 zombie=fal
se
[2] provder=ComponentInfo{com.android.music/com.android.music.MediaAppWidgetPr
ovider} min=(294x72) updatePeriodMillis=0 initialLayout=2130903040 zombie=false
AppWidgetIds: (size=1)
[0] appWidgetId=1 host=1024/com.android.launcher provider=ComponentInfo{com.an
droid.alarmclock/com.android.alarmclock.AnalogAppWidgetProvider} host.callbacks=
com.android.internal.appwidget.IAppWidgetHost$Stub$Proxy@4363f610 views=android.
widget.RemoteViews@43731e90
Hosts: (size=1)
[0] packageName=com.android.launcher uid=10004 hostId=1024 callbacks=com.andro
id.internal.appwidget.IAppWidgetHost$Stub$Proxy@4363f610 instances.size=1 zombie
=false
-------------------------------------------------------------------------------
DUMP OF SERVICE audio:
C:\Users\xufan>adb shell ime list
com.android.inputmethod.latin/.LatinIME:
mId=com.android.inputmethod.latin/.LatinIME mSettingsActivityName=com.android.
inputmethod.latin.LatinIMESettings
mIsDefaultResId=0x7f060001
Service:
Filter: null
priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false
labelRes=0x0 nonLocalizedLabel=null icon=0x0
ServiceInfo:
com.android.inputmethod.pinyin/.PinyinIME:
mId=com.android.inputmethod.pinyin/.PinyinIME mSettingsActivityName=com.androi
d.inputmethod.pinyin.SettingsActivity
mIsDefaultResId=0x7f060000
Service:
Filter: null
priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false
labelRes=0x0 nonLocalizedLabel=null icon=0x0
ServiceInfo:
C:\Users\xufan>adb shell input
usage: input [text|keyevent]
input text <string>
input keyevent <event_code>
android ps 命o执行完后Q会有下列各|“USER PID PPID VSIZE RSS WCHAN PC NAME”Q代表的意思分别是Q?/p>
VSIZEQ进E的虚拟内存大小Q?br> RSSQ?nbsp; q程分配到得物理内存大小Q?br> WCHANQaddress of the kernel function where the process is sleepingQRunning tasks will display (0) in this column.
其他的再说?/p>
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while(cursor.moveToNext()){
//get name
int nameFiledColumnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME);
String contact = cursor.getString(nameFiledColumnIndex);
String[] PHONES_PROJECTION = new String[] { "_id","display_name","data1","data3"};//
String contactId = cursor.getString(cursor.getColumnIndex(PhoneLookup._ID));
Cursor phone = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PHONES_PROJECTION,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null);
//name type ..
while(phone.moveToNext()) {
int i = phone.getInt(0);
String str = phone.getString(1);
str = phone.getString(2);
str = phone.getString(3);
}
phone.close();
//addr
Cursor addrCur = cr.query(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI ,
new String[]{"_id","data1","data2","data3"}, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId , null, null);
while(addrCur.moveToNext()) {
int i = addrCur.getInt(0);
String str = addrCur.getString(1);
str = addrCur.getString(2);
str = addrCur.getString(3);
}
addrCur.close();
//email
Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI ,
new String[]{"_id","data1","data2","data3"}, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId , null, null);
while(emailCur.moveToNext()) {
int i = emailCur.getInt(0);
String str = emailCur.getString(1);
str = emailCur.getString(2);
str = emailCur.getString(3);
}
emailCur.close();
}
cursor.close();
android中获取通话记录
String str = "";
int type;
long callTime;
Date date;
String time= "";
ContentResolver cr = getContentResolver();
final Cursor cursor = cr.query(CallLog.Calls.CONTENT_URI, new String[]{CallLog.Calls.NUMBER,CallLog.Calls.CACHED_NAME,CallLog.Calls.TYPE, CallLog.Calls.DATE}, null, null,CallLog.Calls.DEFAULT_SORT_ORDER);
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToPosition(i);
str = cursor.getString(0);
str = cursor.getString(1);
type = cursor.getInt(2);
SimpleDateFormat sfd = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
date = new Date(Long.parseLong(cursor.getString(3)));
time = sfd.format(date);
}
String | ADD_SHORTCUT_ACTION | 动作Q在pȝ中添加一个快h式? | "android.intent.action.ADD_SHORTCUT" |
String | ALL_APPS_ACTION | 动作Q列举所有可用的应用?br>输入Q无?/td> | "android.intent.action.ALL_APPS" |
String | ALTERNATIVE_CATEGORY | cdQ说?activity 是用h在浏览的数据的一个可选操作?/td> | "android.intent.category.ALTERNATIVE" |
String | ANSWER_ACTION | 动作Q处理拨入的电话?/td> | "android.intent.action.ANSWER" |
String | BATTERY_CHANGED_ACTION | q播Q充늊态,或者电池的电量发生变化?/td> | "android.intent.action.BATTERY_CHANGED" |
String | BOOT_COMPLETED_ACTION | q播Q在pȝ启动后,q个动作被广播一ơ(只有一ơ)?/td> | "android.intent.action.BOOT_COMPLETED" |
String | BROWSABLE_CATEGORY | cdQ能够被览器安全用的 activities 必须支持q个cd?/td> | "android.intent.category.BROWSABLE" |
String | BUG_REPORT_ACTION | 动作Q显C?activity 报告错误?/td> | "android.intent.action.BUG_REPORT" |
String | CALL_ACTION | 动作Q拨打电话,被呼叫的联系人在数据中指定?/td> | "android.intent.action.CALL" |
String | CALL_FORWARDING_STATE_CHANGED_ACTION | q播Q语音电话的呼叫转移状态已l改变?/td> | "android.intent.action.CFF" |
String | CLEAR_CREDENTIALS_ACTION | 动作Q清除登陆凭?(credential)?/td> | "android.intent.action.CLEAR_CREDENTIALS" |
String | CONFIGURATION_CHANGED_ACTION | q播Q设备的配置信息已经改变Q参?Resources.Configuration. | "android.intent.action.CONFIGURATION_CHANGED" |
Creator | CREATOR | ?/td> | ?/td> |
String | DATA_ACTIVITY_STATE_CHANGED_ACTION | q播Q电话的数据zd(data activity)状态(x发数据的状态)已经改变?/td> | "android.intent.action.DATA_ACTIVITY" |
String | DATA_CONNECTION_STATE_CHANGED_ACTION | q播Q电话的数据q接状态已l改变?/td> | "android.intent.action.DATA_STATE" |
String | DATE_CHANGED_ACTION | q播Q日期被改变?/td> | "android.intent.action.DATE_CHANGED" |
String | DEFAULT_ACTION | 动作Q和 VIEW_ACTION 相同Q是在数据上执行的标准动作?/td> | "android.intent.action.VIEW" |
String | DEFAULT_CATEGORY | cdQ如?activity 是对数据执行省动作Q点? center pressQ的一个选项Q需要设|这个类别?/td> | "android.intent.category.DEFAULT" |
String | DELETE_ACTION | 动作Q从容器中删除给定的数据?/td> | "android.intent.action.DELETE" |
String | DEVELOPMENT_PREFERENCE_CATEGORY | cdQ说?activity 是一个设|面?(development preference panel). | "android.intent.category.DEVELOPMENT_PREFERENCE" |
String | DIAL_ACTION | 动作Q拨打数据中指定的电话号码?/td> | "android.intent.action.DIAL" |
String | EDIT_ACTION | 动作Qؓ制定的数据显C可~辑界面?/td> | "android.intent.action.EDIT" |
String | EMBED_CATEGORY | cdQ能够在上Q父Qactivity 中运行?/td> | "android.intent.category.EMBED" |
String | EMERGENCY_DIAL_ACTION | 动作Q拨打紧急电话号码?/td> | "android.intent.action.EMERGENCY_DIAL" |
int | FORWARD_RESULT_LAUNCH | 启动标记Q如果这个标记被讄Q而且被一个已l存在的 activity 用来启动新的 activityQ已?activity 的回复目?(reply target) 会被转移l新?activity?/td> | 16 0x00000010 |
String | FOTA_CANCEL_ACTION | q播Q取消所有被挂v?(pending) 更新下蝲?/td> | "android.server.checkin.FOTA_CANCEL" |
String | FOTA_INSTALL_ACTION | q播Q更新已l被认Q马上就要开始安装?/td> | "android.server.checkin.FOTA_INSTALL" |
String | FOTA_READY_ACTION | q播Q更新已l被下蝲Q可以开始安装?/td> | "android.server.checkin.FOTA_READY" |
String | FOTA_RESTART_ACTION | q播Q恢复已l停止的更新下蝲?/td> | "android.server.checkin.FOTA_RESTART" |
String | FOTA_UPDATE_ACTION | q播Q通过 OTA 下蝲q安装操作系l更新?/td> | "android.server.checkin.FOTA_UPDATE" |
String | FRAMEWORK_INSTRUMENTATION_TEST_CATEGORY | cdQTo be used as code under test for framework instrumentation tests. | "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" |
String | GADGET_CATEGORY | cdQ这?activity 可以被嵌入宿?activity (activity that is hosting gadgets)?/td> | "android.intent.category.GADGET" |
String | GET_CONTENT_ACTION | 动作Q让用户选择数据q返回?/td> | "android.intent.action.GET_CONTENT" |
String | HOME_CATEGORY | cdQ主屏幕 (activity)Q设备启动后昄的第一?activity?/td> | "android.intent.category.HOME" |
String | INSERT_ACTION | 动作Q在容器中插入一个空?(item)?/td> | "android.intent.action.INSERT" |
String | INTENT_EXTRA | 附加数据Q和 PICK_ACTIVITY_ACTION 一起用时Q说明用户选择的用来显C的 activityQ和 ADD_SHORTCUT_ACTION 一起用的时候,描述要添加的快捷方式?/td> | "android.intent.extra.INTENT" |
String | LABEL_EXTRA | 附加数据Q大写字母开头的字符标签Q和 ADD_SHORTCUT_ACTION 一起用?/td> | "android.intent.extra.LABEL" |
String | LAUNCHER_CATEGORY | cdQActivity 应该被显C在?launcher 中?/td> | "android.intent.category.LAUNCHER" |
String | LOGIN_ACTION | 动作Q获取登录凭证?/td> | "android.intent.action.LOGIN" |
String | MAIN_ACTION | 动作Q作Z入口点启动,不需要数据?/td> | "android.intent.action.MAIN" |
String | MEDIABUTTON_ACTION | q播Q用h下了“Media Button”?/td> | "android.intent.action.MEDIABUTTON" |
String | MEDIA_BAD_REMOVAL_ACTION | q播Q扩展介质(扩展卡)已经?SD 卡插槽拔出,但是挂蝲?(mount point) q没解除 (unmount)?/td> | "android.intent.action.MEDIA_BAD_REMOVAL" |
String | MEDIA_EJECT_ACTION | q播Q用h要移除扩展介质(拔掉扩展卡)?/td> | "android.intent.action.MEDIA_EJECT" |
String | MEDIA_MOUNTED_ACTION | q播Q扩展介质被插入Q而且已经被挂载?/td> | "android.intent.action.MEDIA_MOUNTED" |
String | MEDIA_REMOVED_ACTION | q播Q扩展介质被U除?/td> | "android.intent.action.MEDIA_REMOVED" |
String | MEDIA_SCANNER_FINISHED_ACTION | q播Q已l扫描完介质的一个目录?/td> | "android.intent.action.MEDIA_SCANNER_FINISHED" |
String | MEDIA_SCANNER_STARTED_ACTION | q播Q开始扫描介质的一个目录?/td> | "android.intent.action.MEDIA_SCANNER_STARTED" |
String | MEDIA_SHARED_ACTION | q播Q扩展介质的挂蝲被解?(unmount)Q因为它已经作ؓ USB 大容量存储被׃n?/td> | "android.intent.action.MEDIA_SHARED" |
String | MEDIA_UNMOUNTED_ACTION | q播Q扩展介质存在,但是q没有被挂蝲 (mount)?/td> | "android.intent.action.MEDIA_UNMOUNTED" |
String | MESSAGE_WAITING_STATE_CHANGED_ACTION | q播Q电话的消息{待Q语音邮Ӟ状态已l改变?/td> | "android.intent.action.MWI" |
int | MULTIPLE_TASK_LAUNCH | 启动标记Q和 NEW_TASK_LAUNCH 联合使用Q禁止将已有的Q务改变ؓ前景d (foreground)?/td> | 8 0x00000008 |
String | NETWORK_TICKLE_RECEIVED_ACTION | q播Q设备收C新的|络 "tickle" 通知?/td> | "android.intent.action.NETWORK_TICKLE_RECEIVED" |
int | NEW_TASK_LAUNCH | 启动标记Q设|以后,activity 成为历史堆栈中的第一个新dQ栈Ӟ?/td> | 4 0x00000004 |
int | NO_HISTORY_LAUNCH | 启动标记Q设|以后,新的 activity 不会被保存在历史堆栈中?/td> | 1 0x00000001 |
String | PACKAGE_ADDED_ACTION | q播Q设备上新安装了一个应用程序包?/td> | "android.intent.action.PACKAGE_ADDED" |
String | PACKAGE_REMOVED_ACTION | q播Q设备上删除了一个应用程序包?/td> | "android.intent.action.PACKAGE_REMOVED" |
String | PHONE_STATE_CHANGED_ACTION | q播Q电话状态已l改变?/td> | "android.intent.action.PHONE_STATE" |
String | PICK_ACTION | 动作Q从数据中选择一个项?(item)Q将被选中的项目返回?/td> | "android.intent.action.PICK" |
String | PICK_ACTIVITY_ACTION | 动作Q选择一?activityQ返回被选择?activity 的类Q名Q?/td> | "android.intent.action.PICK_ACTIVITY" |
String | PREFERENCE_CATEGORY | cdQactivity是一个设|面?(preference panel)?/td> | "android.intent.category.PREFERENCE" |
String | PROVIDER_CHANGED_ACTION | q播Q更新将要(真正Q被安装?/td> | "android.intent.action.PROVIDER_CHANGED" |
String | PROVISIONING_CHECK_ACTION | q播Q要?polling of provisioning service 下蝲最新的讄?/td> | "android.intent.action.PROVISIONING_CHECK" |
String | RUN_ACTION | 动作Q运行数据(指定的应用)Q无论它Q应用)是什么?/td> | "android.intent.action.RUN" |
String | SAMPLE_CODE_CATEGORY | cdQTo be used as an sample code example (not part of the normal user experience). | "android.intent.category.SAMPLE_CODE" |
String | SCREEN_OFF_ACTION | q播Q屏q被关闭?/td> | "android.intent.action.SCREEN_OFF" |
String | SCREEN_ON_ACTION | q播Q屏q已l被打开?/td> | "android.intent.action.SCREEN_ON" |
String | SELECTED_ALTERNATIVE_CATEGORY | cdQ对于被用户选中的数据,activity 是它的一个可选操作?/td> | "android.intent.category.SELECTED_ALTERNATIVE" |
String | SENDTO_ACTION | 动作Q向 data 指定的接收者发送一个消息?/td> | "android.intent.action.SENDTO" |
String | SERVICE_STATE_CHANGED_ACTION | q播Q电话服务的状态已l改变?/td> | "android.intent.action.SERVICE_STATE" |
String | SETTINGS_ACTION | 动作Q显C系l设|。输入:无?/td> | "android.intent.action.SETTINGS" |
String | SIGNAL_STRENGTH_CHANGED_ACTION | q播Q电话的信号强度已经改变?/td> | "android.intent.action.SIG_STR" |
int | SINGLE_TOP_LAUNCH | 启动标记Q设|以后,如果 activity 已经启动Q而且位于历史堆栈的顶端,不再启动(不重新启动) activity?/td> | 2 0x00000002 |
String | STATISTICS_REPORT_ACTION | q播Q要?receivers 报告自己的统计信息?/td> | "android.intent.action.STATISTICS_REPORT" |
String | STATISTICS_STATE_CHANGED_ACTION | q播Q统计信息服务的状态已l改变?/td> | "android.intent.action.STATISTICS_STATE_CHANGED" |
String | SYNC_ACTION | 动作Q执行数据同步?/td> | "android.intent.action.SYNC" |
String | TAB_CATEGORY | cdQ这?activity 应该?TabActivity 中作Z?tab 使用?/td> | "android.intent.category.TAB" |
String | TEMPLATE_EXTRA | 附加数据Q新记录的初始化模板?/td> | "android.intent.extra.TEMPLATE" |
String | TEST_CATEGORY | cdQ作为测试目的用,不是正常的用户体验的一部分?/td> | "android.intent.category.TEST" |
String | TIMEZONE_CHANGED_ACTION | q播Q时区已l改变?/td> | "android.intent.action.TIMEZONE_CHANGED" |
String | TIME_CHANGED_ACTION | q播Q时间已l改变(重新讄Q?/td> | "android.intent.action.TIME_SET" |
String | TIME_TICK_ACTION | q播Q当前时间已l变化(正常的时间流逝)?/td> | "android.intent.action.TIME_TICK" |
String | UMS_CONNECTED_ACTION | q播Q设备进?USB 大容量存储模式?/td> | "android.intent.action.UMS_CONNECTED" |
String | UMS_DISCONNECTED_ACTION | q播Q设备从 USB 大容量存储模式退出?/td> | "android.intent.action.UMS_DISCONNECTED" |
String | UNIT_TEST_CATEGORY | cdQ应该被用作单元试Q通过 test harness q行Q?/td> | "android.intent.category.UNIT_TEST" |
String | VIEW_ACTION | 动作Q向用户昄数据?/td> | "android.intent.action.VIEW" |
String | WALLPAPER_CATEGORY | cdQ这?activity 能过备设|墙U?/td> | "android.intent.category.WALLPAPER" |
String | WALLPAPER_CHANGED_ACTION | q播Q系l的墙纸已经改变?/td> | "android.intent.action.WALLPAPER_CHANGED" |
String | WALLPAPER_SETTINGS_ACTION | 动作Q显C选择墙纸的设|界面。输入:无?/td> | "android.intent.action.WALLPAPER_SETTINGS" |
String | WEB_SEARCH_ACTION | 动作Q执?web 搜烦?/td> | "android.intent.action.WEB_SEARCH" |
String | XMPP_CONNECTED_ACTION | q播QXMPP q接已经被徏立?/td> | "android.intent.action.XMPP_CONNECTED" |
String | XMPP_DISCONNECTED_ACTION | q播QXMPP q接已经被断开?/td> |
原文地址Q?/span>
在移?UI 架构开发的h中, Android 上升到首位。如果你有一些移动体验,你会发现它是一?Java ME ?Canvas / Screen 对象?BREW 构徏阶层的完组合,通过一?XML 布局工具启动。每Ҏ动被攄在屏q堆栈,当它从您的应用程序启动?Android 是已l被配置处理关闭当前的活动,q激zd的下一个活动,当你要求或当用户按下 Back 。此讄允许您认为每个作Z个屏q基地活动?
每一Ҏ动都可能包含不同的视囑֒视图l在一个层ơ树。你可以惛_q样一个带有视囄的树Q布局对象作ؓ树干和树枝(因ؓ视图l对象可以强制{换成对象Q,视图或部g作ؓ树叶。单一 view Q在其最基本的Ş式,是一个可以拖拽的矩Ş。一个视囄Q在其最基本的Ş式,是一个包含一个或多个视图的对象。这个对象层ơ结构允许您布置复杂的用L面,而不必经历计视囄形和l徏重叠的错误过E。如果,另一U方法,q种事是你的袋子Q?Android 退出的方式Q让您呈现通过 Java ME Ҏ手绘游戏d?
在本章中Q你׃开始基本的Z XML-based 屏幕布局Q{Ud更复杂的自定义画布上l制。ؓ了本书,我会分解q讨图作Z个主要食物群Q?
Ø XML-defined widgets/views and view groups Q?良好的基本信息显C和菜单
Ø Android native views Q?TextViews, LayoutGroups, ScrollBars, and text entry
Ø Custom views Q?游戏E序员最好的朋友
您将开始一个示例登录屏q,q操U和Ud出部件和代码的意见,最l一个交互式动画与自定义视图?
方便、快速的 XML 布局
首先Q?XML 的布局开始看似简单,但它会很快变得复杂。您开始与你的布局和工作方式到的各个元素?
布置
大多 XML 屏幕被装在一个布局对象。布局对象来在许多不同的口呻I每一个你看看实在是太快,然后查了以下几节单的例子了?
注意Q在~译Ӟq些 XML 配置文g解析?Android 包装成一个紧凑的二进制格式。这样可以节省解析可怕的启动旉上的数额。但是,它意味着 XML 文g无法?q您的代码在q行时改变。更具体地说Q您可以在执行过E中改变q些 XML 文gQ但它会完全没有应用E序的布局。此外,您必L付夸大一个视图或?XML ?囄一性能h。您的里E可能会Ҏ CPU 负蝲和用L面的复杂性?
LinearLayout
所有元素被排列成递减的列Q以在一个从上到下或从左到右的方式。每个元素可以有重力和体重的属性记Q设|如何动态增长和~小Q以填补I间。元素自己排列成行或列的标示Z参数Q?android:orientation ?For example (see Figure 3-1):
<LinearLayout xmlns:android=
"
android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element One" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Two" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Three" /> </LinearLayout> RelativeLayout 每个子元素的布局是与子元素有关的。这U关pȝ建立使得在上一个子元素l束的地方元素才开始。子元素可以只涉及那些所列内容的面前。因此,建立?XML 文g开始到l束的依赖。请注意Q?ID 是需要的Q以侉K件可以互相引用。例如(见图 3-2 Q: <RelativeLayout xmlns:android= "
android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/EL01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element One" /> <TextView android:id="@+id/EL02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Two" android:layout_below="@id/EL01" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Three" android:layout_toRight="@id/EL02" /> </RelativeLayout> AbsoluteLayout 每个孩子有一个一个特定的位置Q必d父母布局对象的范围内?AbsoluteLayout 对象可能是最Ҏ建立和可视化Q但最难迁Ud新的讑֤或屏q尺怸。例如(见图 3-3 Q: <AbsoluteLayout xmlns:android= "
android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element One" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Two" android:layout_x="30px" android:layout_y="30px" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Three" android:layout_x="50px" android:layout_y="50px" /> </AbsoluteLayout> TableLayout TableLayout 是一个布局对象Q允许您指定表中的行?Android 试图安排q入正确的行和列的每一个子元素。例如(见图 3-4 Q: <TableLayout xmlns:android= "
android:layout_width="fill_parent" android:layout_height="fill_parent"> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element One A" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element One B" /> </TableRow> <TableRow> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Two A" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Element Two B" /> </TableRow> </TableLayout> q些是主要布局对象Q你来会遇到。每个例子有几个单的 TextView 元素Qؓ每种布局cdC布局怎样起作用的Q同时一q屏q捕h?XML 文g呈现。你可以?Android 的文件更d的实?http://code.google.com/android/samples/ApiDemos/src/com/google/android/samples/view/ ? 接下来的d是找到所有放|在一个布局元素Q相兛_元素的列表。这U资源是可以在纷J复 杂表?http://code.google.com/android/reference/android/R.styleable.html Q?Menu ? 从那里,你可以尝试第一?UI dQ在?“ C交 ” 应用E序的登录屏q。这d屏幕成?getSplashy CZ应用E序的一部分? 滚动、文字输入、按钮,以及所有在生活单的事情 现在是时候用布局的一个类?XML 的布局是完的Q在用户输入Q信息传递,以及几乎M屏幕的内Ҏ相对静态地斏V您添加一个简单的d屏幕昄前面提到?“ C交 ” 甌表(见代码清?3-1 Q。第一Q务是来描q屏q看h的样子在一个新的视图中。您可以使用U性布局Q您可以只垂直地添加小工具。(h意,q个 XML 需?general_bg 囄和声明字W串被定义在 res 文g夹中。ؓ此,从有兌l信息, Apress |站下蝲该项目的一章。) Code Listing 3-1. /res/layout/login.xml <ScrollView xmlns:android= "
android:layout_width="fill_parent" android:layout_height="wrap_content" android:scrollbars="vertical"> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/general_bg" > <TextView android:text="Login Screen" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAlign="center" /> <TextView android:text="Username:" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:id="@+id/username" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <TextView android:text="Password:" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:id="@+id/password" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/loginbutton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Login" /> <TextView android:id="@+id/status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAlign="center" android:text="Enter Username and Password" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/disclaimer" /> </LinearLayout> </ScrollView> 我将从原来的列D中撤Z些具体的U条q且解释他们的作用在下面部分。注意,你没有定义组成这个屏q元素的M位置。但是,因ؓ您用的?LinearLayout 对象Q每个连l的元素附加C前的元素的底部? Scrolling 滚动一个超q你讑֤屏幕大小的视图,你只是需要在 ScrollView 中封装你的布局对象。ؓ了用垂直滚动条Q你?ScrollView 必须讄参数 android:scrollbars="vertical" Q当你向下翻屏时Q将昄一个滚动条。ؓ了视图_长以说明q个对象Q我已经d TextView 作ؓ假声明在U性布局l束处。你会发玎ͼ如果你设|原来的 XML 为活动视图,重点是向下Ud的对象,直到到达的按钮,此时滚动条将处理键和向下Ud用户文本的底部? H探 TextView 两个主要 “ 构g ” 工作在原?XML. 注意Q在 Android 中的一个小部g是指M独立视图对象的子cR? Z标题和文本输入标{,使用 TextView 对象。对于用h制的文字输入Q?EditText 对象。最昄的,因此Q特别值得详细描述的是最后的 “status” 的文本: <TextView android:id="@+id/status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAlign="center" android:text=”Enter Username and Password” /> 首先Q由于本书内容将被修改在某个时候,通过你的代码在运行的时候,所以你需要给它一?ID 。这允许您?findViewById Ҏ后获得? @+id/status 添加到您的 ID 状态在 R.java Q如果文件不存在了。这一点,你的 IDE 可能会错误当您在代码中引用它W一ơ。不要惧怕,但因为是W一ơ编译,全部解决了? 接下来,您用 TextView 讄其宽度达到其父类的宽度在q种情况下, LinearLayout 对象。你告诉它让它的高度是由文字大小范围内用的 layout_height 参数 wrap_content 。您希望文字居住在屏q的中心Q因此您使用 textAlign Q因Z已经讄其宽度ؓ整个屏幕。最后,您给它一些简单的文字昄在活动开始了。后来,你会改变q一案文以反映当前的状态? 看到q个手艺的结果,只需创徏zdQƈ讄q个 XML 的布局是主要内容视图。您应该能够看到屏幕上,在文本输入字D늚cdQƈ选择框。这些行动,但是不会有Q何结果。ؓ配合该计划将他们Q让他们互动你就必须l箋阅读? XML 的布局 我们深刻体会?XML 的布|方案既单又强大。它提供了一个非~程接口的移动屏q布局和设计。它l开发h员提供了工具ȝ解打开和修改运行时的飞行这些|你会做探讨如何相互作用现?Android 的内|部件? 唤醒构徏 我已l说明了如何使用 Android ?TextView Q?button ?EditText 部g。但如何有用的是一个文本输入字D,如果你不能摄取你的用户已l进入? q是一个反问,不要回答Q我不能听你Q我希望Q。答案是显而易见的Q没有目的和l果文本输入是没有用处的。要讉K您的 EditText 部g先前定义的内容,你就必须做两件事Q? 1 。获取一个您?XML 定义部g的对象句柄? 2 。监听点L选择事g?Login 按钮部g上? 获取的事情句? W一个Q务就是得C个在您的 XML 配置文g中定义的元素指针。要做到q一点,你会保您要讉K的每?XML 部g有一?Android Q?ID 参数。正如前面简单提刎ͼ使用W号 @+id/-id_name_here- 确保您?R.java 文g有你需要的 ID 。以下是如何获得一个视囑֯象指针,当您的应用程序启动时。在新的dzd中,q是 OnCreate ҎQ被d?GetSplashy CZ应用E序Q? Button btn = null; public void onCreate(Bundle args) { super .onCreate(args); setContentView(R.layout.login ); btn = (Button) findViewById(R.id.loginbutton ); } 在这里,您已l获得了d按钮的指针,通过调用 findViewById 。这使您d单击监听Q会通知您当按钮被选中Q在手写W触摸屏Q或选定中心软键。您扩?ClickListener cȝ内联函数如下Q? public class loginScreen extends Activity { private OnClickListener buttonListener = new OnClickListener() { public void onClick(View v) { grabEnteredText(); } }; ... } 当一个选择通知发生Q以前的内联函数定义调用 grabEnteredText Ҏ。现在你已经定义的点M听器Q您可以使用 btn 对象?OnCreate Ҏ中: public void onCreate(Bundle args) { //... btn = (Button) findViewById(R.id.loginbutton ); btn.setOnClickListener(buttonListener); } 如果您放断点您的按钮监听?onClick Ҏ中,断点开火当您移动焦点ƈ选择d按钮Q当您用鼠标点击它在q行模拟器中? ~丝在文? 现在剩下要做的就是定?grabEnteredText 来做到这点,正如它名字的含义。在d屏幕的最l品的版本Q您要提取输入的文本Q开始一个网l登录的调用Q发动一个蝲入对话框。现在,你只昄一个对话框Q包含在d名和密码域中输入的内宏V下?grabEnteredTex 的样子在更新的登录活动: public void grabEnteredText() { //Get a pointer to the status text TextView status = (TextView) findViewById(R.id.status ); //Grab handles to both text-entry fields EditText username = (EditText) findViewById(R.id.username ); EditText pwd = (EditText) findViewById(R.id.password ); //Extract Strings from the EditText objects // and format them in strings String usrTxt = username.getText().toString(); String pwdTxt = pwd.getText().toString(); //HTTP transaction would spin up a //new thread here status.setText("Login" + usrTxt + " : " + pwdTxt); //Show dialog box that would eventually turn into this .showAlert("Login Data", 0, "Login" + usrTxt + " : " + pwdTxt, "ok!", false ); } 首先Q?findViewById Qؓ?status ?username ?password 部gQ您?TextView ?EditText 指针。接下来Q您提取 Text-Entry 构徏的内定w过?TextEntry 对象Qƈ其转换?String cR最后,你把两个字段的内容在一P他们都加入到状态文本对象,q弹Z个对话框q包含两个字W串? Java 的部? 当你看到我写的代码生即使是很小的选择菜单Q你可能会像我,有点吓呆了。等到熟悉的 XML 的屏q布局Q试图自q java 动手完成q一切,会感觉像是用一对破损的保龄球演奏古兔R乐。被警告Q它涉及许多打字Q或怸仅仅是一Ҏ折? 另一斚wQ可能有一个用L面布局的具体元素,你要动态调整。因为正如我前面提到的,您不能在应用E序q行时编?XML 文g的布局Q它必须有需要修Ҏ一个用L面的代码在运行时可能片断的工兗?Android l你q个动力Q只要你是舒适的打字以惊人速度? 现在您可以在引擎盖下开始小的修补Q用最基本、最直觉式的Ҏ?Android 的构建。你已经了解一个核心部分的基本外观Q其中许多是您在 XML 形式探讨。正如在前面的例子中Qؓ了说明v见,我将保持q种基本。我已经在这里讨论的界面布局Q它应该很容易学以致应用到更复杂的问题。在后来Q更多的高例子Q你会获得更多的其他 Android 部g。在下面的例子中Q我尽力确保用很你从前依赖没有?XML 元素。它应该l你一个机会,获得良好的处理非 XML 布局Q但要记住,实际上,你必L疯狂的做所有的用户界面Q这U方式? 主菜? 几乎所有的Ud应用Q至在发行Ӟ首先是图形主菜单。这个图形屏q引导用h行移动应用的各种功能。因?“ 主菜?” 的概忉|如此普遍的移动应用体验,它一个很好的和实际的案例研究。在q个例子中,你的目标是将一个简单功能主菜单的放在一赗ؓ了便于比较,你会使用其他的线性布局Q?把一切融合在一赗这个例子将建立在三个主要阶D: 1 。布局Q你会在屏幕上正地安排所有的主菜单项。当Ӟq将只?Android 的大屏幕版面上的一部分。但是,大多数应用程序菜单将使用大型囑ŞQ承担着更多的空间? 2 。焦点:您需要徏立一个焦点结构,使用户可以通过元素Ud。当焦点UdӞ你必调整每个菜单元素的颜色? 3 。选择zdQ最后,您需要徏立一个监听,以便当一个元素被选中或单击,你知情和可以在选定的项目基上采取适当行动? 当您完成所有这些Q务的三个Q你应该有徏立主要输入屏q的框架Q这大约占整个移动应用的癑ֈ?80 的工作。虽然不完全现实Q即Q我已经完全使用 XML 的零Q,它是极好CQ如何做事情以自定义q行时的驱动方式。当您添加更多的功能在你?“ C交 ” 应用E序中,您填写此主菜单将更加完善? 布局Q?Java 风格 在简单主菜单上的W一步是得到所有在屏幕上的菜单元素。正如我刚才所_你将采用U性布局完成它。您需要在甌前做q一切提L一ơ,所以就必须在新?MainMenu zd?OnCreate Ҏ中?Q请参阅W?1 章,如果你忘C如何创徏q插入一个新的活动。)代码清单 3-2 昄了它的实例化和配|的模样? LinearLayout layout = new LinearLayout(this ); layout.setBackground(R.drawable.general_bg ); layout.setOrientation(LinearLayout.VERTICAL ); layout.setLayoutParams( new LayoutParams(LayoutParams.FILL_PARENT , LayoutParams.FILL_PARENT )); setContentView(layout); 之后Q您通过什么迄今ؓ止,q在概念上似乎应熟悉。您可以讄背景使用?/res/drawable/ 文g夹中的图片,讄U性布局为垂直方向,q设|?LayoutParams 以填补父Ԍ在这U情况下Q父亲是zdQ控制全屏幕Q。布局参数Q在他们的基圎ͼ必须界定规定部g的高度和宽度。正如您后来可能会发玎ͼ在前布局参数讄之前试图攑օ一个部件在 ViewGroup 里,抛Z个异常。但是,现在你有一个布局对象来填充,你可以开始徏立了屏幕? d标题 接下来,d一个简单的标题Q在你的主菜单画面上方将为本。代码清?3-3 昄的代码块Q您需要它? Code Listing 3-3. Adding the Title TextView title = new TextView(this ); title.setText(R.string.man_menu_title ); title.setLayoutParams( new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT , LayoutParams.WRAP_CONTENT )); title.setAlignment(Alignment.ALIGN_CENTER ); layout.addView(title); 创徏文本对象Qƈ讄文本?/res/values/strings.xml ?。我知道我说我不会用M XML Q但我恐怕我会对此有些撒谎。在开发中Q您需要将所有的字符串移到这个位|,而不是在代码中定义。如果你的客h像我q样Q你׃会想拉你的源代码~辑器ƈ重新~译每次他们x变对 screens.Now 之一的措词,你有一个标题,是时候添 加更多有的和积极的菜单元素? Code Listing 3-4. Adding a Menu Item TextView ItemOne = new TextView(this ); ItemOne.setFocusable(true ); ItemOne.setText("Login Screen"); ItemOne.setTextColor(Color.WHITE ); ItemOne.setLayoutParams( new LinearLayout.LayoutParams( LinearLayout.LayoutParams.FILL_PARENT , LayoutParams.WRAP_CONTENT )); //Give the menu item an ID for tracking reasons. //The ID is a static int defined locally to the class ItemOne.setId(IdOne ); //Add it to our linear layout layout.addView(ItemOne); 天哪Q你可能认ؓ在仔l阅M码,q看h像你已l添加标题。你完全正确Q多么聪明的 you.The 的一个对象时表明的焦ҎQ当它被选中J重q没有到Q所以不要太自大q。下面是与以前的菜单,上面列出的标题文字有差别Q? Ø 你需要告?TextView 它可以接受的Ҏ调用 setFocusable 焦点? Ø 菜单上市目需要n份证Q因此您可以区别开来,在选择处理E序菜单元素的其余部分? ?如我刚才单,只要增加一个小部g?ViewGroup ?LayoutParams 对象必须明确q一观点内组定义的对象。例如,在过?setLayoutParams Ҏ调用Q你必须通过?LinearLayout.LayoutParams 对象。你必须通过正确的子cȝ布局参数Q或?器h你扔在q行时异常? 正如我以前说q,Z使菜单,我将d两个文本元素几乎完全一P以前上市。ؓ贪方便,我不会在q里一一列D。一定要参照整个目Q以满你的好奇心。现在,你把所有的菜单到位,是时候对其进行修ҎQ接收或失去焦点 焦点q轻的草?... ? Code Listing 3-5. Creating a Focus Listener OnFocusChangeListener focusListener = new OnFocusChangeListener() { public void onFocusChanged(View v, boolean hasFocus) { adjustTextColor(v, hasFocus); } }; private void adjustTextColor(View v, boolean hasFocus) { //Dangerous cast. Be sure you are //listening only to TextView focus changes // or this could go horribly wrong. TextView t = (TextView)v; if (hasFocus) t.setTextColor(Color.RED ); else t.setTextColor(Color.WHITE ); } 此外Q您必须d以下行对应于每个菜单中选择元素附加焦点更改侦听器对象: ItemOne.setOnFocusChangeListener(focusListener); ?着地方听众Q您现在每次通知一个菜单要素收益或失去焦点。在更先q的主菜单,q个Ҏ可以增加地方的Ş象{变,动画Q三l爆炸或其他奇才邦图形效果。在q?个例子中Q您不得不满于仅仅改变文字的颜色。现在,用户可以告诉通过颜色的变化,其中菜单,H出昄Q您需要的时候作出反应,他们按中心键选择一?目? 提示Q它可能通过使用 setTextColor Q?ColorStateList 颜色Q方法,该方法是贯彻落实文本单的方式为基的主?menu.There 一?TextView 重点Q没有重点,q定颜色L很多Ҏ可以实现一个目标,一个很好的 IDE 中,我只是选择了更通用的(因ؓ?希望你的应用越文本菜单Q。有关?setTextColor 信息Q请参阅文g Android ?http://code.google.com/android /reference/android/widget/TextView.html Q?setTextColor Q整型)? 单击q择zd Code Listing 3-6. Adding a Selection Listener OnClickListener clickListener = new OnClickListener() { public void onClick(View v) { String text = "You selected Item: "; switch (v.getId()) { case IdOne : text += "1"; startActivity( new Intent(MainMenu.this, Login.class)); break; case IdTwo : text += "2"; startActivity( new Intent( "com.apress.example.CUSTOM_VIEW")); break; case IdThree : text += "3"; break; } //We'll get to the following line in a bit status.setText(text); } }; 以前?switch 语句是调?setID 回来的原因当您最初创建ƈ TextView 部g。当一个菜单项被选中或指针点击,?onClick 函数被调 用,q过相应的视图是作ؓ参数。您负责审查,以确定哪些菜单项被选ؓ通过视图 ID 。这使您可以采取的菜单中选择适当的行动。通过q种方式Q您可以切换 到先前定义的d屏幕Q你卛_会与 startActivity Ҏ调用写入自定义视图? q是有留下的一步Q如果你在示例代码中?onCreatefuction 的底部,你会点它。你需要添加一个点ȝ听到视图。下面是应该q行在你建立的部件清单行Q? ItemOne.setOnClickListener(clickListener); 回顾 自定义用L面渲染的d q?是你部分游戏开发商一直在{待 for.Android 允许你定义一个自定义视图对象只是通过扩展视图cd执行 OnDraw Ҏ。ؓ了演C定义视图?动画循环中运行,我已l从旧金山市的探索展CZ些启C我们如何看待动d声音。您可以?http://www.exploratorium.edu /listen/index.php 更多关于博物馆和有关的展览。你可以购买 http://www.nature.com/neuro/journal /v7/n7/full/nn1268.html U学白皮书? Ø 实施意见?Android Ø l制到屏q上使用 Canvas 对象 Ø 创徏动画循环 Ø 修改Qƈ从活动自定义视图交互 自定义视? Code Listing 3-7. Simple Custom View Declared in the CanvasExample Activity protected class CustomView extends View { public void onDraw(Canvas canvas) { Paint p = new Paint(); p.setColor(Color.WHITE ); canvas.drawText("Yo!", 0, 25, p); } } 贺Q输入文字这几句Q你现在是自q自定义部仉傲的所有者。当Ӟ它只是打招呼Q像?17 岁朋克表妹,但我想你必须从某个地方开始。对于那些你在与 GameCanvas 的经验对象的 Java ME Q这应该很熟悉。要接收 OnDraw 中呼叫,您需要设|作为样本活动的主要内容查看。你必须仪式代码Q将实例化,q其成为当前视图。代码清?3-8 昄?CanvasExample zd的外观? Code Listing 3-8. Activating a Custom View CustomView vw = null; public void onCreate(Bundle args) { super .onCreate(args); vw = new CustomView(this ); setTitle("Bounce or Pass, sounds changes everything"); setContentView(vw); } 你ؓ你的样品zd的名Uͼ因ؓ你没有给它一个应用程序的名称。然后,它只是一个创建新 CustomView 对象Qƈ讄它ؓ当前内容视图的问题。这调?您的自定义部件内?OnDraw ҎQƈ昄您的有点不合常规的问候。您现在有一个掌握在非常基本的绘L式到屏幕上。您现在应该可以q入更复杂的渲染?动画的@环开始? ?意:如果你想实现自己以外的浏览自q动画循环 / ViewGroup 层次Qƈ建立?SurfaceView 循环研究对象。你可以扑ֈq一 http://code.google.com/android /reference/android/view/SurfaceView.html 对象文g? 加蝲音频和图? Code Listing 3-9. Initializing the CustomView protected class CustomView extends View { Context ctx; Paint lPaint = new Paint(); int x_1=0,y_1=0; MediaPlayer player = null; Bitmap ball = null ; boolean running = true ; CustomView(Context c) { super(c); player = MediaPlayer.create (c, R.raw.bounce ); BitmapDrawable d = (BitmapDrawable) getResources().getDrawable(R.drawable.theball ); ball = d.getBitmap(); ctx = c; } ... } 在构造函CQ你通过 R.java 装蝲常数的反弹媒体资源从 / 水库 / 原始位置的文件。因Z做了几个其他资源cd此之前,你应该是一个老手了。您q需要加 载一个,作?“ 球得出的形象?” 你这样做的资源管理器使用对象Q这是从上下文对?etrieved 。虽然你没有明确从资源加载位|之前的形象Q这好像?乎Q何其他资源负载的代码? 实施环,实施循环Q实?... Code Listing 3-10. The Core of the Animation Loop public void onDraw(Canvas canvas) { //Draw the white background Rect rct = new Rect(); rct.set(0, 0, canvas.getBitmapWidth(), canvas.getBitmapHeight()); Paint pnt = new Paint(); pnt.setStyle(Paint.Style.FILL ); pnt.setColor(Color.WHITE ); canvas.drawRect(rct, pnt); //Increment the X and Y value for the sprites x_1+=2; y_1+=2; //Reset the loop when the balls drift offscreen. if (x_1 >= canvas.getBitmapWidth()) { x_1 = 0; y_1 = 0; } //Draw ball 1 drawSprint(x_1, y_1, canvas); //Draw ball 2 drawSprint(canvas.getBitmapWidth() - x_1, y_1, canvas); if (running) invalidate(); } 从顶部开始,您的W一个白色的背景使用 paintstyle 对象和调?canvas.drawRect 。a漆对象,l合 Rectangle 对象Q将告诉?布画一个白色盒子,覆盖整个屏幕。接下来Q您递增 x 和你的球 Sprite ?y 倹{然后,您需要重新设|他们,如果他们已经漂过dq的范围Qƈ最l绘?用自q drawSprite l他们打电话。代码清?3-11 昄了该函数的内宏V? Code Listing 3-11. Drawing a Bitmap protected void drawSprint(int x, int y, Canvas canvas) { canvas.drawBitmap(ball, x, y, lPaint); } q个功能Q现在,只是一个简单的调用 drawBitmap Ҏ。我已经分离出来Q这U方法只是因为绘制在另一场合雪碧可能需要比q个单的例子功能。最 后,回到 OnDraw 函数Q你会打电话l你的只有无效运行标志是真实的。调用无效的看法?Android 的强q重l的首选方式。在q种情况下,您自己无效,q将??OnDraw 中,整个q程中,再度开始。如果你单地讄q行的标志虚假暂停或退出和无效时再恢复它的动画应该留在同其母公司活动的重点步骤? d和控制声? Code Listing 3-12. Playing and Reloading Audio if (playSound && canvas.getBitmapWidth() - x_1 -16 == x_1 + 16) player.start(); if (x_1 >= canvas.getBitmapWidth()) { x_1 = 0; y_1 = 0; player.stop(); player.release(); player = MediaPlayer.create (ctx, R.raw.bounce ); } 正如您可能已l注意到Q你开始音频播放时Q小_Q?16 像素q离Ҏ。这是一个没有行贿的旉Q让音频开始。我要指出,q更加证明我不能~辑音频文g而不 是针对一个缺乏效率的音频负荷?Android 播放旉。您q必ȝ保以播放音频只有 playSound 布尔是真实的。这个变量是一cȝzd在其中自定义视图定义 的成员。用此布尔Q你会得C来自内部的屏q活动自定义视图cȝ控制。要打开和关闭音频,您现在只需实施 Code Listing 3-13. Reacting to Key Events public boolean onKeyDown(int key, KeyEvent kc) { if (key == KeyEvent.KEYCODE_DPAD_CENTER ) { playSound = !playSound; return true; } return super.onKeyDown(key, kc); } 此代码应cM于你如何驛_了在W?2 章恶作剧的应用? 把它同在一? 提示Q用所有你学到了在本章中,建立q种qLQ它包含了一些说明文字,以及边界使用 XML.When zd开始了一个框Ӟ但呈现的 XML 插入到适当的位|自定义视图。对于这Q务,我徏议用的解释Qƈ境矩形相对布局Q?TextView ?
注意Q如果您是移动开发方面的新手Q当军_如何布置您的应用E序Ӟ您必重复你的头一个右铭Q?“ ULQ移植,UL?” 理想情况下,一个布局的设计将所有可能的工作讑֤。事实上Q这永远不会奏效。如果你q行应用在多个电话上Q如大多数运营商要求您这样做Q,重Ҏ在动态的Q相对的布局l构。我保证Q你的屏q大今后将以一U戏剧性的方式变化。减绝对?X/ Y 的数量,q保留那些你在方便用找到的位置 .
q就是它 —?现在允许用户输入文字Q你获取、操U,甚至昄一个对话框包含了该信息。干得好Q花一U钟L自己在背后,或Q何胳膊可以拘着的地斏V?
到目前ؓ止,您探讨如何?XML 来做屏幕设计Q仅仅?“ C交 ” 画面屏幕。此Ӟ你已l学会了如何使用两个的合体在您的登录屏q。最后一站关?Android 部g表达Q就需要单独用代码徏立屏q布局的?
引擎盖下使用
菜单?
现在您可以添加单个菜单元素。因是W一个在相当重复Q我插入和解释的第一个元素,但其余的留给你的你自q讑֤。随意抓取在 Apress |站的完整项目,看到菜单休息。同样地Q你会填补他们更为您通过 Android 要素各地的发展?
代码清单 3-4 昄的代码添加单个菜单项?
Z处理焦点改变事gQ你必须创徏一?OnFocusChangeListener 抽象cȝ实现。该CZ的版本,在主菜单内定义类的活动在当地Q将cM于代?3-5 ?
你已l看到如何登记在 oginscreen onClick 事gQ所以你应该能够通过q一?withouttrouble 的微风。代码清?3 ?6 ?昄了示例代码获取选择的事件?
回顾 Java 驱动的主菜单Q你做到了几个重?things.First Q您执行功能以前只能通过 XML 文g的布局。虽然不完全切合实际的做一斚wQ它会给你够的工具来改变和定制应用E序的同时运?XML 视图?
W二Q你注册为您的所有菜单项的焦Ҏ变事件。当焦点更改侦听叫,你改变了重点目Q以H出昄它的颜色。在实际应用中,要达到同L事情更有效的ҎQ但我假设你x变的东西代替文本颜色多,可以_奢华?
W?三,你学会了如何們和作出反应的选择事gQ洞悉项目选中Qƈ采取适当的行动是 selection.Again 基础上,Ҏ有需要将重点攑֜手屏q小部g Z码,往往是相当昂贵,但是使用你刚刚学到的工具Q你可以修改Q增加,以及自定义菜单或工程清单数据和用户偏好ؓ基础Q同时应用程序正在运行。但是,?果您需要获得更多的专业如何l制到屏q上Q你需要较微妙和更代码重的方法?
q个例子动M个球对对Ҏ游,然后或者或弹蟩和移动距通过。这个例子是Z表明反弹声音可以看到之间的传递对象,看他们相互弹球h的区别。代码方面,我将演示了一个自定义视图几个重要斚wQ?
?可以自定义在两个斚w视图H口。第一Q是?View cR这使您可以通过滚动自己创造一?android.View 可行的子cȝ “ 工具 ” 。另一U方法,您就 必须对自q探烦Q是子类Q如 TextView Q进度条Q或 ImageView 和修改其行ؓ受保护的Ҏ使用现有的部件。这个例子显CZW一个选择Q因?它的范围q泛Q比较容易理解?
在最基本的层面,一个自定义部g重写保护 OnDraw Ҏ。代码清?3-7 昄了这样一个方法的一个示例?
创徏游戏循环
׃所有游戏程序员会告诉你Q大多数游戏Q其核心Q一个不断@?onsist 。用戯入的循环查,q?在此输入和Q何其他游戏行动,届时制订新的框?/ 帧在您的CZ应用E序 screen.The 循环不会赢得的复杂性和独创性的M奖项Q但它会得到你开 始自q amerendering 循环?
在您绘?CustomView 得到Q您需要加载初始化E后用于一些资源。代码清?3-9 昄了新的构?CustomView 包括局部类变量声明?
事不宜迟Q代码清?3-10 昄?CustomView 对象?OnDraw Ҏ样子?
׃听觉错觉需要能够打开和关闭两个反弹互相对象声韻I您需要设|音频比赛,他们打,然后为用户徏立一个机Ӟ把这一声音的和关闭?
?播放的音频,在代码中d代码清单 3 ?12 ?C前的 OnDraw 函数Q因为它也实际上Q游戏控制回路。当我说 “ 游戏循环Q?” 我指的是无效呼叫?OnDraw 中结束,设立一个重l?Android ?UI 事g循环。请CQ?playSound 是一个布宣?326-7524 自定义视图?
在代码的ҎQ在zd清单 3-13 ?
如果您已l按照一直密切(或欺骗,只是下蝲完成的项目)Q您应该能够q行应用E序Q看的觉。新M心方向键打开和关闭音频。与音频 起飞Q它应该像他们通过互相q行表决Q看h他们反弹Q即走各的\。在q个例子中,我演CZ如何创徏自己的视囄Q如何用它来d屏幕上,如何建立一个游 戏渲染@环,以及如何控制Q简单的循环利用关键事g?
使用用户界面
在本章中Q您已经了解Q详l,如何布局屏幕使用 Android ?XML 架构Q以及如何相互作用和修改了一?Java ?code.Next q行的模式,学习了如?UI 部g布局和视囄使用源码单。这是一个不那么实际应用 ?Android 用户界面工具Q但重要的是ȝ解的但ؓ了通过。最后,您探索徏?gamerendering 循环的重要工兗您加入到把一些简单的多媒体和用户?Ӟ创徏了一个简单的听觉qLQ应该让 yourvery 讨厌鬼的朋友?
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/lihaifeng555/archive/2009/11/02/4757323.aspx
]]>
Activity: Android 应用E序的UI(User Interface)基本lg?
Intent receiver: 可随时被启动来处理IntentQƈ执行其Q务?/p>
Service: 非UI功能的后台处理组件?/p>
Content provider: 跨程序的׃n资料之存储者?/p>
Android vs. Java ME vs. BREW
一个BREW应用E序Q在所有绝大多数情况下Q是׃个单独的程序组成,q个程序是通过接收和发送活动与手机的其他部分通信的。另一斚wQ你可以一个Java ME应用看做Midletcȝ扩展。这个Midlet有启动、停止、暂停、键处理Qkey handlingQ的功能Qƈ且可以完成Q何手机和应用的交互。一个Java ME应用E序通常׃个单独的Midletl成?/p>
Android应用E序有许多活动,通过AndroidManifest.xml文gQ这些活动可以被注册在手Z?在面向Android的开发与面向其他手机开发工具包的开发之_Android的multiactivity架构或许是的他们之间主要的区别。正是这个事实ɾ~写模块化、分割的代码Qmodular, compartmentalized codeQ更Ҏ。在BREW和Java ME中,开发h员可以执行在Midlet或小E序范围内的大部分功能。在Android中,你可以写一个活动、内容处理程序(content handlerQ、意图接收器Qintent receiverQ、或服务以应对几乎Q何东ѝ一旦你~写了编辑文本文件的zdQ通过发送和接收意向的行动,您可以引用这个活动在您将来所有编写的应用中。这个这q不是说Q这U架构在BREW或Java ME中是不能实现的,他们只是必须在Java和C或C++~程的基上,或在BREW中通过J琐的扩展实玎ͼ而不是被qx地集成到应用框架中?/p>
Functionality
像MidletQ活动用了一pd的功能与外面的世界进行交换。在他的基础上,你编写的zd必须重写ҎOnCreateQ你q要重写其他功能Q包括:onStop、onPause、onResume和onKeyDown。这几个功能可以让最大限度地你开发的zdl定到Android手机中。在默认情况下,在Eclipse中创建新的Android应用E序执行一?#8220;HelloQWorld”应用E序。我会告诉你如何从这个基本应用到功能齐全的画面?/p>
如何d囄(Image)资源
首先图片资?例如menu_background.jpg)直接拯?res/drawable文g夹中。此ӞEclipse的Android插g(Android Plug-In)会自动将一个新的ID值添加到R.java里。所以R.java文档中会多加了一行指令如下:
public static final int menu_background=0x7f020001;
在应用程序将q此ID值来取得q个图标文gQƈ昄或处理它?/p>
如何定义XML布局 (Layout) 文g
刚才已经新增了一个图片资源文件。此Ӟ在定义布局XML文g中,可以引用此囄。这些布局XML文g都放在在/res/layout文g夹中Q其中Eclipse的Android插g已经生成了一个main.xml文g。现在,你可利用Eclipse?File>New>File菜单选项来生成新布局XML文gQ例如:splash.xml。然后,以main.xml內容为模板,之拯到新的splash.xml里,下一步移?lt;TextView>q且增加<ImageView>Q内容如下:
<ImageView android:src="@drawable/menu_background"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</ImageView>
在Android的XML布局文g里,使用@drawable/pL地引?res文g夹中的资源,例如上面的的android:src="@drawable/menu_background"。此外,layout_width和layout_height 则说明这个ImageButton昄Z的大?Size)。splash.xml也成Z項新的資源。所以在R.java裡也會自動產生新的一行,如下Q?/p>
public static final int splash=0x7f030001;
l制启动画面
现在Q你的初始画面被定义完成Q可以激zd昄。你现有的Androidzd已制定了main.xmlQ所以你要{Ud新的初始布局。ؓ了切换,更改OnCreateҎ中的代码Q?
setContentViewQR.layout.mainQ;
?
setContentViewQR.layout.splashQ;
q行应用E序Q看着你新创徏的启动画面。到目前为止Q如果你得到了错误信息,查以认你的名字是否匚w。如果图片没有显C,保它被正确地放|在res/rawable文g夹,qsplash.xml应用了正的名称和文件?
旉可以解决M问题
启动屏幕开始展玎ͼ但启动画面单独作无聊的应用程序,所以你需要进入主菜单。你会用简单的内嵌定义U程来完成的定时器,有一些常数需要在定义U程前初始化。ؓ了看上去完整Q我包括全部的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();
}
到现?Q?你才开始看C?Java 代码。这个简单的U程直到q行旉计数器超q?m_dwSplashTime 才停止。虽然有实现一个计时器多种方式Q选择q种方式有两个原因:
此计数器可以暂停。该计时器只有m_bPaused标志为false时才推动。正如你看到在一分钟内,如果你调用活动的OnPauseҎQ可以方便暂停计时器。这q不L对启动画面的需求,q对其他以时间ؓ基础的业务是重要的?
UdC一个屏q很单,只要改变的m_bSplashActive标记为false。推q到下一个屏q,如果你执行这在时,不要求你作出的行动,然后取消更传l的计时器?
有了q个代码Q只要你以毫Uؓ单位讄m_dwSplashTimeQ你应该看到启动画面。当旉C或用户用按键中断了启动画面QstartActivity被调用。finish可以关闭启动zdQ用户不必通过从主菜单上选择Backq回。你需要执行一Ҏ动,接受CLEARSPLASH意图的行动。与此同Ӟ让我们回一些其他重要活动的Ҏ你需要重写?
暂停Q恢复,冲洗Q重?
׃呼入电话Q短信或其他中断Q你的活动被挂vӞ暂停启动计时器,如下Q?
protected void onPause()
{
super.onPause();
m_bPaused = true;
}
对于q些大部分覆盖的Ҏ Q?在做M事情之前 Q?你需要调用超cR如果你查看计时器线E,如果m_bPaused是trueQ你会看到负责跟t时间的MS计数器保持时间没有前q。在q一点上Q我怿你可以猜onResume的样子:
protected void onResume()
{
super.onResume();
m_bPaused = false;
}
当你的应用程序恢复,计时器线E添加时间恢复到MS计数器?
基础?Key Handling
在活动内QKey Handling是处理覆盖onKeyDownҎ。我们将使用此功能允许用户取消你不完的启动画面。正如在本节开始你看到的计时器U程Q通过m_bSplashActive讄Q你在计时器循环中了异常语句。ؓ了异常处理,你只需要重写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;
}
现在 Q?当用h下Q意键 Q?屏幕被推进C一个\E通过计时器@环?
Clear intent
有一件事你需要在启动画面之前?Q?我相信你想知道有?startActivity Ҏ调用。这里应该简单介l一下intent。Intent是一个对象,在两个或两个以上zd、内容处理(content handlersQ、意图接收器Qintent receiverQ、或服务之间Q可以作Z个通讯事g。你会用com.google.app.splashy.CLEARSPLASH调用 startActivity 。当startActivity被调用时QAndroid搜烦所有配|清单文ӞL已注册ؓCLEARSPLASH Intent action节点?
你要增加一个新cMainMenuQ其作ؓ主菜单activity。它要承Activityc,实现OnCreateҎQ在R.layout.main中调用setContentViewҎ。你要打开的AndroidManifest.xmlq增加新?activity 元素。在 </activity> l束W之后, 你应该插入以下内容:
<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>
定zd的名UCؓ .MainMenu 。这会告?Android 加蝲和运?Java cR在 Intent filer 标签?Q?注册?com.apress.splash.CLEARSPLASH ?Intent Action 。在现实中,名称意图可能是beef.funkporium.swizzleQ只要名U在startActivity调用和前面的Android配置清单中一_所有正的事情应l发生?
一Ҏ动的生命周期
Activity的生命周期被包括在Google的文档中。但是,如果你先仔细考虑生Activity的底层原理,你不能错q这个重要的信息。在q一点,你的启动画面Q你应该准备好推出?
Z说明Q我q增加了以功能在启动画面zd中:
protected void onStop()
{
super.onStop();
}
protected void onDestroy()
{
super.onDestroy();
}
如果你方断点在上面活动的所有功能,在调试模式下q行它,你会看到断点与下面顺序一?
1. onCreate
2. onStart
3. onResume
4. 在这一点上Q你的活动目前已l运行。在三秒钟内Q计时器U程达到结束,q调用startActivityl算的意图。下一步,它将调用finishQ它告诉Android关闭启动画面zd?
5. onPause
6. onStop
7. onDestroy
5. onPause
6. onStop
7. onDestroy
从开始到l束 Activity Q?q是一般的生命周期来。你可以扑ֈ对生命和时代?Android zd更全面地披露 Q?在谷歌的文档zd?http://code.google.com/android/reference/android/app/ Activity.html 。你甚至可以扑ֈ漂亮囑Ş。从本质上讲Q手Z用了以前的组合功能提醒你的主要事件可以发生在你的应用E序Q启动,关闭Q暂停和恢复。我已经讨论q,Activity要成ؓM传统应用的的核心lgQ他们给你控制了屏幕Q能够接收用戯入?
ȝ
到目前ؓ止,我已l探讨了zd如何成在手机中,他们如何启动和停止,以及他们如何与基层沟通。我演示了如何显CZ个简单的XML视图屏幕Q以及如何活性之间切换两个反应都在一个关键的事g和结束时的一个指定的旉量。在短期内,你需要了解更多有Android如何使用意向Q意图接收器Q过滤器和意图沟通。要做到q一点,你需要一个示例应用程序?
创徏一个Intent Receiver
Intent Receiver是Android重要的组成部分,从它的名字可以看出其作用。它的作用是{待接收注册的Intent ActionQAndroid是按照BREW的通知模式实现的。我们将使用一个简单的应用Q展C个复杂的Intent ReceiverdQ输入文本消息的接收和响应?
事情的v?
我们开始设惌样一q画面:一天下午,当你回到你的办公桌,你发C的办公桌Q从地毯到天花板与可q_红色的囄Q铺满最令h讨厌的图甅R你知道q是谁在做,现在是你报复的时候了。你也知道你的工E部副总裁最厌恶一首特D的歌。这首歌?“ La Bamba “ 。让你决定通过一个休眠程序操U你同事的Android手机。我会告诉你如何制作一个Android应用E序Q收到特定的短信后,播放q种耻i效应的音频文件。这会你的副d你的新敌Z生强烈的愤慨。同Ӟ你要l他一个机会关闭声音了。这U恶作剧E序要求Intent ReceiverQActivityQServiceQ以及所有三U方式进行通信?
q有什么实际的通途吗Q这可能有吗Q?
q是一个很好的问题。虽然表面上看来不是很实用应用,我相信,如果有一Ҏ像力Q你可以发现其很多重要的现实用途:从推送电子邮仉知到内部电话应用通信?
你将向前q进四个阶段。在每个阶段Q你了解更多关于Intent receivesQservicesQ所有这些应用程序之间的怺作用Ӟ
通知收到一个短?
打开短信的内容和扑ֈҎ的净?
当短信到达Activity启动Qƈ且意识到启动发生在接收器的控制下
开始一个新的服务,播N频文?
使用Intent Receiver
在你开始编写Intent Receiver之前Q你需要了解你Z么会使用他。Intent Receriver没有或几乎没有内存占用、linkage和系l开销。在启动Ӟ一个活动必d所有大量的引入的类加蝲QIntent Receriver则没有这些约束。由于某U类型的新Intent可以辑ֈ破碎频率Q例如网l状态更斎ͼQ一个轻量的对象必d分析数据的第一阶段。如果它是一个适当的时间唤醒一个更大的用户界面E序或大q后台服务,意图接收机应采取q种行动?
提示Q意图接收器可以l常的启动和关闭Q这依靠他们的监听)Q试图让它们变地重量轻,使用可能少的类库。你的用户不会高_如果他们电话在缓慢地爬行Q因Z已经插入到太多特定的事g处理开销?
~写Intent Receiver
W一件事首先你需要创Z个这个小恶作剧应用程序徏立新目。在源目录中Q创Z个新c,成为新的Intent Receiver。在W一阶段Q它看v来应该像q样Q?
public class PrankSMSReceiver extends IntentReceiver
{
public void onReceiveIntent
(Context context, Intent intent)
{
return;
}
}
现在你已l设定了阶 Q?你必d诉你惌 Android 接收 SMS 事g。你可以通过修改 AndroidManifest.xml 文gl你许可和登?RECEIVE_SMS ?Intent action ?
权限
q营商,用户Q甚臛_发h员可能不希望lAndroid应用自由支配Q诏I其手机和网l的Ҏ层。因此,h推出一U被Ud发h员认可的权限概念。ؓ了能够接收短信息Q你需要通知手机你可以接收?
在Android中,所有元素的权限声明在特别的配置文g中,你添加的权限?lt;manifest>标记后(代码2-2Q。该CZ应用E序被UCؓPrankApp。其zd主要是rankActivity?
Code Listing 2-2. Adding Permissions to Receive SMS Messages
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=
"
package="com.apress.book.PrankApp"> <uses-permission android:name= "android.permission.RECEIVE_SMS" /> 没有权限标志QAndroid你的应用程序无法启动当它接收到一个短信。还有其他的权限我需要涵盖你向前看。在此期?Q?你可以找到所有在列表的权?Android 的文件资?http://code.google.com/android/reference/android/ Manifest.permission.html ? 向我发送短信! 现在Q你已经允许q行与手机的SMS层交互,你必d诉手机做什么,当一个新的文本信息到达时。要做到q一点,你必L开AndroidManifest.xml文gQ添加一个新的Intent Receiver。代码清?-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> q就是你每次必须要接受的 Intent notification Q?当手机得C个接收到?SMS ? ?Action 中分?Intent Receiver 要完成这个要比我们想象的有一点困难。一个进E必d一?DDMS 中运?。但在大多数情况下,你不惌应用E序q行Q除非新的事件触发它。这问题的解x案在Eclipse IDE中只是一个小的把戏。当你一步一步往下走Ӟq可能会一点一点变得复杂? 在你的onReceiveIntentҎ中放|一个断炏V开始调试应用程序,q让模拟器位?#8220;Hello WorldQPrankActivity”屏幕上。在Eclipse中,切换视图到DDMS。你可以按这命o+ F8键几ơ或选择菜单 Window Open Perspective DDMS ? 沿着左边H口Q在Device选项卡上Q你现在应该看有一个绿色bug图标在你的应用旁辏V这是DDMS告诉你调试器附加C的PrankAppq程中。在它的下面是Emulator Control选项卡。在q里你可以发送短信消息。首先输入Q何一个电话号码,选择SMSQ键入一个测试消息,q按下Send? 如果你的配置正确Q你应该看到Eclipse切换到Debug透视图,q停止在你的新设|断点上? 注意Q如果没有发生,首先保你设|了权限正确。如果他们不正确Q你应该看到一个失败的权限信息昄在DDMS屏幕底部的LogCat标签中。此外,L保你的应用程序已l在q行Qƈ在Devices选项卡有l色调试图标在它的旁辏V如果所有这些都不奏效,比较你的目与文中的CZ? 目前为止Q如果你正确地完成了。你的Intent的onReceiveIntent功能被调用,当每一个SMS消息发送到手机上。接下来Q你必d清楚如何得到短信的内宏V? 什么是在一个SMS中? 可悲的是Q到目前为止Android关于接收和过滤SMS信息的文档只不过是q。我怀疑这不是一w要告诉开发h员的重要功能。我不同意这些优先事,但是使我有机会填补空~? 下面是methodonReceiveIntent的代码,功能是监听新的SMS信息Q? 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; } 你还需要输入两个类库来完成q项工作Q? Import android.telephony.gsm.SmsMessage; Import android.provider.Telephony; getMessageFromIntent Ҏ是在 Telephony cM Q?q将q回 SMS 信息的数l。现在剩下的是得到短信的有效蝲荗你要找的触发恶作剧zd的特D代码ؓ文本 “ 0xBADCAT0_Fire_The_Missiles Q?” 它必L一个适当的独特组合,以便它不会被触发事故。你不会希望自己的恶作剧qq提醒受害h太早的? 注意Q在Android里,没有记蝲的功能是很可能还没有完成。由于接收短信的文档几乎不存在,你应该会有些变化在如何处理手机简讯上。更可能的是整体的方法应该是怼的,但它有把握地认ؓ其中的一些细节将改变SDK的前到达它的最l版本。这个例子是有关学习如何使用意图接收器多是有x本的消息通信资料? 触发zd 重要的是要记住,意图接收器的生命周期短,只有只要Ҏ调用onReceiveIntent。一旦出于这一职能QAndroid是免Ҏ死进E中q行你的应用E序。Q何异步功能会dQ如果是一个十分棘手的M开始。如果你惌做超了单的处理Ҏ内的M事情Q你需要启动服务或zd。既然你要同时播N乐和警报你的受害者,他们去过了,你需要启动的一Ҏ动。你完成此情况如下: 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); } 你会看到q里是增?NEW_TASK_LAUNCH ?setLaunchFlags 。你需要做M你要发送的 Intent action Q?启动一Ҏ的活动。此外,正如你在启动画面CZ应用E序Q你必须d一个新的行动,你的Activity的Intent filter。那个过E应该看h很熟悉: <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> 现在 Q?如果你在前面正确地添加了代码 Q?当你?DDMS 透视图中 发?SMS 消息?Q?你应该看C的应用蟩出到前台 Q?昄 “Hello World QPrankActivity ” 文本在屏q上? 索具的活? 一个最后的工作你需要添?Q?在得到卑鄙的音乐播放服务之前 Q?装配 Activity Q?以回应你?Intent Receiver 发送的zd 。如果应用程序正常启动,你要立即关闭了。同P如果可以通过菜单启动Q这样你的恶作剧的计划就会过早的曝光。要做到q一点,你必L索发的IntentQƈ调用getActionҎ来计出在什么情况下Q它已经启动。该PrankActivity的OnCreateҎ现在看v来应该代?-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(); } 首先你会得到发v Activity 的Intent 。用目前得到的 Intent Q?你可以用 getAction Ҏ索调用的行动。这个将q回一个包含启动事件的字符Ԍ你核对你的著名音乐行动列在原来的XML。如果在启动事gZ的活动来自正常的方式Q从菜单或从启动调试器)Q该行动字符串将是null。如果是q样的话Q你要立即用finishҎ关闭zd? 注意QOnCreateҎ被调用当你的应用被首ơ启动时。如果你已经启动你的应用E序Q然后退出(使用q回键)Q应用程序仍然在后台q行。如果在q时Q你发送短信,你的zd回到前収ͼ但其OnStartҎ调用而不是OnCreat? 你今天想i谁呢Q? 虽然可能有些矫枉q正Q你要用Android的service对象来处理音乐播放。我打算q样做有因ؓ另个原因Q? n q是一个好的机会来展示以简单的方式service的用,在简单的环境? n 潜在的,它会让你启动音乐不用看到应用E序Q你的恶作剧的应用E序更卑鄙? 经与服? Z么你要用的服务Q从本质上讲Q它意味着是一个对象,与用L面分ȝ可运行地q程。这是完的情况Q当一个开发h员希望的功能Q无论是|络或多媒体相关Q能够独立运行。例子包括:音频播放Q网l交易的后台Q和邪恶的恶作剧E序。虽然服务允许多个应用程序(打开通信信道Q与他们l定Q你会用它作ؓ一个简单的后台q程。同Pservices有很多用途不只是q个单的例子? 创徏service d一个新cȝ源码包。我已经再次调用PrankServiceQ没有点创意Q。在最基本的层面,service要重写onBindҎ。要获得服务cȝ译,它必ȝQ至有一点点Q如代码2-5? Code Listing 2-5. A Stripped-Down Service public class PrankService extends Service { public IBinder onBind(Intent intent) { return null; } } 在这个例子中Q你不会使用该服务onBindҎq行互动。你可以单地启动和停止服务在你的主要zd内。要做到q一点,你必重写两个方法在服务c: OnStart QInt startId QBundle argument Q? 当OnStart被调用时Q你会开始播攄媒体文g。当服务被破坏,׃明确地停止。这不是必然要求Q但你会明白? 启动服务 开始一个新的服务应该类g开始活动。自从你已经接触到这是几ơ,我就在给你一D代码,让你整理一下?调用前面列出的PrankActivity OnCreateҎ。简单替换注?#8220; We’ll need to start the music service here ”用下面的代码行: startService(new Intent ("com.apress.START_AUDIO_SERVICE"), null ); 同样Q这个看上去很熟悉。启动Activity和启动service之间唯一的区别是Q除了不同的Ҏ调用Q是随Intent传递bundleQ实际上是一个地图或哈希表)参数的能力。这bundle被传递到OnCreateҎ服务? 启动音乐 BREW和Java一PAndroid的媒体播放(单的播放/停止计算Q非常简单易用。当你服务的OnStart函数被调用,你会加蝲和播?res/raw 目录中的试音频文g首先要做的是复制音频h文g导入/res/rawQ如果没有这个目录,l箋q创建它Q。下一步,放下iQƈ复制写入重Q音频文件原始文件夹。如果你使用EclipseQ你应该d相应的元素R.raw。在你的情况下,它的R.raw.test? 现在你有一个音乐文件的引用Q你可以dE序 PrankService 的要求如?Q? public void onStart(int startId, Bundle arguments) { MediaPlayer p; super .onStart(startId, arguments); player = MediaPlayer.create(this , R.raw.test); player.start(); } 误?Q?是一个重写的 OnStart Ҏ Q?因此你必调用父cd一函数?Android 变得不E_。在q一点上Q你需要用MediaPlayer的静态类创徏一个新的媒体播攑֙对象。因为service是context的子c,你将一个指针传递给你当前的context和静态变量代表你的测试媒体。在q一点上Q你可以调用playQ现在你可以开始忙了。播放会l箋在后台运行,直到stopServiceq个Ҏ是由你的主Activity调用? 当stopService被调用时Q下面的Ҏ调用: public void onDestroy() { super.onDestroy(); player.stop(); } 同情的行? 既然你是一个不错的爱开玩笑的h Q?你要l你的受完一个台阶下。正如你之前见过的,Activity是由Intent Receiver触发的,在活动启动服务的旉点上。正如你刚才看到的,service是负责播攑֙声激怒你副dE师。同P因ؓ你是仁慈的在你的执行回报的同Ӟ你必Mؓ受害者设计关闭音乐方法。添加在你的PrankActivity下面的方法可以实C善意的行动: public boolean onKeyDown(int keyCode, KeyEvent event) { stopService(new Intent( "com.apress.START_AUDIO_SERVICE")); finish(); return true; } 配置文g 下面是表现如下所C?Q? <service android:name=".PrankService"> <intent-filter> <action android:name= "com.apress.START_AUDIO_SERVICE" /> <category android:name= "android.intent.category.DEFAULT" /> </intent-filter> </service> 宗和报复的艺术 通过不光明正大的恶作剧应用E序的?Q?你应该明白了 Intents QIntent Receivers Qservices 和Activities 如何 共同在先q的 ?主要是后??应用E序中运行的。我现在要改变一下方式,一步一步做Q你做了什么以及如何实现它? 让我做的更好 你做了以下内容: 1。你使用正确的权限和pȝ接收器的意图U短信的意图安排的对象是PrankSMSReciever每次实例化一个手Z的SMS到达。如果你的Intent Receiver发现一个非常特定的SMS的有效蝲P它将通过发送Intent启动你的活动? 2。这Ҏ动名为PrankActivityQ会监听被PrankSMSReceiver的特定intent action。当它收到确切intent actionQ你的活动将昄一?#8220;gotcha”消息l受完。同Ӟ该活动将发出意图旨在启动服务。如果在M时候受害h/用户按下一个电话上的键Q应用程序将退出,音乐服务终止? 3。服务类Q称为PrankServiceQ监听PrankActivity的intentQ将启动q开始播放o厌,预定义的音频文g。它l播放,直到它被要求停止通过PrankActivity的调用方法stopService? 注意Q此CZ应用E序不涉及手机的本地短信应用。因为所有的intent receiver传入的通知意图Q你的应用将被争夺用户与Android的关注短信收件箱的应用。在生中,q可能需要相当计时器也许触发文本有效载荷Q这是一个微妙多一?“0xBADCAT0_Fire_The_Missiles Q?#8221; 在Android中移动数? 最后,你需要把重点攑֜内容解析器?Android不会lSDK特别的手机文件系l的讉K权限Q如Brew一栗它也没有提供一个RecordStoreQ像Java ME一栗在你的Activities、Intent Receiver和services之间Q你传递数据的主要Ҏ是必通过ContentResolver类。虽然你可以存储数据通过文gQ参敎ͼ和其他数据库Q可以采取许多Ş式,Android附带的几个重要内|content resovlers。这里有一个列表,Android的主要content resovlersQ你可能要经怺动基上: 书签 pȝ讄 Android 的文档提供了非常好的CZ Q?a >http://code.google.com/android/
onDestroyQ)
览?
搜烦历史
电话呼叫
通话记录
最q通话
联系
g讄Q蓝牙,|络讄Q?
软g讄
注意Q可以创Z自己的content providerQ作ZU方式,Z公共讉K装Android的SQLite的执行。你进入如何在后面的章节中q一炏V现在你只是d理content resolver交给?#8220;client”斚w?
Android采用了自定义的SQLite实现Q来存储本地信息。如果你不熟悉SQL的基知识Q现在也许是一个学习的Z。ؓ表述方便Q我要假设你了解基本的SQL查询命o。如果你需要进一步提高,Apress上有一个很好的资源http://apress.com/book/ catalog?category=145 ?
无ȝ自我推销
让我们说一下你的应用程序中“about”部分Q你x一个按钮,d你的商业软g|页到用Lweb书签。你要确保它不添加两ơ,如果你的用户有再ơ点击该按钮意外。ؓ了ɘq个实例单,你将触发q个事g在你CZ应用E序中,当用h下一个键?
注意Q在一个有的注意Q如果你需要证明,作ؓ一个开发h员,Android是还没有完全成熟的,你只要看看比对下文g的android.content.ContentResolverҎgetDataFilePathQ其中规定: “ 请不要用此功能Q有q一点,他们不应该。你没有直接的访问文件内的内Ҏ供商。不要碰q个。走开?“ q是好,知道即是对Android的文档技术作家有q默感?
获取用户的书{?
q应该是显而易见的Q至在q一点,开发h员可以做一些非帔R恶的事情Q访问用L书签。目前还不清楚,在这一点,Android会做什么以防止发生q类事情。我惌得由q营商来锁定或监视此行ؓ。在M情况下,你将使用一个调用方法managedQueryQ它返回一个列表用L书签Q?
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格式提供其多数内部数据的讉KQ你应该习惯于用数据库的方式引你保存的信息。接下来Q你设|游标,一个类似Java ME中RecordStore枚D对象Q设|字W串数值的映射。因Z只关心列包含的网址Q它保存非常单。方法调用managedQuery是调用将q回你的数据。你可以通过URI中ؓ书签存储字符Ԍ交给你了单的映射数|不需要where语句Qƈ告诉它按降序排列的网址?
搜烦l果
搜烦l果很简单只要P代游标对象,是通过单的光标q代对象和退Z列从URL字符串ID你检索前 Q?
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 的内?Q?但现在你会只是看你的 www.apress.com 链接。很明显Q如果此代码的运行是上述Apress|址Q你不会扑ֈ它。因为用户希望添加贵公司的网址在虚拟的“About” ” 部分中,你也要给他们?
使用Content Resolverd邪恶公司|址
也许他们不是邪恶Q但你加入他们。由于Apress也许是公司最邪恶那里Q不是我有偏见,CQ,你让他们摆脱它,只此一ơ。下面是一个美丽的ContentReceiver方式d书签记录Q?
ContentValues inputValues = new ContentValues();
inputValues.put
(android.provider.Browser.BookmarkColumns.BOOKMARK,
"1");
inputValues.put
(android.provider.Browser.BookmarkColumns.URL,
要玩google 手机 G1的模拟器Q当焉要先去google上面下蝲Android的SDKQ解压出来后在SDK的根目录下有一个tools文g夹,里面是模拟器和一些非常有用的工具?/p> 双击“emulator.exe”Q直接启动模拟器Q简单吧。当Ӟ如果要对模拟器进行一些定Ӟq是要从命o行调用,带上参数启动。下面就来介l一下启动是常用的几个参敎ͼ 1.模拟器外观的定制Q?br>480x320, landscape: emulator -skin HVGA-L 2.为模拟器加上SD卡: 下面我们再来说说如何创徏"sdcard.img"文gQ?br>“tools”目录下还有另外一个很好用的工?#8220;mksdcard.exe”Q一看名字就知道——make sdcard。对Q就用它来创Z?#8220;SD?#8221;?/p> 命o为: OK,q样一个容量ؓ1G的SD卡就创徏完毕了?/p> 使用SDCard: 创徏: mksdcard <1024M> <sdcard.img> q接到模拟器: emulator -sdcard <目录/sdcard.img> 传文件到SDCard: adb push <目录/audio.mp3> </sdcard/audio.mp3>
玩过手机模拟器的Z般最感兴的当然是模拟器能做什么呢Q下面一一道来Q?/p> GPhone的模拟器有个Ҏ的号码:15555218135Q这个就cM我们实体手机的SIM卡号码啦。要实现拨号Q用手机Q当然不行! 更简单,三步Q?br>1.q行 cmd lookQ是不是模拟器上昄来电了?接听/挂断和实体手Z栗?/p> 发短信也一L单,重复上面1Q?两步Q第三部命o改一下: 来说说PC与模拟器文g传输的方法吧。这里需要用到另一个重要工P也在“tools”目录下,“adb.exe”?/p> adb: adb(Android Debug Bridge)?span class="t_tag" style="line-height: 19px; ">Android 提供的一个通用的调试工P借助q个工具Q我们可以管理设备或手机 模拟?/span> ?span class="t_tag" style="line-height: 19px; ">状?/span> 。还可以q行以下的操作: 一些常用的操作Q?/p> q入Shell: adb shell 通过上面的命令,可以进入设备或模拟器的shell环境中,在这?span class="t_tag" style="line-height: 19px; ">Linux Shell中,你可以执行各U?span class="t_tag" style="line-height: 19px; ">Linux 的命令,另外如果只想执行一条shell命oQ可以采用以下的方式Q?br>adb shell [command] 上传文g: adb push <PC文g> </tmp/...> 安装E序: adb install <*.apk> 补充一点,通过adb安装的Y?*.apk)都在"/data/app/"目录下,所以安装时不必制定路径Q卸载只需要简单的执行"rm"p?/p> l束adb: adb kill-server 昄android模拟器状? {待正在q行的设? adb wait-for-device 端口转发: adb forward adb forward tcp:5555 tcp:1234 查看bug报告: adb bugreport adb shell sqlite3 讉K数据库SQLite3 应用E序配置文g: ----------------------------------------------------------------------------------- am指o(在shell内用am来加载android应用): am instrument [-e <ARG_NAME> <ARG_VALUE>] 启动览? 拨打电话: 启动google map直接定位到北? ----------------------------------------------------------------------------------- 目录Q?/strong> q里要说明下Q从andorid中得到的文g的字符串的序是按“cd+权限+拥有?数组+大小+日期+名称+链接?#8221;序排列的,其中cd“d”表示的是文g夹,"l"表示的是链接,'-'表示的是文g?/p> 例如d rwxrwx--- system cache 2009-01-09 11:46 cache 上面的目录就是通过解析ls命oq回的字W串q行解析的?/p> ----------------------------------------------------------------------------------- 数据? 联络?含通话记录)数据库:/data/data/com.android.providers.contacts/databases/contacts.db 铃声: /system/media/audio ----------------------------------------------------------------------------------- 安装后: android模拟器和真机的不同之处: * 不支持呼叫和接听实际来电Q但可以通过控制台模拟电话呼?呼入和呼? andoroid模拟器用注意: |
import android.app.Activity;
import android.view.Window;
import android.view.WindowManager;
public class ActivityUtil {
public static void noTitleBar(Activity activity){
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
}
public static void noNotificationBar(Activity activity){
final Window win = activity.getWindow();
win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
public static void fullScreen(Activity activity){
noTitleBar(activity);
noNotificationBar(activity);
}
}
奇怪的?.0以上的版本,
要在.xml中设|?br>AndroidManifest.xml 中activity ?android:theme="@android:style/Theme.NoTitleBar"AndroidManifest.xml 中activity ?android:theme="@android:style/Theme.NoTitleBar"
屏幕大小 320 - 480 480-720
很多学习android的朋友都想看看安装目录里面sample的效?但是使用file-->import ... 选择了root directory ?下面的project没有目选择.试试q样?File-->new-->android project -->选择create project from existing source ...-->选择目录,如果目录选择后Build target没有选择,自己N一?->finish,1.5的sdk一般导入时会自动勾选build target?导入后也不会有什么问?担不?.5?然后build target选择的是1.5?目导入q来?src的包里面会有一个R.java文g,gen目录下面也有一个R.java文g,此时,删除掉src的包里面的那个R.java文g可以了,1.0版本的一些功?.5不支?比如说Phone,1.0有Phoneq个c?里面有挂掉电话的Ҏ,?.0以上的版本不支持q个?有这U情늚话就?.0的target?...