Android FrameWork中的SP、RefBase、weakref_impl,Thread类

来源:互联网 发布:五常知乎 编辑:程序博客网 时间:2024/05/17 08:46

本文转自:http://blog.csdn.net/gzzaigcnforever/article/details/20649781

在阅读Android的Framework处的代码可以发现,无处不在SP给予了我视觉上的冲击,这个是什么?初级的我,看这个当初就基本当成指针来用,熟不知其的内在美,于是在这里和大家一起学习总结SP类的魅力所在。

1 SP这货是个模板类,让我们看下他的结构。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. template <typename T>  
  2. class sp  
  3. {  
  4. public:  
  5.     inline sp() : m_ptr(0) { }  
  6.   
  7.     sp(T* other);  
  8.     sp(const sp<T>& other);  
  9.     template<typename U> sp(U* other);  
  10.     template<typename U> sp(const sp<U>& other);  
  11.   
  12.     ~sp();  
  13.       
  14.     // Assignment  
  15.   
  16.     sp& operator = (T* other);  
  17.     sp& operator = (const sp<T>& other);  
  18.       
  19.     template<typename U> sp& operator = (const sp<U>& other);  
  20.     template<typename U> sp& operator = (U* other);  
  21.       
  22.     // Reset  
  23.     void clear();  
  24.       
  25.     // Accessors  
  26.   
  27.     inline  T&      operator* () const  { return *m_ptr; }  
  28.     inline  T*      operator-> () const { return m_ptr;  }  
  29.     inline  T*      get() const         { return m_ptr; }  
  30.   
  31.     // Operators  
  32.           
  33.     COMPARE(==)  
  34.     COMPARE(!=)  
  35.     COMPARE(>)  
  36.     COMPARE(<)  
  37.     COMPARE(<=)  
  38.     COMPARE(>=)  
  39.   
  40. private:      
  41.     template<typename Y> friend class sp;  
  42.   
  43.     T*              m_ptr;  
  44. };  

看到了上述的代码结构,瞬间觉得其高大上,作为一个经典的模板类,精懂的人说这个类很好,其实没有过多的去了解他只知道是更好的维护对象。这个SP指针内部有个T* m_ptr成员变量,它是真正指向我们new出来的变量。

我们以sp<A> mA = new A();为例,作为一个模板类的构造函数,调用如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. template<typename T>  
  2. sp<T>::sp(T* other)  
  3.     : m_ptr(other)  
  4. {  
  5.     if (other) other->incStrong(this);  
  6. }  

果然,new出来的A对象被存入到sp的成员变量之中,这里看到对mA对象构建时,会调用A的一个incStrong,这个是什么?阅读过代码的都知道一个RefBase类,他是比sp类更为常见的类,我们看她的结构可以发现内容都较多,但都是一些很特别的东西,  我们看下面的UML图来分析我们之间构建的A为何要继承与RefBase。

可以看到继承了RefBase,那么A的对象有东西可以玩了,调用RefBase的incStrong函数,接着看他的实现,先来个构造函数过过瘾:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. RefBase::RefBase()  
  2.     : mRefs(new weakref_impl(this))  
  3. {  
  4. }  

做的东西不多,但是有一个成员变量mRefs,必然他先实现,好吧mRefs被赋值给了一个wekref_impl这个对象,传入的this就是我们的这个new A()对象,好的接着再看看:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. weakref_impl(RefBase* base)  
  2.     : mStrong(INITIAL_STRONG_VALUE)  
  3.     , mWeak(0)  
  4.     , mBase(base)  
  5.     , mFlags(0)  
  6. {  
  7. }  

这里有个mBase,他是一个RefBase类,故按C++的知识,一个从RefBase继承的A类对象被赋值给了mBase,那基类的指针mBase就可以访问类A自带的重载的虚函数了,先留着过会就会用到。

回来我们来看这个刚才other->incStrong(),调用的是基类的incStrong,看他的实现:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void RefBase::incStrong(const void* id) const  
  2. {  
  3.     weakref_impl* const refs = mRefs;//影子对象的refs  
  4.     refs->incWeak(id);  
  5.       
  6.     refs->addStrongRef(id);  
  7.     const int32_t c = android_atomic_inc(&refs->mStrong);  
  8.     ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);  
  9. #if PRINT_REFS  
  10.     ALOGD("incStrong of %p from %p: cnt=%d\n"this, id, c);  
  11. #endif  
  12.     if (c != INITIAL_STRONG_VALUE)  {  
  13.         return;  
  14.     }  
  15.   
  16.     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);  
  17.     refs->mBase->onFirstRef();//mBase维护着继承类实际对象this指针  
  18. }  

这里是增加了对这个指针的引用次数,最重要的一点是关注最后一行代码,在我们写自己类的时候一般都喜欢重载该函数,在这里面对类对象进行必要的初始化。

