NoClassdefFoundError R$layout

工程引入了jar包,jar包使用了R.layout.xx,但这个layout并没有打进jar包导致找不到R.layout.xx。

It's because inside JAR doesn't contain resource folder of SDK Project.

解决方法有两种:

  1. 导入SDK Project,并以lib的形式依赖。

    如果要把jar包提供出去,则需要使用方法2

  2. 首先,使用下面的方法替代R(在SDK中,R自动为SDK的包名,引入他人工程后肯定找不到这个R,所以不能在SDK中使用R)

    public static int getResourseIdByName(String packageName, String className, String name) {
    Class r = null;
    int id = 0;
    try {
    r = Class.forName(packageName + ".R");

    Class[] classes = r.getClasses();
    Class desireClass = null;

    for (int i = 0; i < classes.length; i++) {
    if(classes[i].getName().split("\\$")[1].equals(className)) {
    desireClass = classes[i];

    break;
    }
    }

    if(desireClass != null)
    id = desireClass.getField(name).getInt(desireClass);
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (IllegalArgumentException e) {
    e.printStackTrace();
    } catch (SecurityException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    } catch (NoSuchFieldException e) {
    e.printStackTrace();
    }

    return id;

    }

    举例,如果以前使用了 R.layout.main,现在需要使用getResourseIdByName(context.getPackageName(), "layout", "main")      以前使用了R.id.mView,现在需要使用getResourseIdByName(context.getPackageName(), "id", "mView")

然后,把用到的资源从SDK中copy到Apk工程。

源自http://stackoverflow.com/questions/14373004/java-lang-noclassdeffounderror-com-facebook-android-rlayout-error-when-using-f

 

Android获得内存信息

在Android中,想要获得进程内存信息,有两类方法

1.exec大法,使用Runtime.getRuntime().exec()方法来执行命令行,主要命令行有 dumpsys(需要system权限)  cat /proc等

private String catProc() {
StringBuilder meminfo = new StringBuilder();
try {
ArrayList<String> commandLine = new ArrayList<String>();
commandLine.add("cat");
// commandLine.add("/proc/meminfo");
commandLine.add("/proc/" + android.os.Process.myPid() + "/status");

Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[commandLine.size()]));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

String line;
while ((line = bufferedReader.readLine()) != null) {
meminfo.append(line);
meminfo.append("\n");
}

} catch (IOException e) {
Log.e(TAG, "Could not read /proc/meminfo", e);
}

Log.i(TAG, "showMeminfo = " + meminfo.toString());

return meminfo.toString();
}

2.android.os.Debug

Debug类有大量的获取内存信息方法,如getPss,用起来很简单

 

使用jar包中的service

要使用jar包或lib中的service,

假如 app包名为 com.app.xx

jar包名为 com.jar.xx

需要在当前app的manifest中声明service,且使用jar包中的包名,全路径,

android:name="com.jar.xx.xxService"

同时声明exported为true

android:exported="true"

<service
android:name="com.jar.xx.xxService"
android:enabled="true"
android:exported="true" />

之后就可以使用am指令打开/关闭service了

打开service ()
adb shell am startservice -n com.app.xx/com.jar.xx.xxService
关闭service
1.adb shell am stopservice -n com.app.xx/com.jar.xx.xxService
2.可能android低版本会不支持 stopservice命令。备用关闭方法: adb shell am force-stop com.app.xx (会关闭整个进程,用kill进程不行,service会自动重启)

Windows 7 命令行调用Android截图命令screencap

目前测试,在Windows 7命令行调用Android截图命令screencap的时候,只能是如此操作才可以

参考链接


Android截图命令screencap

Mac OSX下执行crosstool-ng提示“Your file system ‘xxxx’ is *not* case-sensitive!”

Mac下面使用HomeBrew安装了crosstool-ng来编译树莓派的代码,结果在执行的时候报告如下错误:

比较简单的解决方法就是创建一个支持大小写区分的文件,作为一个分区挂载,然后把代码拷贝到这个分区中执行编译。

1.创建分区文件

2.挂载分区

早期版本的Mac OS X

