Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android FrameWork中的SP、RefBase、weakref_impl,Thread類

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

編輯:關於Android編程

在閱讀Android的Framework處的代碼可以發現,無處不在SP給予了我視覺上的沖擊,這個是什麼?初級的我,看這個當初就基本當成指針來用,熟不知其的內在美,於是在這裡和大家一起學習總結SP類的魅力所在。

1 SP這貨是個模板類,讓我們看下他的結構。

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;
};

看到了上述的代碼結構,瞬間覺得其高大上,作為一個經典的模板類,精懂的人說這個類很好,其實沒有過多的去了解他只知道是更好的維護對象。這個SP指針內部有個T* m_ptr成員變量,它是真正指向我們new出來的變量。

我們以sp mA = new A();為例,作為一個模板類的構造函數,調用如下:

template
sp::sp(T* other)
    : m_ptr(other)
{
    if (other) other->incStrong(this);
}

果然,new出來的A對象被存入到sp的成員變量之中,這裡看到對mA對象構建時,會調用A的一個incStrong,這個是什麼?閱讀過代碼的都知道一個RefBase類,他是比sp類更為常見的類,我們看她的結構可以發現內容都較多,但都是一些很特別的東西, 我們看下面的UML圖來分析我們之間構建的A為何要繼承與RefBase。

\

可以看到繼承了RefBase,那麼A的對象有東西可以玩了,調用RefBase的incStrong函數,接著看他的實現,先來個構造函數過過瘾:

RefBase::RefBase()
    : mRefs(new weakref_impl(this))
{
}

做的東西不多,但是有一個成員變量mRefs,必然他先實現,好吧mRefs被賦值給了一個wekref_impl這個對象,傳入的this就是我們的這個new A()對象,好的接著再看看:

    weakref_impl(RefBase* base)
        : mStrong(INITIAL_STRONG_VALUE)
        , mWeak(0)
        , mBase(base)
        , mFlags(0)
    {
    }
 

這裡有個mBase,他是一個RefBase類,故按C++的知識,一個從RefBase繼承的A類對象被賦值給了mBase,那基類的指針mBase就可以訪問類A自帶的重載的虛函數了,先留著過會就會用到。

回來我們來看這個剛才other->incStrong(),調用的是基類的incStrong,看他的實現:

void RefBase::incStrong(const void* id) const
{
    weakref_impl* const refs = mRefs;//影子對象的refs
    refs->incWeak(id);
    
    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維護著繼承類實際對象this指針
}

這裡是增加了對這個指針的引用次數,最重要的一點是關注最後一行代碼,在我們寫自己類的時候一般都喜歡重載該函數,在這裡面對類對象進行必要的初始化。

refs為mRefs,就是我們類A的對象的一個繼承成員weakref_impl,該對象有個內部成員mBase,通過上面的分析可知mBase就是指向類A對象的指針,故當訪問虛函數時,實際調用的是派生類的重載函數,故最終首次建立一個sp mA 時,就也是所謂的第一次引用吧。

2.學一學Android Native的Thread類

上面介紹了很多的類,在onFirstRef裡面可以經常會遇到一個run函數,這是啟動一個新線程的方法,那就是你的類A 繼承了thread類,從上一UML圖可以看到,thread有幾個核心的函數,最重要的就是一個run函數。來看她的部分代碼:

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 reference on ourself
    mHoldSelf = this;

    mRunning = true;

    bool res;
    if (mCanCallJava) {
        res = createThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);//啟動_threadLoop線程
    } 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
}

源碼上深入的話會比較復雜,但是一點可以肯定的是調用的線程函數是_thread_Loop,看看他的實現:

int Thread::_threadLoop(void* user)
{
    Thread* const self = static_cast(user);//派生類對象轉為基類指針
do {
        bool result;
        if (first) {
            first = false;
            self->mStatus = self->readyToRun();//直接調用繼承類的readyToRun
            result = (self->mStatus == NO_ERROR);
......
           else
            result = self->threadLoop();
        }
}

這裡的self是什麼,實際是我們新建的一個對象,那麼首次就是調用類A的操作函數readyToRun(),隨後一般是調用threadLoop進入線程的循環,線程的退出主要由threadLoop函數的返回結果來決定。

3. 好了,下面再來看看這個這幾個比較常見的過程,會和C++的多態符合重載有緊密的關系。

比如mA->fun(),一眼看去感覺和普通的指針調用沒有區別,但你是否知道mA只是一個sp類的對象,那麼這個mA->的操作符是什麼?那就是所謂的符合重載,來看sp的幾個運算符的重載函數:

   inline  T&      operator* () const  { return *m_ptr; }
    inline  T*      operator-> () const { return m_ptr;  }
    inline  T*      get() const         { return m_ptr; }

很好,可以看到他的實現,不需要輸入參數,返回一個m_ptr,m_ptr是什麼,前面說過他是我們new A()出來的一個對象,那麼調用的就是類A所屬的成員函數.類似的還有:

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;
}

分別是對指針與引用的賦值操作。

上述的Android Framework裡面會經常遇到這些細節性的問題,了解這些基本類往往可以做到事半功倍,閱讀代碼更加心領神會!






  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved