⑴ 如何在android的jni线程中实现回调
jni回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。
其中一种在Android系统的解决方案是:
把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。
假设有c++函数:
[cpp] view plain
void *thread_entry(void *args)
{
while(1)
{
printf("thread running...\n");
sleep(1);
}
}
void init()
{
pthread_t thread;
pthread_create(&thread,NULL,thread_entry,(void *)NULL);
}
init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive:
[cpp] view plain
public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback:" + msg;
Log.d("Test", msg);
}
首先在c++中定义回调函数指针:
[cpp] view plain
//test.h
#include <pthread.h>
//function type for receiving data from native
typedef void (*ReceiveCallback)(unsigned char *buf, int len);
/** Callback for creating a thread that can call into the Java framework code.
* This must be used to create any threads that report events up to the framework.
*/
typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg);
typedef struct{
ReceiveCallback recv_cb;
CreateThreadCallback create_thread_cb;
}Callback;
再修改c++中的init和thread_entry函数:
[cpp] view plain
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include "test.h"
void *thread_entry(void *args)
{
char *str = "i'm happy now";
Callback cb = NULL;
int len;
if(args != NULL){
cb = (Callback *)args;
}
len = strlen(str);
while(1)
{
printf("thread running...\n");
//invoke callback method to java
if(cb != NULL && cb->recv_cb != NULL){
cb->recv_cb((unsigned char*)str, len);
}
sleep(1);
}
}
void init(Callback *cb)
{
pthread_t thread;
//pthread_create(&thread,NULL,thread_entry,(void *)NULL);
if(cb != NULL && cb->create_thread_cb != NULL)
{
cb->create_thread_cb("thread",thread_entry,(void *)cb);
}
}
然后在jni中实现回调函数,以及其他实现:
[cpp] view plain
//jni_test.c
#include <stdlib.h>
#include <malloc.h>
#include <jni.h>
#include <JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "test.h"
#define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test"
using namespace android;
static jobject mCallbacksObj = NULL;
static jmethodID method_receive;
static void (JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
LOGE("An exception was thrown by callback '%s'.", methodName);
LOGE_EX(env);
env->ExceptionClear();
}
}
static void receive_callback(unsigned char *buf, int len)
{
int i;
JNIEnv* env = AndroidRuntime::getJNIEnv();
jcharArray array = env->NewCharArray(len);
jchar *pArray ;
if(array == NULL){
LOGE("receive_callback: NewCharArray error.");
return;
}
pArray = (jchar*)calloc(len, sizeof(jchar));
if(pArray == NULL){
LOGE("receive_callback: calloc error.");
return;
}
// buffer to jchar array
for(i = 0; i < len; i++)
{
*(pArray + i) = *(buf + i);
}
// buffer to jcharArray
env->SetCharArrayRegion(array,0,len,pArray);
//invoke java callback method
env->CallVoidMethod(mCallbacksObj, method_receive,array,len);
//release resource
env->DeleteLocalRef(array);
free(pArray);
pArray = NULL;
(env, __FUNCTION__);
}
static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
}
static Callback mCallbacks = {
receive_callback,
create_thread_callback
};
static void jni_class_init_native
(JNIEnv* env, jclass clazz)
{
method_receive = env->GetMethodID(clazz, "Receive", "([CI)V");
}
static int jni_init
(JNIEnv *env, jobject obj)
{
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(obj);
return init(&mCallbacks);
}
static const JNINativeMethod gMethods[] = {
{ "class_init_native", "()V", (void *)jni_class_init_native },
{ "native_init", "()I", (void *)jni_init },
};
static int registerMethods(JNIEnv* env) {
const char* const kClassName = RADIO_PROVIDER_CLASS_NAME;
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName);
if (clazz == NULL) {
LOGE("Can't find class %s/n", kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)
{
LOGE("Failed registering methods for %s/n", kClassName);
return -1;
}
/* fill out the rest of the ID cache */
return 0;
}
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
LOGI("Radio JNI_OnLoad");
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("ERROR: GetEnv failed/n");
goto fail;
}
if(env == NULL){
goto fail;
}
if (registerMethods(env) != 0) {
LOGE("ERROR: PlatformLibrary native registration failed/n");
goto fail;
}
/* success -- return valid version number */
result = JNI_VERSION_1_4;
fail:
return result;
}
jni的Android.mk文件中共享库设置为:
[cpp] view plain
LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper
最后再实现Java中的Test类:
[java] view plain
//com.tonny.Test.java
public class Test {
static{
try {
System.loadLibrary("test");
class_init_native();
} catch(UnsatisfiedLinkError ule){
System.err.println("WARNING: Could not load library libtest.so!");
}
}
public int initialize() {
return native_radio_init();
}
public void Receive(char buffer[],int length){
String msg = new String(buffer);
msg = "received from jni callback" + msg;
Log.d("Test", msg);
}
protected static native void class_init_native();
protected native int native_init();
}
⑵ android 的try catch 具体能处理什么问题 简单介绍 给个简单的例子
try{
//代码区
}catch(Exceptione){
//异常处理
}
代码区如果有错误,就会返回所写异常的处理。
首先要清楚,如果没有try的话,出现异常会导致程序崩溃。
而try则可以保证程序的正常运行下去,比如说:
try{
inti=1/0;
}catch(Exceptione){
........
}
一个计算的话,如果除数为0,则会报错,如果没有try的话,程序直接崩溃。用try的话,则可以让程序运行下去,并且输出为什么出错!
trycatch是捕捉try部分的异常,当你没有trycatch的时候,如果出现异常则程序报错,加上trycatch,出现异常程序正常运行,只是把错误信息存储到Exception里,所以catch是用来提取异常信息的,你可以在Catch部分加上一句System.out.println(e.ToString());,如果出现异常可以把异常打印出来
⑶ android中的try catch不执行
说明代码写的有问题,建议debug调式运行,异常都会在logcat中输出的。
找到Logcat视图的方式:
1. Eclipse 点击 Window。
2. Show View会出来一个对话框。
3. 点击Ok按钮时,会在控制台窗口出现LogCat视图。
⑷ android开发怎么会出现数据库错误
1. 异常机制
1.1 异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。
1.2 传统的处理异常的办法是,函数返回一个特殊的结果来表示出现异常(通常这个特殊结果是大家约定俗称的),调用该函数的程序负责检查并分析函数返回的结果。这样做有如下的弊端:例如函数返回-1代表出现异常,但是如果函数确实要返回-1这个正确的值时就会出现混淆;可读性降低,将程序代码与处理异常的代码混爹在一起;由调用函数的程序来分析错误,这就要求客户程序员对库函数有很深的了解。
1.3 异常处理的流程
1.3.1 遇到错误,方法立即结束,并不返回一个值;同时,抛出一个异常对象
1.3.2 调用该方法的程序也不会继续执行下去,而是搜索一个可以处理该异常的异常处理器,并执行其中的代码
2 异常的分类
2.1 异常的分类
2.1.1 异常的继承结构:基类为Throwable,Error和Exception继承Throwable,RuntimeException和 IOException等继承Exception,具体的RuntimeException继承RuntimeException。
2.1.2 Error和RuntimeException及其子类成为未检查异常(unchecked),其它异常成为已检查异常(checked)。
2.2 每个类型的异常的特点
2.2.1 Error体系 Error类体系描述了Java运行系统中的内部错误以及资源耗尽的情形。应用程序不应该抛出这种类型的对象(一般是由虚拟机抛出)。如果出现这种错误,除了尽力使程序安全退出外,在其他方面是无能为力的。所以,在进行程序设计时,应该更关注Exception体系。
2.2.2 Exception体系 Exception体系包括RuntimeException体系和其他非RuntimeException的体系
2.2.2.1 RuntimeException RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等。处理RuntimeException的原则是:如果出现 RuntimeException,那么一定是程序员的错误。例如,可以通过检查数组下标和数组边界来避免数组越界访问异常。
2.2.2.2 其他(IOException等等)这类异常一般是外部错误,例如试图从文件尾后读取数据等,这并不是程序本身的错误,而是在应用环境中出现的外部错误。
2.3 与C++异常分类的不同
2.3.1 其实,Java中RuntimeException这个类名起的并不恰当,因为任何异常都是运行时出现的。(在编译时出现的错误并不是异常,换句话说,异常就是为了解决程序运行时出现的的错误)。
2.3.2 C++中logic_error与Java中的RuntimeException是等价的,而runtime_error与Java中非RuntimeException类型的异常是等价的。
3 异常的使用方法
3.1 声明方法抛出异常
3.1.1 语法:throws(略)
3.1.2 为什么要声明方法抛出异常?方法是否抛出异常与方法返回值的类型一样重要。假设方法抛出异常确没有声明该方法将抛出异常,那么客户程序员可以调用这个方法而且不用编写处理异常的代码。那么,一旦出现异常,那么这个异常就没有合适的异常控制器来解决。
3.1.3 为什么抛出的异常一定是已检查异常? RuntimeException与Error可以在任何代码中产生,它们不需要由程序员显示的抛出,一旦出现错误,那么相应的异常会被自动抛出。而已检查异常是由程序员抛出的,这分为两种情况:客户程序员调用会抛出异常的库函数(库函数的异常由库程序员抛出);客户程序员自己使用throw语句抛出异常。遇到Error,程序员一般是无能为力的;遇到RuntimeException,那么一定是程序存在逻辑错误,要对程序进行修改(相当于调试的一种方法);只有已检查异常才是程序员所关心的,程序应该且仅应该抛出或处理已检查异常。
3.1.4 注意:覆盖父类某方法的子类方法不能抛出比父类方法更多的异常,所以,有时设计父类的方法时会声明抛出异常,但实际的实现方法的代码却并不抛出异常,这样做的目的就是为了方便子类方法覆盖父类方法时可以抛出异常。
3.2 如何抛出异常
3.2.1 语法:throw(略)
3.2.2 抛出什么异常?对于一个异常对象,真正有用的信息时异常的对象类型,而异常对象本身毫无意义。比如一个异常对象的类型是 ClassCastException,那么这个类名就是唯一有用的信息。所以,在选择抛出什么异常时,最关键的就是选择异常的类名能够明确说明异常情况的类。
3.2.3 异常对象通常有两种构造函数:一种是无参数的构造函数;另一种是带一个字符串的构造函数,这个字符串将作为这个异常对象除了类型名以外的额外说明。
3.2.4 创建自己的异常:当Java内置的异常都不能明确的说明异常情况的时候,需要创建自己的异常。需要注意的是,唯一有用的就是类型名这个信息,所以不要在异常类的设计上花费精力。
3.3 捕获异常如果一个异常没有被处理,那么,对于一个非图形界面的程序而言,该程序会被中止并输出异常信息;对于一个图形界面程序,也会输出异常的信息,但是程序并不中止,而是返回用户界面处理循环中。
3.3.1 语法:try、catch和finally(略)控制器模块必须紧接在try块后面。若掷出一个异常,异常控制机制会搜寻参数与异常类型相符的第一个控制器随后它会进入那个catch 从句,并认为异常已得到控制。一旦catch 从句结束对控制器的搜索也会停止。 3.3.1.1 捕获多个异常(注意语法与捕获的顺序)(略)
3.3.1.2 finally的用法与异常处理流程(略)
3.3.2 异常处理做什么?对于Java来说,由于有了垃圾收集,所以异常处理并不需要回收内存。但是依然有一些资源需要程序员来收集,比如文件、网络连接和图片等资源。
3.3.3 应该声明方法抛出异常还是在方法中捕获异常?原则:捕捉并处理哪些知道如何处理的异常,而传递哪些不知道如何处理的异常
3.3.4 再次抛出异常
3.3.4.1 为什么要再次抛出异常?在本级中,只能处理一部分内容,有些处理需要在更高一级的环境中完成,所以应该再次抛出异常。这样可以使每级的异常处理器处理它能够处理的异常。
3.3.4.2 异常处理流程对应与同一try块的catch块将被忽略,抛出的异常将进入更高的一级。
4 关于异常的其他问题
4.1 过度使用异常首先,使用异常很方便,所以程序员一般不再愿意编写处理错误的代码,而仅仅是简简单单的抛出一个异常。这样做是不对的,对于完全已知的错误,应该编写处理这种错误的代码,增加程序的鲁棒性。另外,异常机制的效率很差。
4.2 将异常与普通错误区分开对于普通的完全一致的错误,应该编写处理这种错误的代码,增加程序的鲁棒性。只有外部的不能确定和预知的运行时错误才需要使用异常。
4.3 异常对象中包含的信息一般情况下,异常对象唯一有用的信息就是类型信息。但使用异常带字符串的构造函数时,这个字符串还可以作为额外的信息。调用异常对象的getMessage()、toString()或者printStackTrace()方法可以分别得到异常对象的额外信息、类名和调用堆栈的信息。并且后一种包含的信息是前一种的超集。
请对照分析你的错误类型
⑸ android怎么阻止完成try和catch函数
可以用以下两种方法试试:
1,label懂得自己更新,label.Text=...不必放在panel1_Paint()里面。panel1_Paint应只做和画图相关的事情。
2,用int.TryParse()而不是Convert.ToInt32(),int.TryParse()不成功的时候也不会抛出异常。当它不成功可以用一个默认值。
⑹ android中google有一个方法可以替代 Thread.sleep()方法来着。它不需要try catch,叫啥
如果是想延时一下,在处理业务逻辑的话,可以使用handler类提供的方法:handler.postDelayed()直接延时操作
⑺ androidstudio中怎么捕获异常
//可以使用try catch finally语句来捕获异常。
//代码格式:
try{
//如果要捕获异常,需要将代码放置在这try的代码块范围内
}catch(IOException ex){//异常范围IOException 以及它的派生类异常
//此处编写发生 IOException 或其派生类异常时处理方案
}catch(Exception ex){//异常范围Exception 以及它的派生类异常
//此处编写发生Exception 或其派生类异常时处理方案
}finally{
//此处无论上方的代码中是否出现了异常、return语句,这里必定执行。
}
/*
try catch语句至少需要有一个catch,却可以同时有多个catch。
其中catch语句块的异常范围从上到下顺序书写时应当从小范围到达范围,如果将Exception的catch与IOException的catch位置对换,那么永远不会执行IOException的catch块的代码
finally语句代码块是可选的。可以有它,也可以不使用它,具体是否启用它需要根据业务逻辑决定
*/
⑻ Android编程,怎样让整个activity都运行在try-catch中,总是因为点小错误就闪退
Activity本身没错,错的是你的业务逻辑,你把逻辑抽出到Service类,再调用,加上try捕捉吧。
你的想法有点偏。
不记得了,在Application的实例里面可以设置未捕捉异常的处理,这也可以。
⑼ android代码,我无论如何也无法在主线程中等待dialog的出现
自己看看书把,在子线程中发消息出来,然后在主线程接受到消息的时候弹出dialog
⑽ android studio 怎么快速加try catch
快捷键: Ctrl + Alt + S
1.选择try catch
2.选择try finally
3.选择try catch finally