refs为mRefs,就是我们类A的对象的一个继承成员weakref_impl,该对象有个内部成员mBase,通过上面的分析可知mBase就是指向类A对象的指针,故当访问虚函数时,实际调用的是派生类的重载函数,故最终首次建立一个sp<A> mA 时,就也是所谓的第一次引用吧。

 

2.学一学Android Native的Thread类

上面介绍了很多的类,在onFirstRef里面可以经常会遇到一个run函数,这是启动一个新线程的方法,那就是你的类A 继承了thread类,从上一UML图可以看到,thread有几个核心的函数,最重要的就是一个run函数。来看她的部分代码:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. status_t Thread::run(const char* name, int32_t priority, size_t stack)  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.   
  5.     if (mRunning) {  
  6.         // thread already started  
  7.         return INVALID_OPERATION;  
  8.     }  
  9.   
  10.     // reset status and exitPending to their default value, so we can  
  11.     // try again after an error happened (either below, or in readyToRun())  
  12.     mStatus = NO_ERROR;  
  13.     mExitPending = false;  
  14.     mThread = thread_id_t(-1);  
  15.       
  16.     // hold a strong reference on ourself  
  17.     mHoldSelf = this;  
  18.   
  19.     mRunning = true;  
  20.   
  21.     bool res;  
  22.     if (mCanCallJava) {  
  23.         res = createThreadEtc(_threadLoop,  
  24.                 this, name, priority, stack, &mThread);//启动_threadLoop线程  
  25.     } else {  
  26.         res = androidCreateRawThreadEtc(_threadLoop,  
  27.                 this, name, priority, stack, &mThread);  
  28.     }  
  29.       
  30.     if (res == false) {  
  31.         mStatus = UNKNOWN_ERROR;   // something happened!  
  32.         mRunning = false;  
  33.         mThread = thread_id_t(-1);  
  34.         mHoldSelf.clear();  // "this" may have gone away after this.  
  35.   
  36.         return UNKNOWN_ERROR;  
  37.     }  
  38.       
  39.     // Do not refer to mStatus here: The thread is already running (may, in fact  
  40.     // already have exited with a valid mStatus result). The NO_ERROR indication  
  41.     // here merely indicates successfully starting the thread and does not  
  42.     // imply successful termination/execution.  
  43.     return NO_ERROR;  
  44.   
  45.     // Exiting scope of mLock is a memory barrier and allows new thread to run  
  46. }  

源码上深入的话会比较复杂,但是一点可以肯定的是调用的线程函数是_thread_Loop,看看他的实现:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int Thread::_threadLoop(void* user)  
  2. {  
  3.     Thread* const self = static_cast<Thread*>(user);//派生类对象转为基类指针  
  4. do {  
  5.         bool result;  
  6.         if (first) {  
  7.             first = false;  
  8.             self->mStatus = self->readyToRun();//直接调用继承类的readyToRun  
  9.             result = (self->mStatus == NO_ERROR);  
  10. ......  
  11.            else  
  12.             result = self->threadLoop();  
  13.         }  
  14. }  

这里的self是什么,实际是我们新建的一个对象,那么首次就是调用类A的操作函数readyToRun(),随后一般是调用threadLoop进入线程的循环,线程的退出主要由threadLoop函数的返回结果来决定。

 

3. 好了,下面再来看看这个这几个比较常见的过程,会和C++的多态符合重载有紧密的关系。

比如mA->fun(),一眼看去感觉和普通的指针调用没有区别,但你是否知道mA只是一个sp类的对象,那么这个mA->的操作符是什么?那就是所谓的符合重载,来看sp的几个运算符的重载函数:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. inline  T&      operator* () const  { return *m_ptr; }  
  2.  inline  T*      operator-> () const { return m_ptr;  }  
  3.  inline  T*      get() const         { return m_ptr; }  

很好,可以看到他的实现,不需要输入参数,返回一个m_ptr,m_ptr是什么,前面说过他是我们new A()出来的一个对象,那么调用的就是类A所属的成员函数.类似的还有:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. template<typename T>  
  2. sp<T>& sp<T>::operator = (T* other)  
  3. {  
  4.     if (other) other->incStrong(this);  
  5.     if (m_ptr) m_ptr->decStrong(this);  
  6.     m_ptr = other;  
  7.     return *this;  
  8. }  
  9.   
  10. template<typename T> template<typename U>  
  11. sp<T>& sp<T>::operator = (const sp<U>& other)  
  12. {  
  13.     T* otherPtr(other.m_ptr);  
  14.     if (otherPtr) otherPtr->incStrong(this);  
  15.     if (m_ptr) m_ptr->decStrong(this);  
  16.     m_ptr = otherPtr;  
  17.     return *this;  
  18. }  

分别是对指针与引用的赋值操作。

 

上述的Android Framework里面会经常遇到这些细节性的问题,了解这些基本类往往可以做到事半功倍,阅读代码更加心领神会!


0 1
原创粉丝点击