After reading the code at the Android Framework, I can find that the ubiquitous SP has a visual impact on me. What is this? At the beginning, I think this is basically used as a pointer, and I don't know its internal beauty. So I will learn and sum up the charm of the SP class here.
1 SP this product is a template class. Let's look at its structure.
template
class sp{public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp
& other); template
sp(U* other); template
sp(const sp
& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp
& other); template
sp& operator = (const sp
& other); template sp& operator = (U* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=)private: template friend class sp; T* m_ptr;};
Seeing the above code structure, I instantly think it is very tall. As a classic template class, well-understood people say this class is good, in fact, he does not know much about it, but only knows it is a better maintenance object. The SP pointer contains a T * m_ptr member variable, which actually points to the new variable.
We use sp mA = new A (); as an example to call the constructor of A template class as follows:
template sp ::sp(T* other) : m_ptr(other){ if (other) other->incStrong(this);}
Indeed, the new object A is saved to the member variable of the sp. here we can see that an incStrong of a will be called when building the mA object. What is this? All those who have read the code know a RefBase class, which is more common than the sp class. We can see that there are many contents in her structure, but they are all very special things, let's take A look at the UML diagram below to analyze why A built between us should inherit and RefBase.
We can see that RefBase is inherited, so A's object has something to play with. Call RefBase's incStrong function, and then let's look at its implementation. First, A constructor is quite enjoyable:
RefBase::RefBase() : mRefs(new weakref_impl(this)){}
There are not many things to do, but there is A member variable mRefs, which must be implemented first. Well, mRefs is assigned A wekref_impl object, and the incoming this is our new () object. Now let's take a look:
weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { }
Here there is an mBase, which is A RefBase class, so according to the C ++ knowledge, A Class A Object inherited from RefBase is assigned to mBase, the base class pointer mBase can be used to reload the virtual functions that come with Class.
Back, let's take a look at other-> incStrong () and call the base class incStrong. Let's look at its implementation:
Void RefBase: incStrong (const void * id) const {weakref_impl * const refs = mRefs; // refs-> incWeak (id) of the Shadow object ); refs-> addStrongRef (id); const int32_t c = android_atomic_inc (& refs-> mStrong); ALOG_ASSERT (c> 0, "incStrong () called on % p after last strong ref ", refs); # if PRINT_REFS ALOGD (" incStrong of % p from % p: cnt = % d \ n ", this, id, c); # endif if (c! = INITIAL_STRONG_VALUE) {return;} android_atomic_add (-INITIAL_STRONG_VALUE, & refs-> mStrong); refs-> mBase-> onFirstRef (); // mBase maintains the actual object this pointer of the inheritance class}
Here we have increased the number of references to this pointer. The most important thing is to pay attention to the last line of code. We generally like to reload this function when writing our own classes, perform necessary initialization for class objects.
Refs is mRefs, which is an inherited member weakref_impl of the object in Class A. The object has an internal Member mBase. The above analysis shows that mBase is A pointer to Class A objects, therefore, when you access a virtual function, you actually call the overload function of the derived class. Therefore, when you create an sp mA for the first time, it is also called the first reference.
2. Learn the Thread class of Android Native
Many classes are introduced above. In onFirstRef, you may often encounter A run function. This is the method to start A new thread, that is, your class A inherits the thread class, from the UML diagram above, we can see that thread has several core functions, the most important of which is a run function. Let's look at some of her code:
Status_t Thread: run (const char * name, int32_t priority, size_t stack) {Mutex: Autolock _ l (mLock); if (mRunning) {// thread already started return INVALID_OPERATION;} // reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun () mStatus = NO_ERROR; mExitPending = false; mThread = thread_id_t (-1); // hold a strong referenc E on ourself mHoldSelf = this; mRunning = true; bool res; if (mCanCallJava) {res = createThreadEtc (_ threadLoop, this, name, priority, stack, & mThread ); // start _ threadLoop thread} else {res = androidCreateRawThreadEtc (_ threadLoop, this, name, priority, stack, & mThread);} if (res = false) {mStatus = UNKNOWN_ERROR; // something happened! MRunning = false; mThread = thread_id_t (-1); mHoldSelf. clear (); // "this" may have gone away after this. return UNKNOWN_ERROR;} // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result ). the NO_ERROR indication // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return NO_ERROR; // Exiting scope of mLock is a memory barrier and allows new thread to run}
It will be complicated to go deep in the source code, but it is certain that the called thread function is _ thread_Loop. Let's look at its implementation:
Int Thread: _ threadLoop (void * user) {Thread * const self = static_cast (User); // the object of the derived class is converted to do {bool result; if (first) {first = false; self-> mStatus = self-> readyToRun (); // directly call readyToRun result = (self-> mStatus = NO_ERROR) of the inheritance class );...... else result = self-> threadLoop ();}}
What is self here? It is actually A new object, so the first time it is to call the operation function readyToRun () of Class A, it is generally to call threadLoop to enter the thread loop, the exit of a thread is mainly determined by the result returned by the threadLoop function.
3. Now let's take a look at these common processes, which will be closely related to the C ++ polymorphism and heavy load.
For example, mA-> fun (). At a glance, it seems that it is no different from a normal pointer call, but do you know that mA is only an object of the sp class, so what is the mA-> operator? This is the so-called reload-compliant function. Let's see the reload functions of several sp operators:
inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; }
Well, we can see his implementation. Without entering A parameter, we will return A m_ptr and m_ptr. As we mentioned earlier, it is an object from new, the member function to which class A belongs is called. similar:
template sp & sp ::operator = (T* other){ if (other) other->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = other; return *this;}template template sp & sp ::operator = (const sp & other){ T* otherPtr(other.m_ptr); if (otherPtr) otherPtr->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = otherPtr; return *this;}
Assign values to pointers and references respectively.
The above Android Framework often encounters these detailed problems. Understanding these basic classes can always get twice the result with half the effort, and reading the Code is even more fascinating!