⑴ 如何分析android bugreport
一、ChkBugReport介紹
ChkBugReport是一個開源工具,它可以把你得到的bugreprot解析成適合閱讀的html文件。導出的html文件包含了根據bugreport數據得出的圖表和分析結論。
它的源碼中用到了以下開源類庫: jQuery ,jsTree jquery plugin , tablednd jQuery plugin , tablesorter jQuery plugin ,js-hotkeys, jquery-cookie 。學習輸出報告文檔型html可以參考源碼。
目前ChkBugReport可以從bugreport數據中抽取出如下信息:
1、Stacktraces ChkBugReport可以從bugreport中解析出輸出bugreport的最後時刻、導致ANR時刻甚至更多時刻的堆棧信息。在例子中你可以看到進程的優先順序和策略都已標示出來,堆棧中耗時的部分顏色是黑紅,一些違反Strict Mode的部分(比如主線程中使用資料庫)顏色標記為亮紅。如果這個線程死鎖,在報告的Errors將會出現。
2、Logs 這部分是對system、main和kernel日誌的分析,在這里你可以看到每個進程內存使用圖、那個程序產生的log最多、Activity的啟動耗時、資料庫操作耗時統計、對象被鎖定時間、AIDL調用時間、Activity和Service的生命周期及其在內存中使用頻率等等,詳見
3、Packages ChkBugReport解析bugreport中存儲的packages.xml並展示一系列的packages、user ids和 permissions。參見
4、Processes 操作app過程中產生的系統事件日誌、內存使用信息等等,參見
5、Battery statistics 電池使用統計信息,參見
6、CPU Frequency statistics CPU頻率統計信息,參見
7、Raw data 被分割成小段的原始數據
同時ChkBugReport也可以檢測到(潛在的)錯誤,這些錯誤在輸出的報告Errors部分中可以找到。你也可以在輸出報告的stacktrace中找到死鎖或一些違反Strict Mode的行為。
二、ChkBugReport使用
使用很簡單:1 java -jar $HOME/Downloads/chkbugreport.jar $HOME/tmp/bugreport.txt
你也可以把chkbugreport.jar加到path下,然後這樣使用1 chkbugreport thebugreport.txt
該工具將根據你的bugreport數據輸出一個分析結果目錄bugreport_out。
你可以使用如下命令取得bugreport:1 adb shell bugreport > bugreport.txt
當然你可以使用ChkBugReport分析bugreport的部分數據比如/data/anr/traces.txt1 chkbugreport -sl:the_system_log.txt -sa:traces.txt mmy
這將輸出分析結果到mmy_out。
你甚至可以使用ChkBugReport分析traceview生成的數據1 chkbugreport -t something.prof
Prof數據生成方法可以參考以下方法:
1、可以使用eclipse插件traceview生成
2、也可以按如下步驟:
a.用adb shell ps列出所有進程並找出你想要trace的進程的PID
b.執行adb shell am profile PID start /data/profile.dat,開始分析
c.操作你的app
d.執行adb shell am profile PID stop ,停止分析
e.導出數據並清除臨時文件:adb pull /data/profile.dat adb shell rm /data/profile.dat
f.使用ChkBugReport進行分析 chkbugreport -t profile.dat
⑵ 如何在Android用FFmpeg解碼圖像
創建一個VideoPicture結構體用來保存解碼出來的圖像。
LOCAL_PATH := $(call my-dir)
###########################
#
# SDL shared library
#
###########################
include $(CLEAR_VARS)
LOCAL_MODULE := SDL2
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := \
$(subst $(LOCAL_PATH)/,, \
$(wildcard $(LOCAL_PATH)/src/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/mmy/*.c) \
$(LOCAL_PATH)/src/atomic/SDL_atomic.c \
$(LOCAL_PATH)/src/atomic/SDL_spinlock.c.arm \
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/cpuinfo/*.c) \
$(wildcard $(LOCAL_PATH)/src/dynapi/*.c) \
$(wildcard $(LOCAL_PATH)/src/events/*.c) \
$(wildcard $(LOCAL_PATH)/src/file/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/mmy/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/filesystem/mmy/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*/*.c) \
$(wildcard $(LOCAL_PATH)/src/stdlib/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/pthread/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/unix/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/test/*.c))
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
include $(BUILD_SHARED_LIBRARY)
###########################
#
# SDL static library
#
###########################
#LOCAL_MODULE := SDL2_static
#LOCAL_MODULE_FILENAME := libSDL2
#LOCAL_SRC_FILES += $(LOCAL_PATH)/src/main/android/SDL_android_main.c
#LOCAL_LDLIBS :=
#LOCAL_EXPORT_LDLIBS := -Wl,--undefined=Java_org_libsdl_app_SDLActivity_nativeInit -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
#include $(BUILD_STATIC_LIBRARY)
二、參考[原]如何在Android用FFmpeg解碼圖像, 在工程中新建一個ffmpeg文件夾,將與ffmpeg相關的頭文件include進來。ffmpeg文件夾下的Android.mk內容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := /path/to/build/ffmpeg/libffmpeg.so
include $(PREBUILT_SHARED_LIBRARY)
三、新建player文件夾,用來編寫解碼與顯示文件。player.c文件內容:
/*
* SDL_Lesson.c
*
* Created on: Aug 12, 2014
* Author: clarck
*/
#include <jni.h>
#include <android/native_window_jni.h>
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_events.h"
#include "../include/logger.h"
#include "../ffmpeg/include/libavcodec/avcodec.h"
#include "../ffmpeg/include/libavformat/avformat.h"
#include "../ffmpeg/include/libavutil/pixfmt.h"
#include "../ffmpeg/include/libswscale/swscale.h"
int main(int argc, char *argv[]) {
char *file_path = argv[1];
LOGI("file_path:%s", file_path);
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameYUV;
AVPacket *packet;
uint8_t *out_buffer;
SDL_Texture *bmp = NULL;
SDL_Window *screen = NULL;
SDL_Rect rect;
SDL_Event event;
static struct SwsContext *img_convert_ctx;
int videoStream, i, numBytes;
int ret, got_picture;
av_register_all();
pFormatCtx = avformat_alloc_context();
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
LOGE("Could not initialize SDL - %s. \n", SDL_GetError());
exit(1);
}
if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
LOGE("can't open the file. \n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
LOGE("Could't find stream infomation.\n");
return -1;
}
videoStream = 1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
LOGI("videoStream:%d", videoStream);
if (videoStream == -1) {
LOGE("Didn't find a video stream.\n");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
LOGE("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
LOGE("Could not open codec.\n");
return -1;
}
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
//---------------------------init sdl---------------------------//
screen = SDL_CreateWindow("My Player Window", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, pCodecCtx->width, pCodecCtx->height,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
SDL_Renderer *renderer = SDL_CreateRenderer(screen, -1, 0);
bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);
//-------------------------------------------------------------//
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
numBytes = avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width,
pCodecCtx->height);
out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P,
pCodecCtx->width, pCodecCtx->height);
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
int y_size = pCodecCtx->width * pCodecCtx->height;
packet = (AVPacket *) malloc(sizeof(AVPacket));
av_new_packet(packet, y_size);
av_mp_format(pFormatCtx, 0, file_path, 0);
while (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet->stream_index == videoStream) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,
packet);
if (ret < 0) {
LOGE("decode error.\n");
return -1;
}
LOGI("got_picture:%d", got_picture);
if (got_picture) {
sws_scale(img_convert_ctx,
(uint8_t const * const *) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data,
pFrameYUV->linesize);
////iPitch 計算yuv一行數據占的位元組數
SDL_UpdateTexture(bmp, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0]);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bmp, &rect, &rect);
SDL_RenderPresent(renderer);
}
SDL_Delay(50);
}
av_free_packet(packet);
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
SDL_Quit();
exit(0);
break;
default:
break;
}
⑶ android怎麼實現ping-Android開發問答
Ping的API調用需要手機擁有root許可權的,代碼如下:
String shellCmd = "ping -c 3 -i 0.2 -w 1 .com";
Process p = Runtime.getRuntime().exec(shellCmd);
⑷ android之animator 和animation 的區別
一、 前言
Animator框架是Android 4.0中新添加的一個動畫框架,和之前的Animation框架相比,Animator可以進行更多和更精細化的動畫控制,而且比之前更簡單和更高效。在4.0源碼中隨處都可以看到Animator的使用。
二、 Animation和Animator比較
如下圖,是Animation和Animator兩個類繼承圖的對比。
C:Object C:Object
C:Animation C:Animator
C:AlphaAnimation C:AnimatorSet
C:AnimationSet C:ValueAnimator
C:DummyAnimation C:ObjectAnimator
C:Rotate3dAnimation C:TimeAnbimator
C:RotateAniamtion
C:ScaleAnimation
C:TranslateAnimation
Animation框架定義了透明度,旋轉,縮放和位移幾種常見的動畫,而且控制的是一個整個View動畫,實現原理是每次繪制視圖時View所在的ViewGroup中的drawChild函數獲取該View的Animation的Transformation值,然後調用canvas.concat(transformToApply.getMatrix()),通過矩陣運算完成動畫幀,如果動畫沒有完成,繼續調用invalidate()函數,啟動下次繪制來驅動動畫,動畫過程中的幀之間間隙時間是繪制函數所消耗的時間,可能會導致動畫消耗比較多的CPU資源。
在Animator框架中使用最多的是AnimatorSet和ObjectAnimator配合,使用ObjectAnimator進行更精細化控制,只控制一個對象的一個屬性值,多個ObjectAnimator組合到AnimatorSet形成一個動畫。而且ObjectAnimator能夠自動驅動,可以調用setFrameDelay(longframeDelay)設置動畫幀之間的間隙時間,調整幀率,減少動畫過程中頻繁繪制界面,而在不影響動畫效果的前提下減少CPU資源消耗。
三、 關鍵介面介紹
1. ObjectAnimator介紹
Animator框架封裝得比較完美,對外提供的介面非常簡單,創建一個ObjectAnimator只需通過如下圖所示的靜態工廠類直接返回一個ObjectAnimator對象。傳的參數包括一個對象和對象的屬性名字,但這個屬性必須有get和set函數,內部會通過java反射機制來調用set函數修改對象屬性值。還包括屬性的初始值,最終值,還可以調用setInterpolator設置曲線函數。
2. AnimatorSet介紹
AnimatorSet主要是組合多個AnimatorSet和ObjectAnimator形成一個動畫,並可以控制動畫的播放順序,其中還有個輔助類通過調用play函數獲得。
3. AnimatorUpdateListner介紹
通過實現AnimatorUpdateListner,來獲得屬性值發生變化時的事件,在這個回調中發起重繪屏幕事件。
四、 使用實例
在Android4.0中的ApiDemo中有個BouncingBalls實例,描述了Animator框架的使用,當點擊屏幕時,繪制一個球從點擊位置掉到屏幕底部,碰到底部時球有壓扁的效果,然後回彈到點擊位置再消失。
代碼如下:
ShapeHolder newBall =addBall(event.getX(), event.getY());
// Bouncing animation with squash and stretch
float startY = newBall.getY();
float endY = getHeight() - 50f;
float h = (float)getHeight();
float eventY = event.getY();
int ration = (int)(500 * ((h - eventY)/h));
ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY);
bounceAnim.setDuration(ration);
bounceAnim.setInterpolator(new AccelerateInterpolator());
ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(),
newBall.getX() - 25f);
squashAnim1.setDuration(ration/4);
squashAnim1.setRepeatCount(1);
squashAnim1.setRepeatMode(ValueAnimator.REVERSE);
squashAnim1.setInterpolator(new DecelerateInterpolator());
ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(),
newBall.getWidth() + 50);
squashAnim2.setDuration(ration/4);
squashAnim2.setRepeatCount(1);
squashAnim2.setRepeatMode(ValueAnimator.REVERSE);
squashAnim2.setInterpolator(new DecelerateInterpolator());
ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY,
endY + 25f);
stretchAnim1.setDuration(ration/4);
stretchAnim1.setRepeatCount(1);
stretchAnim1.setInterpolator(new DecelerateInterpolator());
stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);
ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height",
newBall.getHeight(),newBall.getHeight() - 25);
stretchAnim2.setDuration(ration/4);
stretchAnim2.setRepeatCount(1);
stretchAnim2.setInterpolator(new DecelerateInterpolator());
stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);
ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY,
startY);
bounceBackAnim.setDuration(ration);
bounceBackAnim.setInterpolator(newDecelerateInterpolator());
// Sequence the down/squash&stretch/upanimations
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
// Fading animation - remove the ball when theanimation is done
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animatoranimation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
});
// Sequence the two animations to play oneafter the other
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
// Start the animation
animatorSet.start();
⑸ 如何在Android中使用匯編語言
由於Android環境非常復雜,框架都是用Java,因此要使用C/C++都需要做很多配置,使用匯編的話需要做更多的工作。
我這邊使用的是最新的Android4.0的開發工具,NDK也是最新支持4.0的。這個NDK與老版本的有一些比較明顯的不同。
由於我用的是Mac OS X,因此配置起來比瘟抖死上的要容易許多,你不需要再裝些雜七雜八的第三方工具,直接可以使用你下載好的NDK。
首先,設置目標路徑——在你的Terminal中進入NDK的根目錄,隨後打NDK_PROJECT_PATH="<你要編譯的項目路徑>"。回車,再輸入export NDK_PROJECT_PATH
回車。
這里要注意的是NDK_PROJECT_PATH=後面的路徑需要加引號,否則無效。
由於NDK默認支持的默認編譯選項僅支持ARMv5到ARMv5TE架構,因此如果要使用比較高級的特性的話有兩種方法:
1、你有辦法將TARGET_ARCH_ABI的值變為armeabi-v7a,俺自己試了一下,木有成功。因此可以使用第二種方法,更簡單便捷:
2、在你的NDK目錄下,找到toolchains,然後找到arm-linux-androideabi-x.y.z目錄,在進去可以發現setup.mk文件。找到-march=armv7-a,將上面的神馬#ifdef都去掉,下面的#endif也都刪了。這樣就能確保編譯器使用ARMv7A來編譯。
完成上述操作之後我們就可以先用最簡單的方式來寫匯編了,即內聯匯編——
static int my_thumb(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"bx lr");
return mmy;
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_thumb(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
上述代碼其實就是基於NDK自帶的hello-jni項目修改的。最後用ndk-build可以成功編譯。
上面一段代碼是編譯器默認的使用Thumb/Thumb-2編譯的,因此我裡面寫的內聯匯編的指令都是Thumb代碼。
我們下面將講述一下如何使用ARM代碼並使用NEON指令集。
首先,在你的Android.mk中修改LOCAL_SRC_FILES,要將源文件名後面添加.neon後綴,比如LOCAL_SRC_FILES := hello-jni.c改成LOCAL_SRC_FILES := hello-jni.c.neon。
這里要注意的是你真正的源文件名不要修改,就修改LOCAL_SRC_FILES這個符號的值即可。
然後我們再添加新的變數,來指示ARM GCC使用ARM指令集來編譯——LOCAL_ARM_MODE := arm
這樣就OK了。我們修改一下代碼:
static int my_arm(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"vp.32 q0, r0 \t\n"
"bx lr");
return mmy;
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_arm(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
使用ndk-build後能正常通過編譯。
最後再上個最最高端的。直接寫匯編文件。NDK帶有GAS工具,因此按常理,完全可以寫匯編文件。一般匯編文件的後綴名為.s,因此我們創建一個xxx.s文件即可。
然後我這邊創建一個叫hey.s。在Android.mk中將這個文件添加上:LOCAL_SRC_FILES += hey.s.neon
我們這里看到,為了能在匯編文件中使用NEON指令集,我們在這里也把.neon後綴添加上。匯編器的makefile也認這個標識。
我們編輯hey.s文件:
.text
.align 4
.arm
.globl my_real_arm
my_real_arm:
add r0, r0, #256
vmov q0, q1
vp.32 q0, r0
bx lr
這里要注意的是,在Apple的匯編器中,函數名要加前綴下劃線,而NDK中提供的匯編器則不需要。
我們修改一下hello-jni.c,把這函數調進去:
extern void my_real_arm(int i);
static int my_arm(int mmy)
{
__asm__("movw r0, #1001 \t\n"
"movw r12, #2020 \t\n"
"add r0, r0, r12 \t\n"
"vp.32 q0, r0 \t\n"
"bx lr");
return mmy;
}
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
my_real_arm(0);
my_arm(0);
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
當然,我們為了確保編譯器能夠正確地將ARM和Thumb指令集做混合連接,我們可以在剛才的setup.mk中強制在TARGET_CFLAGS標志里加上-mthumb-interwork
在Windows操作系統中試驗,終於發現,只要將Application.mk中的APP_ABI中的標志,將armeabi去掉,僅留下armeabi-v7a就能順利使用neon了。這樣不需要修改setup.mk,也不需要將Sample中的那個標志判斷去掉,非常方便。
下面列一下可用的Android.mk編譯配置文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloNeon
LOCAL_SRC_FILES := helloneon.c
LOCAL_ARM_MODE := arm
TARGET_CFLAGS += -mthumb-interwork
TARGET_CFLAGS += -std=gnu11
TARGET_CFLAGS += -O3
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_CFLAGS := -DHAVE_NEON=1
LOCAL_SRC_FILES += neontest.s.neon
LOCAL_ARM_NEON := true
endif
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
$(call import-mole,cpufeatures)
在使用JNI時,只需要在你當前項目工程目錄中添加jni文件夾,然後在裡面根據Sample中所提供的文件布局來做即可。當你用ndk-build(Windows下要在cygwin控制台中用ndk-build.cmd)來編譯時, 如果構建成功,則會在libs文件夾內生成一個libXXX.so。然後用Eclipse ADT重新打開你的項目工程,就會發現jni文件目錄以及生成好的so文件都會在你的工程文件目錄中展現出來。當然,你後面也能直接在Eclipse IDE下編輯.s匯編文件,這樣就更容易閱讀了。
最後,在Android匯編器中如果要注釋某條語句,那麼必須使用C89/90中的注釋符——/* ... */
用分號以及後來C++98中所引入的//形式都不管用。
在最新的NDK版本android-ndk-r8d中加入了ARM-Linux GCC4.7以及當前大紅大紫的LLVM Clang3.1。不過由於LLVM Clang3.1的很多編譯選項與GCC有不少區別,因此在使用Clang3.1的時候需要自己去配置相應的編譯選項。這個版本的NDK默認的編譯器工具鏈使用的是GCC4.6版本。如果要使用GCC4.7,那麼可以在Application.mk文件中添加NDK_TOOLCHAIN_VERSION=4.7;如果要使用Clang3.1,那麼可以在Application.mk中添加NDK_TOOLCHAIN_VERSION=clang3.1。下面給出一個合法的Application.mk的內容:
# Build with LLVM Clang3.1
#NDK_TOOLCHAIN_VERSION=clang3.1
# Build with ARM-Linux GCC4.7
NDK_TOOLCHAIN_VERSION=4.7
# Build only ARMv7-A machine code.
APP_ABI := armeabi-v7a
⑹ 按照Android代碼規范,類中的私有成員變數前必須加m嗎
這玩意,根據每個人習慣不同,並沒有一定的標准。
我一般這樣,私有的或者被保護的成員變數,還有方法全部用_開頭,不加類型前綴,而用含義字元串來命名。
比如兩個TextView 一個是標題,一個是用戶名
private TextView _title;
private TextView _userName;
一個方法獲取用戶名
private String _getUserName();
前面加類型前綴的那種匈牙利標記法,對java這種環境不太適合,java開發,前綴區分類型根本不必要,區分含義才比較重要。
共有或者包許可權的就不加_,
public String mmy;
public String getCurrentUser();
這樣好看不說,而且寫出來的東西,知道是什麼含義,注釋都省了。
⑺ 關於android創建文件夾的一個問題
Android4.4開始,如果設備有內部機身存儲,那麼SD就成為二級外部存儲,導致不能寫入文件,因為默認只能寫入以及存儲。在Android開發者網站的「外部存儲技術信息」文檔中的描述:"WRITE_EXTERNAL_STORAGE只為設備上的主要外部存儲授予寫許可權,應用程序無法將數據寫入二級外部存儲設備,除非指定了應用程序允許訪問的特定的目錄。「 Google表示,這樣做的目的是,通過這種方式進行限制,系統可以在應用程序被卸載後清除遺留文件。
這目前隻影響雙存儲設備,果你同時使用了機身存儲和SD卡,那麼應用程序將無法在SD卡中創建、修改、刪除數據。
會寫入到如下位置:
解決辦法:1.對Android手機用戶來講,獲得系統的ROOT許可權是一個解決方法。2.對Android開發者來講,可在應用中嵌入一段代碼,其它方式寫入失敗,則將數據寫入二級存儲設備(這段代碼作用是在Android 4.4+設備上):
1:
最後記得增加許可權
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>