android中的sp和wp
關於android sp和wp的實現原理,網上很多介紹的。但是為何android為何要設計這兩個智慧指標?使用過程中需要注意什麼?
為何設計智慧指標
首先sp和wp是針對c++而設計的,因為Java根本就沒有指標的概念,替使用者減少了很多不必要的麻煩。在指標的使用過程中,如果處理不妥當,甚至會出現程式的崩潰:
1. 指標沒有初始化;
2. new了物件後沒有delete;
3. ptr1 和 ptr2同時指向了物件A,當釋放了ptr1,同時ptr1=NULL後,ptr2並不知道它所指向的物件不存在了。
關於物件存在多個引用的問題, android設計了兩個引用計數相關的類,LightRefBase和RefBase。我們能夠想到物件的引用計數應該是儲存在物件中的,所以我們在使用引用計數類時,只需要讓普通類去繼承LightRefBase和RefBase即可,這樣普通類產生的物件中就自然而然擁有了引用計數。
首先是LightRefBase,使用mCount作為引用計數。
template <class T>
class LightRefBase
{
//引用計數原子+1
inline void incStrong(__attribute__((unused)) const void* id) const {
android_atomic_inc(&mCount);
}
//引用計數原子-1,當引用計數為0時,銷燬物件
inline void decStrong(__attribute__((unused)) const void* id) const {
if (android_atomic_dec(&mCount) == 1 ) {
delete static_cast<const T*>(this);
}
}
private:
//引用計數
mutable volatile int32_t mCount;
}
考慮另外一種情況,迴圈引用,父類中儲存了子類的物件,子類中儲存了父類的物件,這樣就是一個“死迴圈”,父類和子類的引用計數永遠不會為0,所以這種情況下單純使用”mCount”就解決不了這個問題,所以有了RefBase。
對RefBase,沒有使用int作為引用計數,而是使用了類weakref_impl* const mRefs;
這個類中同時儲存了強引用計數和弱引用計數,也就牽扯出了sp和wp,強智慧指標和弱智慧指標。並且定義了三種普通物件的生命週期,
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
volatile int32_t mStrong;
volatile int32_t mWeak;
}
enum {
//物件的生命週期受強指標控制
OBJECT_LIFETIME_STRONG = 0x0000,
//物件的生命週期受弱指標控制
OBJECT_LIFETIME_WEAK = 0x0001,
OBJECT_LIFETIME_MASK = 0x0001
};
如果一個普通物件的生命週期受強指標控制,當強引用計數為0時,普通物件就可以被銷燬,但是RefBase中的mRefs物件的銷燬由弱引用計數決定。在這種情況下,父子物件可以一個使用強指標,一個使用弱指標,解決迴圈引用的問題。
同時規定:弱指標必須先升級為強指標,才能去訪問智慧指標所指向的真實物件。
使用中需要注意的問題
onFirstRef函式
在frameworks中有部分類都實現了onFirstRef函式(需要使用智慧指標的類重寫了父類RefBase的onFirstRef函式),這個非常有用,當強指標在第一次引用的時候,會去呼叫這個函式,
void RefBase::incStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
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;
}
//第一次incStrong的時候,mStrong就是INITIAL_STRONG_VALUE,會呼叫refs->mBase->onFirstRef()
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
refs->mBase->onFirstRef();
}
下面是SurfaceFlinger中建立Layer的例子,
status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
// initialize the surfaces
switch (format) {
case PIXEL_FORMAT_TRANSPARENT:
case PIXEL_FORMAT_TRANSLUCENT:
format = PIXEL_FORMAT_RGBA_8888;
break;
case PIXEL_FORMAT_OPAQUE:
#ifdef NO_RGBX_8888
format = PIXEL_FORMAT_RGB_565;
#else
format = PIXEL_FORMAT_RGBX_8888;
#endif
break;
}
#ifdef NO_RGBX_8888
if (format == PIXEL_FORMAT_RGBX_8888)
format = PIXEL_FORMAT_RGBA_8888;
#endif
*outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getBufferQueue();
}
ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err));
return err;
}
*outLayer = new Layer(this, client, name, w, h, flags);
建立一個Layer物件,賦值給outLayer ,這時候會增加強引用計數,同時會去呼叫Layer的onFirstRef()函式。
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
mBufferQueue = new SurfaceTextureLayer(mFlinger);
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setFrameAvailableListener(this);
mSurfaceFlingerConsumer->setName(mName);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
updateTransformHint(hw);
}
wp無法操作真實物件
sp中過載了*和->運算子,返回真實物件,所以可以利用sp去操作真實物件。
//m_ptr是真實物件的指標
inline T& operator* () const { return *m_ptr; }
inline T* operator-> () const { return m_ptr; }
對於wp中沒有過載*和->運算子,無法操作真實物件,需要先promote為強指標才能去操作。這種情況就適合於解決如果真實物件已經被delete了,還去操作指標的操作,下面是android中找的例子:
首先在ProxyConsumerListener中定義了一個wp,wp<ConsumerListener> mConsumerListener;
class ProxyConsumerListener : public BnConsumerListener {
public:
ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
virtual ~ProxyConsumerListener();
virtual void onFrameAvailable();
virtual void onBuffersReleased();
private:
// mConsumerListener is a weak reference to the IConsumerListener. This is
// the raison d'etre of ProxyConsumerListener.
wp<ConsumerListener> mConsumerListener;
};
在使用時,首先對wp需要promote,返回sp後才能去操作真實物件(呼叫方法嘛),返回為null,則說明沒有真實物件的存在。
void BufferQueue::ProxyConsumerListener::onFrameAvailable() {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != NULL) {
listener->onFrameAvailable();
}
}
真實物件是在哪存在的?
將sp<IConsumerListener>& consumerListener
賦值給wp,這時候wp可以成功promote。
status_t BufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
bool controlledByApp) {
ST_LOGV("consumerConnect controlledByApp=%s",
controlledByApp ? "true" : "false");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
ST_LOGE("consumerConnect: BufferQueue has been abandoned!");
return NO_INIT;
}
if (consumerListener == NULL) {
ST_LOGE("consumerConnect: consumerListener may not be NULL");
return BAD_VALUE;
}
mConsumerListener = consumerListener;
mConsumerControlledByApp = controlledByApp;
mFrameLost = 0;
return NO_ERROR;
}
相關推薦
Android 的sp 和 wp 類模板 以及RefBase類
sp 和 wp 類模板 以及RefBase類的程式碼在frameworks/base/include/utils/RefBase.h 和 frameworks/base/libs/utils/RefBase.cpp 中。 sp是Strong pointer ,wp是We
android中的sp和wp
關於android sp和wp的實現原理,網上很多介紹的。但是為何android為何要設計這兩個智慧指標?使用過程中需要注意什麼? 為何設計智慧指標 首先sp和wp是針對c++而設計的,因為Java根本就沒有指標的概念,替使用者減少了很多不
Android中的智慧指標:sp和wp
原文: 連結:http://blog.csdn.net/DroidPhone/article/details/5799792 經常會在android的framework程式碼中發現sp<xxx>和wp<xxx>這樣的指標,平
Android中getDrawable和getColor過時的替代方法
this logs con 知識 log launcher 16px ase spa 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 前言 Android SDK 升級到 23 之後,getDrawable和getColor方法提示過時。 解決方案 getRe
Android中 Bitmap和Drawable相互轉換的方法
canvas board null height .com factory oar tool pla 1、Drawable --> Bitmap [java] view plain copy Bitmap drawable2Bitmap(Drawabl
Android中Gallery和ImageSwitcher同步自動(滾動)播放圖片庫
目標 art trac repl otto fin instance img com 本文主要內容是如何讓Gallery和ImageSwitcher控件能夠同步自動播放圖片集 ,看起來較難,然而,實現的方法非常簡單, 請跟我慢慢來。總的來說,本文要實現的效果如下圖:(截
Android中RelativeLayout和LinearLayout性能分析
ant 顯示 二次 iou other comm 排列 vertica 簡單的 先看一些現象吧:用eclipse或者Android studio,新建一個Activity自動生成的布局文件都是RelativeLayout,或許你會認為這是IDE的默認設置問題,其實不然,
Android中Service和IntentService的差別
前言: ServiceTimeout(20 seconds)小概率型別Service在特定的時間內無法處理完成,會造成ANR — 應用程式無響應(ANR:Application Not Responding)的情況 ▲ 分析 : 避免ANR最核心的一點就是在主執行緒減少耗時操作。這時我們
Android中Serializable和Parcelable序列化物件詳解
學習內容: 1.序列化的目的 2.Android中序列化的兩種方式 3.Parcelable與Serializable的效能比較 4.Android中如何使用Parcelable進行序列化操作 5.Parcelable的工作原理 6.相關例項 1.序列化
Android 中src和background的區別
XML屬性中src和background的區別: src會存放原圖的大小,background會根據view的大小拉伸整張圖片。src是前景而background是背景。 可以使用scaleType屬性設定src(只對src起作用)的縮放方式。 詳細的scaleType說明: CEN
Android中activity和xml的第一個專案
我們使用的手機不光是隻用到一個應用程式,比如在淘寶介面要付款的時候可能會啟動微信付款等,這就相當於在淘寶的Activity中啟動了微信的Activity。還比如說當我們註冊一個網站是,可能會給自己傳送一條簡訊作為驗證,這就是在當前的Activity中啟動了簡訊的Activity。之前對比的MVC設
Android中Paint和Canvas的簡單使用
在 Android 中,Canvas 相當於畫布,而 Paint 相當於畫筆;那麼這兩個配合使用就可以畫出來我們想要的形狀了。 首先我們新建一個類,名字叫 MyView,重寫 onDraw() 方法,程式碼如下: @SuppressLint("AppCompatCustomView") pu
android中 IMEI和ICCID的校驗位計算
我們都知道在android 中有IMEI和ICCID 這兩項資料. 至於這兩項資料的獲取方式以及所表示的意思在此我就不寫了.主要講講這兩項資料最後一位的校驗位如何計算的. IMEI共1
Android-0.Android中minsdkversion和targetSdkVersion的選擇
問題 在呼叫系統播放mp4時,程式碼如下: private void viewMediaFile(String path) { if (!TextUtils.isEmpty(path)) { String type =
android中stagefright和OMXCodec原理分析
1. 框架結構 1.1StageFright和openCore和NuPlayer的關係 上圖可知,stagefright是在MediaPlayerService這一層加入的,和opencZ喎�"/kf/ware/vc/" target="_blank" class=
Android中Bitmap和Drawable相互轉換
一、相關概念 1、Drawable就是一個可畫的物件,其可能是一張點陣圖(BitmapDrawable),也可能是一個圖形(ShapeDrawable),還有可能是一個圖層(LayerDrawable),我們根據畫圖的需求,建立相應的可畫物件 2、Canvas畫布,繪圖的
Android中Density和Pixel的關係對介面顯示的影響
眾所周知,Android中的Density為分四種,分別是120dpi,160dpi,240dpi,320dpi,對應工程中的資料夾分別為drawable-ldpi,drawable-mdpi,drawable-hdpi,drawable-xhdpi。同一張圖片的尺
【Android】android中Invalidate和postInvalidate的區別
Android中實現view的更新有兩組方法,一組是invalidate,另一組是postInvalidate,其中前者是在UI執行緒自身中使用,而後者在非UI執行緒中使用。 Android提供了Invalidate方法實現介面重新整理,但是Invalidate不能直接線上程中呼叫,因為他是違背了單執行緒模型
Android中Okhttp和SPDY協議
HTTP的一個問題在於每個連線一次只允許一個請求和響應,這就讓瀏覽器或者其他客戶端為了並行請求必須生成多個套接字(socket)連線。對客戶端來說,這不算什麼大問題,但是對伺服器來說情況就不一樣了
android 中 Canvas和Paint
相關連結: ---------------正文---------------- Canvas類主要實現了螢幕的繪製過程,其中包含了很多實用的方法,比如繪製一條路徑、區域、貼圖、畫點、畫線、渲染文字,下面是Canvas類常用的方法: void drawRect(RectF rect, Pai