'Android'에 해당되는 글 53건
- 2009.10.14 <Android market관련 테스트할 때 쉬운 방법 > 2
- 2009.08.28 도넛부터 탑재되는 통합검색솔루션 Android Search
- 2009.08.15 framework 디버그 하기.. 4
- 2009.07.26 PAAD 의 Intent 설명부분.. 3
- 2009.07.24 구글 안드로이드 - JNI : native binding to java
- 2009.07.24 Service를 확장한 class들... 1
- 2009.07.24 android: App to lib call structure 1
- 2009.07.23 Android build system 10
- 2009.07.23 busybox for android
- 2009.07.20 Parcelable Object 만들기 (1) 185
http://www.engadget.com/2009/05/27/
android-2-0-donut-features-demoed-at-google-i-o/
도넛부터 탑재되는 통합검색솔루션
- Web은 물론이고 local의 contacts, mail, application content등을 하나로 검색 관리 가능
이 방법은 "런타임 메뉴 추가"기능을 의미한다.
<activity android:name=".NostromoController">
<intent-filter android:label="궤도로부터의 핵 공격">
<action android:name="com.pad.nostromo.NUKE_FROM_ORBIT"/>
<data android:mimeType="vnd.moonbase.cursor.item/*/>
<category android:name="android.intent.category.ALTERNATIVE"/>
<category android:name="android.intent.category.SELECTED_ALTERNATIVE"/>
</activity>
위 action을 또 다른 액티비티의 메뉴에서 동적으로 사용할 수 있도록 만들 수 있다.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
Intent intent = new Intent();
intent.setData(MoonBaseProvider.CONTENT_URI);
intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE);
int menuGroup = 0;
int menuItemId = 0;
int menuItemOrder = Menu.NONE;
ComponentName caller = getComponentName();
Intent[] specificIntents = null;
MenuItem[] outSpecificItems = null;
menu.addIntentOptions(menuGroup,
menuItemId,
menuItemOrder,
caller,
specificIntents,
intent,
Menu.FLAG_APPEND_TO_GROUP,
outSpecificItems);
return true;
}
** Broadcast Intent **
인텐트는 액티비티를 호출하는데에만 사용하는 것이 아니라 콤포넌트들간에 메시지를 전달하는데 사용될 수 있다. 어플리케이션내에 브로드캐스트수신자를 장착하여 특정 방송메세지에 귀기울이도록 할 수 있다.
// 방송하기
1. Intent 생성
Intent intent = new Intent(NEW_LIFEFORM_DELETED);
intent.putExtra("lifeformName", lifeformType);
intent.putExtra("longitude", currentLongitude);
intent.putExtra("latitude", currentLatitude);
2. send
sendBroadcast(intent);
// 방송듣기
1. BroadcastReceiver 생성
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Content context, Intent intent) {
// TODO :수신한 방송에 대해 처리를 한다.
}
}
2. AndroidManifest.xml에 수신자를 등록한다.
<receiver android:name=".LifeformDeletedBroadcastReceiver">
<intent-filter>
<action android:name="com.paad.action.NEW_LIFEFORM"/>
</intent-filter>
</receiver>
3. 또는 code상에서 수신자를 등록하거나 해재할 수 있다. 이 처럼 동적으로 액티비티가 활성화되어 있을경우에만 수신할 수 있도록 하는 제어가 가능하다.
//등록하기
IntentFilter filter = new IntentFilter(NEW_LIFEFORM_DETECTED);
LifeformDetectedBroadcastReceiver r = new LifeformDetectedBroadcastReceiver();
registerReceiver(r, filter);
// 해재하기
unregisterReceiver( r );
안드로이드 시스템에서 정의되어 있는 방송의 종류는 아래와 같다.
ACTION_BOOT_COMPLETED
ACTION_CAMERA_BUTTON
ACTION_DATE_CHANGED, ACTION_TIME_CHANGED
ACTION_GTALK_SERVICE_CONNECTED, ACTION_GTALK_SERVICE_DISCONNECTED
ACTION_MEDIA_BUTTON
ACTION_MEDIA_EJECT
ACTION_MEDIA_MOUNTED, ACTION_MEDIA_UNMOUNTED
ACTION_SCREEN_OFF, ACTION_SCREEN_ON
ACTION_TIMZONE_CHANGED
// ... http://developer.android.com/reference/android/content/Intent.html
This section presents the ReadFile example program. This example shows how you can use
the Java Native Interface (JNI) to invoke a native method that makes C function calls to map a
file into memory.
language by declaring a native Java method, loading the library that contains the native code,
and then calling the native method. The ReadFile source code below does exactly this.
However, successfully running the program requires a few additional steps beyond compiling
the Java language source file. After you compile, but before you run the example, you have to
generate a header file. The native code implements the function defintions contained in the
generated header file and implements the business logic as well. The following sections walk
through all the steps.
import java.util.*;class ReadFile {
//Native method declaration
native byte[] loadFile(String name);
//Load the library
static {
System.loadLibrary("nativelib");
}
public static void main(String args[]) {
byte buf[];
//Create class instance
ReadFile mappedFile=new ReadFile();
//Call native method to load ReadFile.java
buf=mappedFile.loadFile("ReadFile.java");
//Print contents of ReadFile.java
for(int i=0;i<buf.length;i++) {
System.out.print((char)buf[i]);
}
}
}
In this example, the loadFile function maps onto a C function called Java_ReadFile_loadFile.
The function implementation accepts a String that represents a file name and returns the
contents of that file in the byte array.
native byte[] loadFile(String name); Load the Library
Placing this call in a static initializer ensures this library is only loaded once per class.
The library can be loaded outside of the static block if your application requires it. You might
need to configure your environment so the loadLibrary method can find your native code library.
static {
System.loadLibrary("nativelib");
}
javac ReadFile.java
Next, you need to generate a header file with the native method declaration and implement the
native method to call the C functions for loading and reading a file.
To generate a a header file, run the javah command on the ReadFile class. In this example,
the generated header file is named ReadFile.h. It provides a method signature that you have
to use when you implement the loadfile native function.
javah -jni ReadFile
Note: When running javah on your own classes, be sure to use the fully-qualified class name.
C function. It uses a method signature to map the arguments and return value of the Java
language mappedfile.loadFile method to the loadFile native method in the nativelib library.
Here is the loadFile native method mapping (method signature):
/* * Class: ReadFile * Method: loadFile * Signature: (Ljava/lang/String;)[B */
JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile (JNIEnv *, jobject, jstring);
in the Java virtual machine, and contains mapping and other hosuekeeping information.
jobject: A reference to the method that called this native code. If the calling method is
static, this parameter would be type jclass instead of jobject.
jstring: The parameter supplied to the native method. In this example, it is the name of
the file to be read.
contained in ReadFile.h. The definition is followed by the native method implementation.
JNI provides a mapping for both C and C++ by default.
#include <jni.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>JNIEXPORT jbyteArray JNICALL Java_ReadFile_loadFile
(JNIEnv * env, jobject jobj, jstring name) {
caddr_t m;
jbyteArray jb;
jboolean iscopy;
struct stat finfo;
const char *mfile = (*env)->GetStringUTFChars(
env, name, &iscopy);
int fd = open(mfile, O_RDONLY);if (fd == -1) {
printf("Could not open %sn", mfile);
}
lstat(mfile, &finfo);
m = mmap((caddr_t) 0, finfo.st_size,
PROT_READ, MAP_PRIVATE, fd, 0);
if (m == (caddr_t)-1) {
printf("Could not mmap %sn", mfile);
return(0);
}
jb=(*env)->NewByteArray(env, finfo.st_size);
(*env)->SetByteArrayRegion(env, jb, 0,
finfo.st_size, (jbyte *)m);
close(fd);
(*env)->ReleaseStringUTFChars(env, name, mfile);
return (jb);
}
Map the name generated by JNI to the existing C function name. The Language Issues
section shows how to map between Xbase database functions and Java language code
Use the shared stubs code available from the JNI page on the java.sun.com web site.
Compile the Dynamic or Shared Object Library
runtime. Static or archive libraries are compiled into an executable and cannot be loaded at
runtime. The shared object or dynamic library for the loadFile example is compiled as follows:
Gnu C/Linux:gcc -o libnativelib.so -shared -Wl,-soname,libnative.so
-I/export/home/jdk1.2/include
-I/export/home/jdk1.2/include/linux nativelib.c
-static -lcGnu C++/Linux with Xbaseg++ -o libdbmaplib.so -shared -Wl,-soname,libdbmap.so
-I/export/home/jdk1.2/include
-I/export/home/jdk1.2/include/linux
dbmaplib.cc -static -lc -lxbase
Win32/WinNT/Win2000cl -Ic:/jdk1.2/include
-Ic:/jdk1.2/include/win32
-LD nativelib.c -Felibnative.dll
Run the Example
set the library path to the current directory as follows:
Unix or Linux: LD_LIBRARY_PATH=`pwd` export LD_LIBRARY_PATH
Windows NT/2000/95: set PATH=%path%;.
With the library path properly specified for your platform, invoke the program as you normally would
with the interpreter command:
java ReadFile
아래의 두가지 함수에 대한 안드로이드 상에서의 특별한 제약이 없다면 JNI 을 지원하기 위한 최소한의
조건은 만족된 듯하다
java.lang.System.loadLibary() API, which, does seem to be documented within the android reference:
java.lang.Systemjava.lang
public final classjava.lang.System
java.lang.Object
java.lang.System
Class System provides a standard place for programs to find system related information.
All System API is static.static void load(String pathName) : Loads the specified file as a dynamic library.
static void loadLibrary(String libName) : Loads and links the library specified by the argument.
3. Dynamic & Shard Object Library 만들기
above for instructions. we have also been informed, through this list that you can build native code
on the device, but without UI bindings:
현재 안드로이드의 /system/lib 아래에는 안드로이드 Library들이 .so 형태로 존재함.
전체 과정을 간략히 설명하면,
TARGET_BUILD_VARIANT에 따라서 System Property와 설치될 모듈을
결정합니다. 그 과정을 Makefile을 따라가면서 확인해
보겠습니다.
시작은 open_src폴더 아래 Makefile에서 build/core/main.mk로 이동합니다.
/Makefile
### DO NOT EDIT THIS FILE ### include build/core/main.mk ### DO NOT EDIT THIS FILE ### |
아래 build/core/main.mk를 보면 환경변수
TARGET_BUILD_VARIANT에 따라서 System Property를 다르게 설정하고
있습니다.
Part 1 : /build/core/main.mk
##
user/userdebug ## user_variant := $(filter
userdebug user,$(TARGET_BUILD_VARIANT)) enable_target_debugging
:= true ifneq
(,$(user_variant)) # Target is secure in user builds. ADDITIONAL_DEFAULT_PROPERTIES +=
ro.secure=1 tags_to_install := user ifeq ($(user_variant),userdebug) # Pick up some extra useful tools tags_to_install += debug else # Disable debugging in plain user builds. enable_target_debugging := endif # TODO: Always set WITH_DEXPREOPT (for user
builds) once it works on OSX. # Also, remove the corresponding block in
config/product_config.make. ifeq ($(HOST_OS)-$(WITH_DEXPREOPT_buildbot),linux-true) WITH_DEXPREOPT := true endif # Disallow mock locations by default for
user builds ADDITIONAL_DEFAULT_PROPERTIES +=
ro.allow.mock.location=0 else
# !user_variant # Turn on checkjni for non-user builds. ADDITIONAL_BUILD_PROPERTIES +=
ro.kernel.android.checkjni=1 # Set device insecure for non-user builds. ADDITIONAL_DEFAULT_PROPERTIES +=
ro.secure=0 # Allow mock locations by default for non
user builds ADDITIONAL_DEFAULT_PROPERTIES +=
ro.allow.mock.location=1 endif
# !user_variant ifeq
(true,$(strip $(enable_target_debugging))) # Target is more debuggable and adbd is on
by default ADDITIONAL_DEFAULT_PROPERTIES +=
ro.debuggable=1 persist.service.adb.enable=1 # Include the debugging/testing OTA keys in
this build. INCLUDE_TEST_OTA_KEYS := true else
# !enable_target_debugging # Target is less debuggable and adbd is off
by default ADDITIONAL_DEFAULT_PROPERTIES +=
ro.debuggable=0 persist.service.adb.enable=0 endif
# !enable_target_debugging ##
eng ## ifeq
($(TARGET_BUILD_VARIANT),eng) tags_to_install
:= user debug eng # Don't require the setup wizard on eng
builds #eng모드에서
ro.setupwizard.mode property를 뺍니다. ADDITIONAL_BUILD_PROPERTIES := $(filter-out
ro.setupwizard.mode=%,\ $(call collapse-pairs,
$(ADDITIONAL_BUILD_PROPERTIES))) endif |
TARGET_BUILD_VARIANT에 따른 동작은 아래와 같습니다. Android.mk의 정의된 LOCAL_MODULE_TAGS를 정의하지 않은 모듈은 기본이 user 태그입니다. 따라서 이전에 eng로 설정되어 있는 모듈들이 설치되지 않은 이유는
명시적으로 eng태그를 설정해 주었기 때문입니다.
TARGET_BUILD_VARIANT |
Actions |
eng |
- Installs
modules tagged with: eng, debug, user, and/or development. - Installs
non-APK modules that have no tags specified. - Installs
APKs according to the product definition files, in addition to tagged APKs. - ro.secure=0 - ro.debuggable=1 - ro.kernel.android.checkjni=1 - adb is
enabled by default. |
user |
- Installs
modules tagged with user. - Installs
non-APK modules that have no tags specified. - Installs
APKs according to the product definition files; tags are ignored for APK
modules. - ro.secure=1 - ro.debuggable=0 - adb is
disabled by default. |
userdebug |
The same
as user, except: - Also
installs modules tagged with debug. -
ro.debuggable=1 - adb is
enabled by default. |
빌드시 build/tools/findleaves.sh를 사용해서 각 폴더의 첫번째 Android.mk파일을 모두 찾아서 Makefile에 추가합니다. 하위 폴더에 Android.mk파일이 존재하더라도 상위 폴더에 Android.mk가 존재하면 상위 폴더에 있는 Android.mk까지만
찾습니다.
그리고 현재 Product설정파일의
TARGET_DEVICE의 BoardConfig.mk를 포함시킵니다.
Part 2 : /build/core/main.mk
#
Can't use first-makefiles-under here because #
--mindepth=2 makes the prunes not work. subdir_makefiles += \ $(shell build/tools/findleaves.sh
--prune="./out" $(subdirs) Android.mk) #
Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE) #
or under vendor/*/$(TARGET_DEVICE).
Search in both places, but #
make sure only one exists. #
Real boards should always be associated with an OEM vendor. board_config_mk
:= \ $(strip $(wildcard \
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \ )) ifeq
($(board_config_mk),) $(error No config file found for
TARGET_DEVICE $(TARGET_DEVICE)) endif ifneq
($(words $(board_config_mk)),1) $(error Multiple board config files for
TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk)) endif include $(board_config_mk) TARGET_DEVICE_DIR
:= $(patsubst %/,%,$(dir $(board_config_mk))) board_config_mk
:= #
Clean up/verify variables defined by the board config file. TARGET_BOOTLOADER_BOARD_NAME
:= $(strip $(TARGET_BOOTLOADER_BOARD_NAME)) # #
Include all of the makefiles in the system # ifneq
($(ONE_SHOT_MAKEFILE),) #
We've probably been invoked by the "mm" shell function #
with a subdirectory's makefile. include
$(ONE_SHOT_MAKEFILE) #
Change CUSTOM_MODULES to include only modules that were #
defined by this makefile; this will install all of those #
modules as a side-effect. Do this
after including ONE_SHOT_MAKEFILE #
so that the modules will be installed in the same place they #
would have been with a normal make. CUSTOM_MODULES
:= $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS),)) FULL_BUILD
:= INTERNAL_DEFAULT_DOCS_TARGETS
:= #
Stub out the notice targets, which probably aren't defined #
when using ONE_SHOT_MAKEFILE. NOTICE-HOST-%:
; NOTICE-TARGET-%:
; else include $(subdir_makefiles) endif # ------------------------------------------------------------------- # All module makefiles have
been included at this point. #
------------------------------------------------------------------- |
build/tools/findleaves.sh 동작 예제
$find hardware –name “*.mk” hardware/libhardware/Android.mk hardware/libhardware/modules/overlay/Android.mk hardware/libhardware_legacy/Android.mk hardware/libhardware_legacy/flashlight/Android.mk hardware/libhardware_legacy/gps/Android.mk hardware/libhardware_legacy/led/Android.mk hardware/libhardware_legacy/mount/Android.mk hardware/libhardware_legacy/power/Android.mk hardware/libhardware_legacy/qemu/Android.mk hardware/libhardware_legacy/qemu_tracing/Android.mk hardware/libhardware_legacy/tests/gpstest/Android.mk hardware/libhardware_legacy/uevent/Android.mk hardware/libhardware_legacy/vibrator/Android.mk hardware/libhardware_legacy/wifi/Android.mk hardware/ril/libril/Android.mk hardware/ril/rild/Android.mk hardware/ril/gpstest/Android.mk hardware/ril/libsecril-client/Android.mk hardware/ril/rilclient-test/Android.mk hardware/ril/secril_multi/Android.mk hardware/modules/sensors/Android.mk hardware/msm7k/Android.mk hardware/msm7k/libaudio/Android.mk hardware/msm7k/libcamera/Android.mk hardware/msm7k/libcopybit/Android.mk hardware/msm7k/librpc/Android.mk hardware/msm7k/yuv420sp2rgb/Android.mk $ ./build/tools/findleaves.sh
hardware Android.mk hardware/libhardware/Android.mk
=> 폴더구조의 첫번째 Android.mk만 포함됨 hardware/libhardware_legacy/Android.mk hardware/modules/sensors/Android.mk hardware/msm7k/Android.mk hardware/ril/gpstest/Android.mk hardware/ril/libril/Android.mk hardware/ril/libsecril-client/Android.mk hardware/ril/rilclient-test/Android.mk hardware/ril/rild/Android.mk hardware/ril/secril_multi/Android.mk |
hardware/msm7k/Android.mk 파일에서 아래와 같이
하위의 Android.mk파일을 상황에 따라서 include를
하여 필요한 모듈만 컴파일하여 추가시킬 때 사용할 수 있습니다. (이것을 사용해서 Samsung의 Open Source쪽 변경 소스 관리를 할 수 있을
것으로 보입니다. )
ifneq ($(filter capella7200,
surf, $(TARGET_DEVICE)), ) include $(all-subdir-makefiles) endif |
설치될 모듈들을 선택하고, LOCAL_OVERRIDES_PACKAGES로 선택된 Package를
항목에서 삭제합니다.
Part 3 : build/core/main.mk
#
------------------------------------------------------------------- #
Figure out our module sets. #
Of the modules defined by the component makefiles, #
determine what we actually want to build. #
If a module has the "restricted" tag on it, it #
poisons the rest of the tags and shouldn't appear #
on any list. Default_MODULES
:= $(sort $(ALL_DEFAULT_INSTALLED_MODULES) \
$(ALL_BUILT_MODULES) \ $(CUSTOM_MODULES)) #
TODO: Remove the 3 places in the tree that use #
ALL_DEFAULT_INSTALLED_MODULES and get rid of it from this list. ifdef
FULL_BUILD # The base list of modules to build for
this product is specified # by the appropriate product definition
file, which was included # by product_config.make. user_PACKAGES := $(call
module-installed-files, \ $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES)) ifeq (0,1) $(info user packages for $(TARGET_DEVICE)
($(INTERNAL_PRODUCT)):) $(foreach p,$(user_PACKAGES),$(info
: $(p))) $(error done) endif else # We're not doing a full build, and are
probably only including # a subset of the module makefiles. Don't try to build any modules # requested by the product, because we
probably won't have rules # to build them. user_PACKAGES := endif #
Use tags to get the non-APPS user modules.
Use the product #
definition files to get the APPS user modules. user_MODULES := $(sort $(call
get-tagged-modules,user,_class@APPS restricted)) user_MODULES := $(user_MODULES)
$(user_PACKAGES) eng_MODULES := $(sort $(call
get-tagged-modules,eng,restricted)) debug_MODULES := $(sort $(call
get-tagged-modules,debug,restricted)) tests_MODULES := $(sort $(call
get-tagged-modules,tests,restricted)) ifeq
($(strip $(tags_to_install)),) $(error
ASSERTION FAILED: tags_to_install should not be empty) endif modules_to_install := $(sort
$(Default_MODULES) \ $(foreach
tag,$(tags_to_install),$($(tag)_MODULES))) # Some packages may override
others using LOCAL_OVERRIDES_PACKAGES. # Filter out (do not install)
any overridden packages. overridden_packages
:= $(call get-package-overrides,$(modules_to_install)) ifdef
overridden_packages # old_modules_to_install :=
$(modules_to_install) modules_to_install := \ $(filter-out $(foreach
p,$(overridden_packages),$(p) %/$(p).apk), \ $(modules_to_install)) endif |
추가로Android의 모든 Application은 고유한 Key를 사용해서 Signning을 수행해야 합니다. 어떤 Key로 Signning을
할지를 결정은 LOCAL_CERTIFICATE에 기술합니다.
packages/apps/Camera/Android.mk
LOCAL_PATH:=
$(call my-dir) include
$(CLEAR_VARS) LOCAL_MODULE_TAGS
:= user LOCAL_SRC_FILES
:= $(call all-java-files-under, src) LOCAL_PACKAGE_NAME
:= Camera LOCAL_CERTIFICATE := media #LOCAL_CERTIFICATE :=
vendor/samsung/products/security/media
=> 명시적으로 선택가능 LOCAL_STATIC_JAVA_LIBRARIES
:= googlelogin-client #include
$(BUILD_PACKAGE) #
Use the following include to make our test apk. #include
$(call all-makefiles-under,$(LOCAL_PATH)) |
package.mk파일을 보시면 LOCAL_CERTIFICATE가 설정되지 않으면 testkey가
사용되며, 관련 private와 certificate는
/build/target/product/security/폴더에 있는 key값을 사용합니다.
mkkey.sh => key값을
생성하기 위한 명령어, Samsung Android폰 개발시 고유한 key를 생성해서 출시해야함. media.pk8 media.x509.pem platform.pk8 platform.x509.pem shared.pk8 shared.x509.pem testkey.pk8 testkey.x509.pem |
/build/core/package.mk
#
Pick a key to sign the package with.
If this package hasn't specified #
an explicit certificate, use the default. #
Secure release builds will have their packages signed after the fact, #
so it's ok for these private keys to be in the clear. ifeq ($(LOCAL_CERTIFICATE),) LOCAL_CERTIFICATE := testkey endif # If this is not an absolute
certificate, assign it to a generic one. ifeq ($(dir $(strip
$(LOCAL_CERTIFICATE))),./) LOCAL_CERTIFICATE :=
$(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE) endif private_key :=
$(LOCAL_CERTIFICATE).pk8 certificate :=
$(LOCAL_CERTIFICATE).x509.pem $(LOCAL_BUILT_MODULE):
$(private_key) $(certificate) $(SIGNAPK_JAR) $(LOCAL_BUILT_MODULE):
PRIVATE_PRIVATE_KEY := $(private_key) $(LOCAL_BUILT_MODULE):
PRIVATE_CERTIFICATE := $(certificate) PACKAGES.$(LOCAL_PACKAGE_NAME).PRIVATE_KEY
:= $(private_key) PACKAGES.$(LOCAL_PACKAGE_NAME).CERTIFICATE
:= $(certificate) #
Define the rule to build the actual package. $(LOCAL_BUILT_MODULE):
$(AAPT) | $(ZIPALIGN) $(LOCAL_BUILT_MODULE):
PRIVATE_JNI_SHARED_LIBRARIES := $(jni_shared_libraries) $(LOCAL_BUILT_MODULE):
$(all_res_assets) $(jni_shared_libraries) $(full_android_manifest) @echo "target Package:
$(PRIVATE_MODULE) ($@)" $(create-empty-package) $(add-assets-to-package) ifneq
($(jni_shared_libraries),) $(add-jni-shared-libs-to-package) endif ifneq
($(full_classes_jar),) $(add-dex-to-package) endif $(sign-package) @# Alignment must happen after all other
zip operations. $(align-package) #
Save information about this package PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES
:= $(strip $(LOCAL_OVERRIDES_PACKAGES)) PACKAGES.$(LOCAL_PACKAGE_NAME).RESOURCE_FILES
:= $(all_resources) PACKAGES
:= $(PACKAGES) $(LOCAL_PACKAGE_NAME) |
$ tar -xvf busybox.tar
$ adb shell
# mkdir /data/busybox
# exit
$ adb push busybox /data/busybox
$ adb shell
# cd data/busybox
# ./busybox --install
# export PATH=/data/busybox:$PATH
Parcelable Object 만들기 (1)
![]() ![]() 2009/07/17 16:24 |
[Parcel Class?]
Android의 핵심 중에서 Binder Driver라는 녀석이 있습니다.
Linux Kernel의 driver로 되어 있고, IPC이긴 하지만 기존의 IPC와는 살짝 다른 녀석 입니다.
저도 어떻게 만들었는지는 잘 모릅니다만,
shared memory를 통하여 오버헤드도 적고 프로세스 사이에 비동기로 호출도 이루어 진다고 합니다.
그리고 Binder는 기존 IPC처럼 데이터만 전달 하는게 아니라,
하나의 프로세스에서 다른 프로세스로 Object를 넘길 수도 있게끔 설계 되어 있습니다.
(물론 Serialize 기술을 사용하면 Object도 주고 받을 순 있지요.)
Binder를 통해서 넘기는 메세지 (data 와 object references) 는
Parcel 클래스에 저장이 되어서 넘어가게 됩니다. Parcel은 메세지 컨테이너인 셈이죠.
Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport.
Parcel 클래스는 고성능 IPC 전송을 가능하게 끔 설계가 되어 있기 때문에,
모든 객체에 대해서 평범하게 serialization하지 않습니다.
그래서 모든 Object들을 Binder를 통해 주고 받을 수는 없습니다.
[Parcelable Interface]
Primitive Type과 Primitive Array Type은 기본적으로 parcelable 합니다.
뭐 그냥 일반 데이터인거죠.
그리고 Parcelable Interface를 implements한 클래스가 (당연히) parcelable 합니다.
오늘 우리가 할 일이 바로 이 Parcelable Interface를 사용하여
parcelable Object를 만드는 일 인 것이죠.
사실 parcelable한 type들이 많이 있습니다만, 나머지는 잘 모르겠군요... 어렵습니다.
여튼 오늘은 parcelable Object를 만드는 것만 생각 합시다.
[Parcelable Rect]
Rect 클래스야 다들 쉽게 만드실 겁니다.
left, top, right, bottom 4개의 필드만 있으면 되죠.
integer든 float이든 상관 없습니다만....
Android에는 Rect 클래스의 float 버전이 RectF 클래스 라고 따로 되어 있기 때문에,
저는 integer로 만들겁니다.
public class Rect {
public int left;
public int top;
public int right;
public int bottom;
}
뭐 아주 간단 합니다. 그냥 C에서의 구조체 수준이네요.
이것을 parcelable하게 바꾸어 봅시다.
Step 1.
public class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(left);
dest.writeInt(top);
dest.writeInt(right);
dest.writeInt(bottom);
}
}
Parcelable을 implements하게 되면 꼭 추가해야 한다는 메소드 두 개도 같이 넣었습니다.
내용도 채워 봤어요.
describeContents() 메소드는 일단 건너뛰고...
writeToParcel() 메소드는 Parcel에 데이터를 쓰는 부분 입니다.
그냥 무작정 쓰면 됩니다. 전 아무 생각 없이 순서대로 그냥 썼습니다.
그럼 이제 에러도 없으니 parcelable한 Rect 클래스가 되었느냐... 라고 한다면 아직 아닙니다.
쓰는건 있는데 읽는건 없네요...
Parcel로 부터 값을 읽어 오기 위해서는 Parcelable.Creator Interface 가 필요합니다.
[Parcelable.Creator Interface]
Parcel 에서 Parcelable 클래스의 인스턴스를 만들 때
CREATOR라는 static field를 찾아서 실행 합니다.
CREATOR는 Parcelable.Creator<T> type 으로 만들어져야 하는데
이건 선언과 동시에 반드시 initialize 되어야 합니다.
클래스 따로 만들어서 initialize 하기도 쉽지 않습니다.
그냥 익명 클래스로 만들어 버립시다.
Step 2.
public class Rect implements Parcelable {
public int left;
public int top;
public int right;
public int bottom;
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(left);
dest.writeInt(top);
dest.writeInt(right);
dest.writeInt(bottom);
}
public static final Parcelable.Creator<Rect> CREATOR = new Creator<Rect>() {
public Rect createFromParcel(Parcel source) {
Rect r = new Rect();
r.left = source.readInt();
r.top = source.readInt();
r.right = source.readInt();
r.bottom = source.readInt();
return r;
}
public Rect[] newArray(int size) {
return new Rect[size];
}
};
}
Parcelable.Creator<T> 클래스는 createFromParcel() 과 newArray() 메소스가 필요 합니다.
newArray() 메소드도 일단 넘어가고...
createFromParcel() 메소드를 보면 리턴이 Rect입니다.
그래서 Parcel에서 값을 읽어 새로운 Rect 인스턴스를 리턴 하는 구조로 만들면 끝입니다.
readInt()를 했는데, 이것은 writeToParcel() 메소드에서 썼던 순서대로 읽어 오는 것입니다.
쓸 때는 무작정 썼지만 읽을 때는 조심스럽게 읽어야하죠.
이제 비로소 parcelable Rect 클래스를 만들었습니다.
그냥 별거 없군요...
[Appendix]
위에서 describeContents() 메소드와 newArray() 메소드는 그냥 넘어 갔었습니다.
네... 뭐 사실 잘 모르기도 합니다만,
그냥 보통 parcelable Object를 만드는데에 크게 중요한 부분은 아니지요. 아하하...
describeContents() 에서는 어떤 특별한 객체를 포함하고 있는지에 대한 설명을
리턴값으로 표현 하는 것이라고 보면 됩니다.
bit mask 형식의 integer를 리턴 하며,
값을 체크 할 때 bit mask 체크를 해서 어떤 것들이 들어 있는지 알 수 있습니다.
현재 사용하는 플래그는 Parcelable.CONTENTS_FILE_DESCRIPTOR (0x00000001)
하나 밖에 정의 되어 있지 않습니다.
소스를 다 뒤져 보지 않아서 또 어떤 값들이 쓰이는지는 확인 해보지 못했네요...
newArray() 메소드는 그냥 배열로 만들어서 리턴 하는 겁니다.
Parcel.createTypedArray() 메소드에서 newArray() 메소드를 호출 하는 걸 확인 했습니다.
나중에 createTypedArray() 메소드를 사용 할 일이 있다면 newArray()가 호출이 되는 것이지요.