NDK开发汇总
双进程守护和卸载监听都使用到了AM命令,应用卸载后的访问网页,命令拉起:
execlp("am", "am", "start","--user","0","-a", "android.intent.action.VIEW", "-d",
"http://www.baidu.com", NULL);
//execlp 是调用命令的函数
在有些手机上如三星fork不出来线程,小米修改了Am的源码导致重新拉起的服务无效
framework.base.cmds.am.src.com.android.commands.am.Am.java
public static void main(String[] args){
(new Am()).run(args);
}
if (args.length < 1) {
onShowUsage(System.out);
return;
}
run调用了父类BaseCommand的抽象方法onRun(),在子类Am中实现了
以开启网页和打电话的命令为例
am start -a andorid.intent.action.VIEW -d http://baidu.com
am start -a android.intent.action.CALL -d 10086
nextArgRequired返回的是start ,
//intent am 开启四大组件 Intent
Intent intent = makeIntent(UserHandle.USER_CURRENT);
命令行的 -d 对应Intent的action
//nextOption 移动到下一个参数
while((opt = nexOption())! = null){
if(opt.equals("-a")){
// action
intent.setAction(nextArgRequired())
}else if(otp.equals("-d")){
data = Uri.parse(nextArgRequired());
if(intent == baseIntent){
hasItentInfo = true;
}
}else
...
intent.setDataAndType(data,type);
}
返回的Intent具备了uri、action ,能够开启一个组件(包括service、broadcast)
返回到runStart中
//aidl文件
private IActivityManger mAm;
void runStart(){
// pm 安装 开启组件
IpacekageManager pm = IpacekageManager.Stub.asInterface(ServcieManager.getService(“package”));
//查询组件 Activity 注册
List<ResovleInfo> activities = pm.queryIntentActivities(intent,mimeType,0,mUserId);
//才能进行下一步跳转
...
//开启组件
res = mAm.startActivityAsUser(null,null,intent,mimeType,null,null,0,mStartFlags,profilerInfo,null,mUserId);
}
gif编码原理
图形控制扩展块(Graphic Control Extension)
注释扩展块
图形文本扩展块
应用程序扩展
a r g b 一个像素 4 个字节
a 24位 r 《16 位 g <位 b
Java方式: Movie类
创建Movie实例,绘制每一帧图片来达到Gif动态效果。
缺点: 部分Gif图片不能自适应大小,播放速度比实际播放速度快,如果要显示的gif过大,还会出现OOM的问题。
GifView
GifView --》GifHelper gif文件 --》编码—》解析 --》播放
Glide 也是采用GifHelper的方式
缺点:OOM的问题
绘制原理
第一步 引入安卓系统加载cif图片的c文件
第二步 JNI加载解析git图片
native-lib.cpp
#include
#include
#include "gif_lib.h"
#include
#include
#include
#define LOG_TAG "david"
#define argb(a,r,g,b) ( ((a) & 0xff) << 24 ) | ( ((b) & 0xff) << 16 ) | ( ((g) & 0xff) << 8 ) | ((r) & 0xff)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
typedef struct GifBean{
int current_frame;
int total_frame;
int *dealys;
} GifBean;
extern "C"{
//绘制一张图片
void drawFrame(GifFileType *gifFileType, GifBean *gifBean, AndroidBitmapInfo info, void *pixels) {
//播放底层代码
// 拿到当前帧
SavedImage savedImage = gifFileType->SavedImages[gifBean->current_frame];
GifImageDesc frameInfo = savedImage.ImageDesc;
//整幅图片的首地址
int* px = (int *)pixels;
// 每一行的首地址
int *line;
// 其中一个像素的位置 不是指针 在颜色表中的索引
int pointPixel;
GifByteType gifByteType;
GifColorType gifColorType;
ColorMapObject* colorMapObject=frameInfo.ColorMap;
px = (int *) ((char*)px + info.stride * frameInfo.Top);
for (int y =frameInfo.Top; y < frameInfo.Top+frameInfo.Height; ++y) {
line=px;
for (int x = frameInfo.Left; x< frameInfo.Left + frameInfo.Width; ++x) {
pointPixel = (y - frameInfo.Top) * frameInfo.Width + (x - frameInfo.Left);
gifByteType = savedImage.RasterBits[pointPixel];
gifColorType = colorMapObject->Colors[gifByteType];
line[x] = argb(255,gifColorType.Red, gifColorType.Green, gifColorType.Blue);
}
px = (int *) ((char*)px + info.stride);
}
}
JNIEXPORT jlong JNICALL
Java_com_dongnao_gifplayerdemo_GifHandler_loadPath(JNIEnv *env, jobject instance, jstring path_) {
const char *path = env->GetStringUTFChars(path_, 0);
int err;
//用系统函数打开一个gif文件 返回一个结构体,这个结构体为句柄
GifFileType * gifFileType=DGifOpenFileName(path, &err);
DGifSlurp(gifFileType);
GifBean *gifBean = (GifBean *) malloc(sizeof(GifBean));
// 清空内存地址
memset(gifBean, 0, sizeof(GifBean));
gifFileType->UserData=gifBean;
gifBean->dealys = (int *) malloc(sizeof(int) * gifFileType->ImageCount);
memset(gifBean->dealys, 0, sizeof(int) * gifFileType->ImageCount);
gifBean->total_frame = gifFileType->ImageCount;
ExtensionBlock* ext;
for (int i = 0; i < gifFileType->ImageCount; ++i) {
SavedImage frame = gifFileType->SavedImages[i];
for (int j = 0; j < frame.ExtensionBlockCount; ++j) {
if (frame.ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) {
ext = &frame.ExtensionBlocks[j];
break;
}
}
if (ext) {
int frame_delay = 10 * (ext->Bytes[2] << 8 | ext->Bytes[1]);
LOGE("时间 %d ",frame_delay);
gifBean->dealys[i] = frame_delay;
}
}
LOGE("gif 长度大小 %d ",gifFileType->ImageCount);
env->ReleaseStringUTFChars(path_, path);
return (jlong) gifFileType;
}
JNIEXPORT jint JNICALL
Java_com_dongnao_gifplayerdemo_GifHandler_getWidth(JNIEnv *env, jobject instance, jlong ndkGif) {
GifFileType* gifFileType= (GifFileType *) ndkGif;
return gifFileType->SWidth;
}
JNIEXPORT jint JNICALL
Java_com_dongnao_gifplayerdemo_GifHandler_getHeight(JNIEnv *env, jobject instance, jlong ndkGif) {
GifFileType* gifFileType= (GifFileType *) ndkGif;
return gifFileType->SHeight;
}
JNIEXPORT jint JNICALL
Java_com_dongnao_gifplayerdemo_GifHandler_updateFrame(JNIEnv *env, jobject instance, jlong ndkGif,
jobject bitmap) {
//强转代表gif图片的结构体
GifFileType *gifFileType= (GifFileType *)ndkGif;
GifBean * gifBean= (GifBean *) gifFileType->UserData;
AndroidBitmapInfo info;
//代表一幅图片的像素数组
void *pixels;
AndroidBitmap_getInfo(env,bitmap,&info);
//锁定bitmap 一幅图片--》二维 数组 ===一个二维数组
AndroidBitmap_lockPixels(env,bitmap,&pixels);
// TODO
drawFrame(gifFileType, gifBean, info, pixels);
//播放完成之后 循环到下一帧
gifBean->current_frame+=1;
LOGE("当前帧 %d ",gifBean->current_frame);
if (gifBean->current_frame >= gifBean->total_frame-1) {
gifBean->current_frame=0;
LOGE("重新过来 %d ",gifBean->current_frame);
}
AndroidBitmap_unlockPixels(env, bitmap);
return gifBean->dealys[gifBean->current_frame];
}
}
第3步, 调用显示
public class GifHandler {
private long gifAddr;
public GifHandler(String path) {
this.gifAddr = loadPath(path);
}
static {
System.loadLibrary("native-lib");
}
private native long loadPath(String path);
public native int getWidth(long ndkGif);
public native int getHeight(long ndkGif);
public native int updateFrame(long ndkGif, Bitmap bitmap);
public int getWidth() {
return getWidth(gifAddr);
}
public int getHeight() {
return getHeight(gifAddr);
}
public int updateFrame(Bitmap bitmap) {
return updateFrame(gifAddr,bitmap);
}
}
public class MainActivity extends AppCompatActivity {
Bitmap bitmap;
GifHandler gifHandler;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView= (ImageView) findViewById(R.id.image);
}
public void ndkLoadGif(View view) {
File file=new File(Environment.getExternalStorageDirectory(),"demo.gif");
gifHandler = new GifHandler(file.getAbsolutePath());
Log.i("tuch", "ndkLoadGif: "+file.getAbsolutePath());
//得到gif width height 生成Bitmap
int width=gifHandler.getWidth();
int height=gifHandler.getHeight();
bitmap= Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
int nextFrame=gifHandler.updateFrame(bitmap);
handler.sendEmptyMessageDelayed(1,nextFrame);
}
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
int mNextFrame=gifHandler.updateFrame(bitmap);
handler.sendEmptyMessageDelayed(1,mNextFrame);
imageView.setImageBitmap(bitmap);
}
};
}
注意:要把显示的gif图片导入到手机对应的加载目录
GifPlayerDemo