Android表示函数指针解析

hjh

1.基于Android说明

Android的源代码中,经常会看到如:sp、wp这样的类型定义,这其实是Android中的智能指针。智能指针是C++中的一个概念,通过基于引用计数的方法,解决对象的自动释放的问题。在C++编程中,有两个很让人头痛的问题:一是忘记释放动态申请的对象从而造成内存泄露;二是对象在一个地方释放后,又在别的地方被使用,从而引起内存访问错误。程序员往往需要花费很大精力进行精心设计,以避免这些问题的出现。在使用智能指针后,动态申请的内存将会被自动释放(有点类似Java的垃圾回收),不需要再使用delete来释放对象,也不需要考虑一个对象是否已经在其它地方被释放了,从而使程序编写工作减轻不少,而程序的稳定性大大提高。
Android的智能指针相关的源代码在下面两个文件中:

    frameworks\base\include\utils\RefBase.h
    frameworks\base\libs\utils\RefBase.cpp

涉及的类以及类之间的关系如下图所示:

Android中定义了两种智能指针类型,一种是强指针sp(strong pointer),一种是弱指针(weak pointer)。其实成为强引用和弱引用更合适一些。强指针与一般意义的智能指针概念相同,通过引用计数来记录有多少使用者在使用一个对象,如果所有使用者都放弃了对该对象的引用,则该对象将被自动销毁。

弱指针也指向一个对象,但是弱指针仅仅记录该对象的地址,不能通过弱指针来访问该对象,也就是说不能通过弱智真来调用对象的成员函数或访问对象的成员变量。要想访问弱指针所指向的对象,需首先将弱指针升级为强指针(通过wp类所提供的promote()方法)。弱指针所指向的对象是有可能在其它地方被销毁的,如果对象已经被销毁,wp的promote()方法将返回空指针,这样就能避免出现地址访问错的情况。
是不是很神奇?弱指针是怎么做到这一点的呢?其实说穿了一点也不复杂,原因就在于每一个可以被智能指针引用的对象都同时被附加了另外一个weakref_impl类型的对象,这个对象中负责记录对象的强指针引用计数和弱指针引用计数。这个对象是智能指针的实现内部使用的,智能指针的使用者看不到这个对象。弱指针操作的就是这个对象,只有当强引用计数和弱引用计数都为0时,这个对象才会被销毁。
说了这么多原理,下面该看看到底智能指针该怎么使用了。假设现在有一个类MyClass,如果要使用智能指针来引用这个类的对象,那么这个类需满足下列两个前提条件:
(1) 这个类是基类RefBase的子类或间接子类;
(2) 这个类必须定义虚构造函数,即它的构造函数需要这样定义:
virtual ~MyClass();

满足了上述条件的类就可以定义智能指针了,定义方法和普通指针类似。比如普通指针是这样定义:
MyClass* p_obj;
智能指针是这样定义:
sp p_obj;
注意不要定义成 sp* p_obj。初学者容易犯这种错误,这样实际上相当于定义了一个指针的指针。尽管在语法上没有问题,但是最好永远不要使用这样的定义。
定义了一个智能指针的变量,就可以象普通指针那样使用它,包括赋值、访问对象成员、作为函数的返回值、作为函数的参数等。比如:

p_obj = new MyClass(); // 注意不要写成 p_obj = new sp<MyClass>
sp<MyClass> p_obj2 = p_obj;
p_obj->func();
p_obj = create_obj();
some_func(p_obj);

注意不要试图delete一个智能指针,即 delete p_obj。不要担心对象的销毁问题,智能指针的最大作用就是自动销毁不再使用的对象。不需要再使用一个对象后,直接将指针赋值为NULL即可:
p_obj = NULL;

上面说的都是强指针,弱指针的定义方法和强指针类似,但是不能通过弱指针来访问对象的成员。下面是弱指针的示例:
wp wp_obj = new MyClass();
p_obj = wp_obj.promote(); // 升级为强指针。不过这里要用.而不是->,真是有负其指针之名啊
wp_obj = NULL;

智能指针用起来是很方便,在一般情况下最好使用智能指针来代替普通指针。但是需要知道一个智能指针其实是一个对象,而不是一个真正的指针,因此其运行效率是远远比不上普通指针的。所以在对运行效率敏感的地方,最好还是不要使用智能指针为好。

2.Android开发中应用

在Android开发中,函数指针通常使用JNI(Java Native Interface)来实现。JNI是一个支持Java调用本地代码的框架,它提供了一些接口和工具,可以让我们在Java代码中调用C或C++代码。

在C/C++中定义函数指针时,需要指定函数的类型以及指针的名称,比如:

// 声明一个函数指针类型
typedef void (*FUNC)(int);

// 定义一个函数指针变量
FUNC func_ptr = NULL;

// 定义一个函数
void my_func(int value) {
    printf("value = %d\n", value);
}

// 将函数指针指向 my_func 函数
func_ptr = my_func;

// 通过函数指针调用 my_func 函数
(*func_ptr)(123);

在JNI中,函数指针需要通过映射来实现。我们需要在C/C++中实现一个本地函数,并将它注册到JNI环境中去。然后在Java代码中通过JNI来调用这个本地函数。以下是一个简单的示题:

1、在C/C++中实现本地函数

// 定义一个函数指针类型
typedef void (*FUNC)(int);

// 定义一个本地函数,用于打印传入的数字
void my_func(JNIEnv *env, jclass clazz, jint value) {
    printf("value = %d\n", value);
}

// 注册本地函数
JNIEXPORT void JNICALL
Java_com_example_MyActivity_registerNativeFunc(JNIEnv *env, jclass clazz) {
    jclass cls = env->FindClass("com/example/MyActivity");
    JNINativeMethod methods[] = {
            {"nativeFunc", "(I)V", (void*)&my_func},
    };
    env->RegisterNatives(cls, methods, sizeof(methods) / sizeof(JNINativeMethod));
}

2、在Java中调用本地函数

public class MyActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }

    public native void nativeFunc(int value);

    private void test() {
        // 调用本地函数
        nativeFunc(123);
    }
}

在这个示题中,MyActivity类中定义了一个nativeFunc方法,用于调用本地函数。在Java代码中,通过System.loadLibrary方法来加载C/C++库文件,然后可以直接调用nativeFunc方法来执行本地代码。在本地代码中,通过env->FindClassenv->RegisterNatives方法来注册本地函数,这样就可以在Java中调用它们了。
在这里插入图片描述
Android :Layout控件属性大全

Android :Layout控件属性大全

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值