編輯:Android開發實例
經常會在android的framework代碼中發現sp<xxx>和wp<xxx>這樣的指針,平時看的時候都把他當成一個普通的指針封裝過掉了,這幾天終於忍不住了,想深入了解一下。
相關的代碼:
frameworks\base\include\utils\RefBase.h
frameworks\base\libs\utils\RefBase.cpp
sp和wp都是一個模板類,看一下sp類的定義:
- template <typename T>
- class sp
- {
- public:
- typedef typename RefBase::weakref_type weakref_type;
- inline sp() : m_ptr(0) { }
- sp(T* other);
- sp(const sp<T>& other);
- ~sp();
- ......
- private:
- // Optimization for wp::promote().
- sp(T* p, weakref_type* refs);
- T* m_ptr;
- };
可以看到他確實封轉了一個原生指針T* m_ptr. 再看一下其中一個構造函數和析構函數:
- template<typename T>
- sp<T>::sp(T* other)
- : m_ptr(other)
- {
- if (other) other->incStrong(this);
- }
- template<typename T>
- sp<T>::~sp()
- {
- if (m_ptr) m_ptr->decStrong(this);
- }
咋一看好奇怪,因為在構造函數中調用了incStrong(),在析構函數中調用的decStrong(),顯然是管理引用計數的函數,但是sp類的中並沒有定義這兩個函數,這兩個函數是在RefBase類中定義的,由此可以得出結論:
要想使用sp<T>或者wp<T>, T必需要繼承RefBase類才行。
RefBase的靜態關系如下:
其中weakref_type是RefBase的內嵌類,weakref_impl則是weakref_type的子類,RefBase的大部分工作都是交由weakref_impl類來完成,通過RefBase的成員變量weakref_impl* const mRefs。查看其中一個sp的構造函數:
- template<typename T>
- sp<T>::sp(T* other)
- : m_ptr(other)
- {
- if (other) other->incStrong(this);
- }
建立sp<xxx>的動態關系如下:
sp<T>
--> RefBase : incStrong()
-->weakref_impl : addStrongRef()
-->android_atomic_inc(&refs->mStrong)
可見當一個普通指針變成一個sp指針後,將會由RefBase類維護該指針的引用計數,當引用為零時則自動釋放該指針指向的內存:
- void RefBase::decStrong(const void* id) const
- {
- weakref_impl* const refs = mRefs;
- refs->removeStrongRef(id);
- const int32_t c = android_atomic_dec(&refs->mStrong);
- if (c == 1) {
- const_cast<RefBase*>(this)->onLastStrongRef(id);
- if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- delete this; //引用為0,銷毀
- }
- }
- refs->removeWeakRef(id);
- refs->decWeak(id);
- }
wp其實是弱指針的意思,wp<T>類型不能直接對類型T進行操作,要想對T進行某種操作,必需把wp升級為sp指針,使用promote()來實現升級:
wp<T> weakp= new T();
sp<T> t = weakp.promote();
wp可能會在弱引用計數不為0的情況下被銷毀,執行如下代碼:
- class WPTest : public RefBase {
- public:
- WPTest(){
- LOGD("WPTest constructor");
- }
- virtual ~WPTest() {
- LOGD("WPTest destructor");
- }
- virtual void onFirstRef() {
- LOGD("first weak ptr ref callback");
- }
- virtual void onLastStrongRef(const void* id) {
- LOGD("last strong ptr ref callback");
- }
- virtual void onLastWeakRef(const void* id) {
- LOGD("last weak ptr ref callback");
- }
- };
- int main()
- {
- WPTest *T = new WPTest();
- {
- wp<WPTest> weakp(T);
- {
- LOGD("promote to strong ptr...\n");
- sp<WPTest> strongp = weakp.promote();
- LOGD("strong ptr's lifetime is just about to finish ...\n");
- }
- LOGD("weak ptr's lifetime is just about to finish ...\n");
- }
- LOGD("weak ptr is out of scope.\n");
- return 0;
- }
程序打印的結果是:
D/sp-wp-sample( 225): WPTest constructor
D/sp-wp-sample( 225): promote to strong ptr...
D/sp-wp-sample( 225): first weak ptr ref callback
D/sp-wp-sample( 225): strong ptr's lifetime is just about to finish ...
D/sp-wp-sample( 225): last strong ptr ref callback
D/sp-wp-sample( 225): WPTest destructor
D/sp-wp-sample( 225): weak ptr's lifetime is just about to finish ...
D/sp-wp-sample( 225): weak ptr is out of scope.
由此可見雖然wp<WPTest >的生命周期還沒有結束,但是因為升級為sp<WPTest >後,sp<WPTest >的強引用計數為0,導致WPTest 被銷毀,當強引用為0而弱引用不為0時,WPTest 銷毀時,基類RefBase的mRefs指向的weakref_impl類並沒有釋放,從而保證了弱引用可以繼續起作用,這點可以從RefBase的析構函數中看出來:
- RefBase::~RefBase()
- {
- // LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
- if (mRefs->mWeak == 0) {
- // LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
- delete mRefs;
- }
- }
不過也可以改變這一行為,我們修改一下WPTest的構造函數:
- WPTest(){
- LOGD("WPTest constructor");
- extendObjectLifetime(OBJECT_LIFETIME_WEAK);
- }
這時的打印結果是:
D/sp-wp-sample( 217): WPTest constructor
D/sp-wp-sample( 217): promote to strong ptr...
D/sp-wp-sample( 217): first weak ptr ref callbac
D/sp-wp-sample( 217): strong ptr's lifetime is j
D/sp-wp-sample( 217): last strong ptr ref callba
D/sp-wp-sample( 217): weak ptr's lifetime is j
D/sp-wp-sample( 217): last weak ptr ref callback
D/sp-wp-sample( 217): WPTest destructor
D/sp-wp-sample( 217): weak ptr is out of scope.
可以看出現在只有當強引用和弱引用的計數都為0時,WPTest對象才會被銷毀。
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
1.黑白效果 代碼如下:/** * 將彩色圖轉換為黑白圖 * &n
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放