对于OS X EI Capitan(10.11.5)版本而言,生成的文件名变成了raspberry.dmg.sparseimage因此需要使用这个文件来挂载

挂载后会在桌面生成一个名为Raspberry的磁盘文件夹生成,直接操作这个目录即可。

3.修改crosstool-ng的编译工具下载目录

如下图的方式进行操作:

1.选择"Paths and misc options",并选中"Select"之后点击回车按键

Crosstool-NG-PathAndMiscOptions

2.点击向下的方向按键,,找到"(${Home}/src) Local tarballs directory",这个项,并选中"Select"之后点击回车按键,修改为"/Volumes/raspberry/src",然后继续向下,找到"(${Home}/x-tools/${CT_TARGET}) Prefix directory",这个项,并选中"Select"之后点击回车按键,修改为"/Volumes/raspberry/x-tools/${CT_TARGET}"

Crosstool-NG-PathAndMiscDirectory
Crosstool-NG-PathAndMiscOptionsPrefixDirectoryVolumesraspberry

修改后的结果如下图:

Crosstool-NG-PathAndMiscDirectoryChange
完成操作后,不断快速按下Esc按键,在最后弹出的确认保存窗口中选择保存即可,如下图:

Crosstool-NG-Configure-Save

4.卸载分区

JSON相关:JSON-bundle

JSON转成bundle

这里有一个需要注意的地方,SDK19以后,用wrap可以更好的处理get出来是map、array等问题。

bundle转JSON 也就是遍历bundle

 

学习JNI

JNI,是Android中Java与C互通,用法有两种

1.Java 调用C

2.C调用Java

 

Java调用C比较简单,首先在某个类中声明jni函数

private native void func(String str, String str);

使用javah脚本生成(老司机可以手写)C的头文件,实现该功能即可。

javah使用方法:

在源码根目录,如src目录下,执行

javah packagenamge.class

javah com.android.test.TestClass

 

C调用Java

C调用Java比较繁琐,需要反射找到Java的方法,google的GLEnvironment有一段很标准的写法

头文件

#include <jni.h>

#ifdef __cplusplus
extern "C"
{
#endif
static struct {
jclass clazzGLEnvironment;
jmethodID lastPageQuit;
} gCallJavaMethod;
void callLastPageQuit(int keycode);
void callCreateVideoView();
void callOnFirstFrame();

#ifdef __cplusplus
}
#endif

实现文件

static int register_javaCallMethod(JNIEnv *env) {
jclass clazz = gCallJavaMethod.clazzGLEnvironment;
if (!gCallJavaMethod.clazzGLEnvironment) {
clazz = env->FindClass("com/yunos/tv/blitz/GLEnvironment");
if (clazz == NULL) {
loge("register_javaCallMethod class not exist!!");
} else {
gCallJavaMethod.clazzGLEnvironment = (jclass)env->NewGlobalRef(clazz);
}
}
if (clazz && !gCallJavaMethod.lastPageQuit) {
gCallJavaMethod.lastPageQuit = env->GetStaticMethodID(clazz, "lastPageQuit", "()V");
}
if (gCallJavaMethod.lastPageQuit == NULL) {
loge("lastPageQuit method get fail!!");
}

 

void callLastPageQuit(int keycode) {
logi("kecode:%d", keycode);
if (m_Gl_VM == NULL) {
loge("vm null");
return;
}
if (gCallJavaMethod.lastPageQuit == NULL) {
loge("lastPageQuit null");
return;
}
CHECK_JVM_THREAD(m_Gl_VM);
if (error) {
return;
}
env->CallStaticVoidMethod(gCallJavaMethod.clazzGLEnvironment, gCallJavaMethod.lastPageQuit);
if (attached) {
m_Gl_VM->DetachCurrentThread();
}

}

 

char*-vector

 

1.如果是想要read到vector中,首先给vector分配足够的大小,之后使用&V[0]即可

2.非read情况,想要将vector<char>转为char*的话

局部使用可以直接

c++ 11后支持

非局部需要把vector拷贝到char*,首先给char*分配内存,然后拷贝