編輯:關於android開發
public static IMManager getInstance(Context context) {
if (mInstance == null) {
synchronized (IMManager.class) {
if (mInstance == null)
mInstance = new IMManager(context);
}
}
return mInstance;
}
當調用getInstance時,如果傳入的context是Activity的context。只要這個單例沒有被釋放,這個Activity也不會被釋放。
解決方案:傳入Application的context.
2.非靜態內部類引起的內存洩露:
在java中,創建一個非靜態的內部類實例,就會引用它的外圍實例.如果這個非靜態內部類實例做了一些耗時的操作.就會造成外圍對象不會被回收,從而導致內存洩露.
解決方案:
1.將內部類變成靜態內部類
當將內部類變成靜態內部類後,便不再持有外部類對象的引用,導致程序不允許你在handler中操作activity的對象了,因此我麼需要在handler中增加一個對A/ctivity的弱引用(WeakReference);
注:為什麼使用靜態內部類就不會造成內存洩露了?
答:靜態內部類不會持有對外部對象的引用
2.如果有強引用Activity中的屬性,則將該屬性的引用方式改為弱引用.
使用WeakReference包裝該對象.
3.在業務允許的情況下,當activity執行onDestory時,結束這些耗時任務
static class MyHandler extends Handler {
WeakReference mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}
3.資源未關閉引起的內存洩露
當使用了BroadcastReceiver\Cursor\Bitmap等資源的時候,當不需要使用時,需要及時釋放掉,若沒有釋放,則會引起內存洩露.
4.**增加:在使用Bitmap時,出現內存溢出的解決方案:**1.調用系統的GC回收,System.gc();2.壓縮圖片質量大小.
雖然靜態類與非靜態類之間的區別並不大,但是對於Android開發者而言卻是必須理解的.至少我們要清楚,如果一個內部類實例的生命周期比Activity更長,那麼我們千萬不要使用非靜態的內部類.最好的做法是,使用靜態內部類,然後在該類裡面使用弱引用來指向所在的Activity
2.Java基礎之弱引用\強引用\軟引用\虛引用
強引用(StrongReference):是使用最普遍的引用.如果一個對象具有強引用,那GC回收器絕不會回收它.
Object o=new Object(); // 強引用
public void test(){
Object o=new Object();
// 省略其他操作
}
當內存不足時,java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足的問題.如果不使用時,要通過如下方式來弱化引用.
在方法內部有一個強引用,這個引用保存在棧中,而真正得引用內容(Object )保存在堆中.當這個方法運行完成後,就會推出方法棧,則引用內容的引用不存在,這個Object會被回收.
但是如果這個o是全局的變量時,就需要在不用這個對象時復制為null,因為強引用不會被垃圾回收。
軟引用(SoftReference): 如果一個對象只具有軟引用,則內存空間足夠,垃圾回收器就不會回收它;如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。
String str=new String("abc"); // 強引用
SoftReference softRef=new SoftReference(str); // 軟引用
軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
弱引用:
弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先級很低的線程,因此不一定會很快發現那些只具有弱引用的對象。
String str=new String("abc");
WeakReference abcWeakRef = new WeakReference(str);
str=null;
當你想引用一個對象,但是這個對象有自己的生命周期,你不想介入這個對象的生命周期,這時候你就是用弱引用。
虛引用(PhantomReference):
“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之 關聯的引用隊列中。
3.Java中static,final等關鍵字:
static關鍵字:
被static修飾的成員變量和成員方法獨立於該類的任何對象。也就是說,它不依賴類特定的實例,被類的所有實例共享。只要這個類被加載,Java虛擬機就能根據類名在運行時數據區的方法區內找到他們。因此,static對象可以在它的任何對象創建之前訪問,無需引用任何對象。
1.static修飾方法:
當static關鍵字修飾方法時,這個方法就稱為靜態方法。靜態方法屬於類而不屬於實例對象。那麼靜態方法如何進行調用?可以通過類名.方法名來直接調用,也可以通過實例對象.方法名來調用。
使用static關鍵字修飾的方法在類加載的時候就會加載到內存中。是被指向所屬的類而不是實例。
可以看出,這並不是覆蓋,其實靜態方法只可以被隱藏,而不可以覆蓋。當t1為Person類型時,則調用Person類的靜態方法,因為靜態方法只屬於這個類,而當t2類型為Test02時,調用子類的靜態方法,當子類沒有時,調用父類的方法,這就叫做繼承父類的方法了。
2.static修改屬性:
當static修飾屬性時,與類一樣,都是在類加載時就加載到了內存。
3.static修飾塊
加static修飾的塊也會隨著類的加載而進入內存,所以可以在這裡初始化一些靜態成員變量。
4.使用static注意事項:
當類被虛擬機加載時,按照聲明順序先後初始化static成員字段和static語句塊
static所修飾的方法和變量只屬於類,所有對象共享。
在static所修飾的方法和語句塊中不能使用非static成員字段。
靜態成員不是對象的特性,只是為了找一個容身之處,所以需要放到一個類中而已,把“全局變量”放在內部類中就是毫無意義的事情,所以 被禁止
在Java不能直接定義全局變量,是通過static來實現的
在Java中沒有const,不能直接定義常量,通過static final來實現
final 關鍵字:
1.final關鍵字的使用:引用本身的不變和引用指向的對象不變。
修飾類:*如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承*。因此一個類不能同時聲明為abstract final或者interface final的。
修飾方法 :將方法聲明為final,可以保證它們在使用中不被改變。被聲明為final的方法也同樣只能使用,不能重載。但是子類可以繼承父類的final方法。
修飾變量 :表示屬性值第一次初始化後不能被修改。final屬性可以直接初始化或在構造函數中初始化.如果屬性是直接初始化,則其值不能被其它函數(包括構造函數)修改。
修飾方法參數 :參數值不能被修改
修飾方法中的局部變量 : 局部變量被第一次初始化後不能被修改
注:任何在interface裡聲明的成員變量,默認為public static final。
使用final的意義:
第一,為方法“上鎖”,防止任何繼承類改變它的本來含義和實現。設計程序時,若希望一個方法的行為在繼承期間保持不變,而且不可被覆蓋或改寫,就可以采取這種做法。
第二,提高程序執行的效率,將一個方法設成final後,編譯器就可以把對那個方法的所有調用都置入“嵌入”調用裡(內嵌機制)。
finally關鍵字:
在異常處理時提供 finally 塊來執行任何清除操作。如果拋出一個異常,那麼相匹配的 catch 子句就會執行,然後控制就會進入 finally 塊。 所以說finally塊是一定會被執行的。
finally 語句塊是在 try 或者 catch 中的 return 語句之前執行的。更加一般的說法是,finally 語句塊應該是在控制轉移語句之前執行,控制轉移語句除了 return 外,還有 break 和 continue。 return 和 throw 把程序控制權轉交給它們的調用者(invoker),而 break 和 continue 的控制權是在當前方法內轉移。
finalize 方法名:
finalize()方法是在垃圾收集器刪除對象之前對這個對象調用的。
4.Java多線程線程池 - 線程池原理:
public interface Executor {
void execute(Runnable command);
}
Executors方便的創建線程池.
(1).newCachedThreadPool :該線程池比較適合沒有固定大小並且比較快速就能完成的小任務,它將為每個任務創建一個線程。那這樣子它與直接創建線程對象(new Thread())有什麼區別呢?看到它的第三個參數60L和第四個參數TimeUnit.SECONDS了嗎?好處就在於60秒內能夠重用已創建的線程。下面是Executors中的newCachedThreadPool()的源代碼:
//基本的無界值(如 Integer.MAX_VALUE),則允許池適應任意數量的並發任務
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
(2).newFixedThreadPool:使用的Thread對象的數量是有限的,如果提交的任務數量大於限制的最大線程數,那麼這些任務將排隊,然後當有一個線程的任務結束之後,將會根據調度策略繼續等待執行下一個任務。下面是Executors中的newFixedThreadPool()的源代碼:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue());
}
(3).newSingleThreadExecutor:就是線程數量為1的FixedThreadPool,如果提交了多個任務,那麼這些任務將會排隊,每個任務都會在下一個任務開始之前運行結束,所有的任務將會使用相同的線程。下面是Executors中的newSingleThreadExecutor()的源代碼:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
(4).newScheduledThreadPool:創建一個固定長度的線程池,而且以延遲或定時的方式來執行任務。
ThreadPoolExecutor構造方法:
public ThreadPoolExecutor(int corePoolSize, //核心線程
int maximumPoolSize, // 線程池維護的最大線程數量
long keepAliveTime, //線程池維護線程所允許的空閒時間
TimeUnit unit,
BlockingQueue workQueue //// 阻塞隊列 ) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
ExecutorService:為了解決執行服務的生命周期問題,Executor擴展了EecutorService接口,添加了一些用於生命周期管理的方法。
ThreadPoolExecutor線程池實現類:
private final BlockingQueue workQueue; // 阻塞隊列
private final ReentrantLock mainLock = new ReentrantLock(); // 互斥鎖
private final HashSet workers = new HashSet();// 線程集合.一個Worker對應一個線程
private final Condition termination = mainLock.newCondition();// 終止條件
private int largestPoolSize; // 線程池中線程數量曾經達到過的最大值。
private long completedTaskCount; // 已完成任務數量
private volatile ThreadFactory threadFactory; // ThreadFactory對象,用於創建線程。
private volatile RejectedExecutionHandler handler;// 拒絕策略的處理句柄
private volatile long keepAliveTime; // 線程池維護線程所允許的空閒時間
private volatile boolean allowCoreThreadTimeOut;
private volatile int corePoolSize; // 線程池維護線程的最小數量,哪怕是空閒的
private volatile int maximumPoolSize; // 線程池維護的最大線程數量
處理任務的優先級為:
核心線程corePoolSize > 任務隊列workQueue > 最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。 當池中的線程數大於corePoolSize的時候,多余的線程會等待keepAliveTime長的時間,如果無請求可處理就自行銷毀。workQueue :線程池所使用的緩沖隊列,該緩沖隊列的長度決定了能夠緩沖的最大數量,緩沖隊列有三種通用策略:
(1) 直接提交,工作隊列的默認選項是 SynchronousQueue,它將任務直接提交給線程而不保持它們.
(2) 無界隊列,使用無界隊列(例如,不具有預定義容量的 LinkedBlockingQueue)將導致在所有 corePoolSize 線程都忙時新任務在隊列中等待。這樣,創建的線程就不會超過 corePoolSize。(因此,maximumPoolSize 的值也就無效了。)當每個任務完全獨立於其他任務,即任務執行互不影響時,適合於使用無界隊列.
(3) 有界隊列,當使用有限的 maximumPoolSizes 時,有界隊列(如 ArrayBlockingQueue)有助於防止資源耗盡,但是可能較難調整和控制。隊列大小和最大池大小可能需要相互折中:使用大型隊列和小型池可以最大限度地降低 CPU 使用率、操作系統資源和上下文切換開銷,但是可能導致人工降低吞吐量。如果任務頻繁阻塞(例如,如果它們是 I/O 邊界),則系統可能為超過您許可的更多線程安排時間。使用小型隊列通常要求較大的池大小,CPU 使用率較高,但是可能遇到不可接受的調度開銷,這樣也會降低吞吐量.
ThreadFactory:使用 ThreadFactory 創建新線程。如果沒有另外說明,則在同一個 ThreadGroup 中一律使用 Executors.defaultThreadFactory() 創建線程,並且這些線程具有相同的 NORM_PRIORITY 優先級和非守護進程狀態。通過提供不同的 ThreadFactory,可以改變線程的名稱、線程組、優先級、守護進程狀態等等。如果從 newThread 返回 null 時 ThreadFactory 未能創建線程,則執行程序將繼續運行,但不能執行任何任務。
在DefaultThreadFactory類中實現了ThreadFactory接口並對其中定義的方法進行了實現,如下:
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-";
}
// 為線程池創建新的任務執行線程
public Thread newThread(Runnable r) {
// 線程對應的任務是Runnable對象r
Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(), 0);
// 設為非守護線程
if (t.isDaemon())
t.setDaemon(false);
// 將優先級設為Thread.NORM_PRIORITY
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
RejectedExecutionHandler:
當Executor已經關閉(即執行了executorService.shutdown()方法後),並且Executor將有限邊界用於最大線程和工作隊列容量,且已經飽和時,在方法execute()中提交的新任務將被拒絕.
在以上述情況下,execute 方法將調用其 RejectedExecutionHandler 的 RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor) 方法。下面提供了四種預定義的處理程序策略:
1) 在默認的 ThreadPoolExecutor.AbortPolicy 處理程序遭到拒絕將拋出運行時 RejectedExecutionException;
2) 在 ThreadPoolExecutor.CallerRunsPolicy 線程調用運行該任務的 execute 本身。此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度
3) 在 ThreadPoolExecutor.DiscardPolicy 不能執行的任務將被刪除;
4) 在 ThreadPoolExecutor.DiscardOldestPolicy 如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程序(如果再次失敗,則重復此過程)。
線程池默認會采用的是defaultHandler策略。
Callable接口代表一段可以調用並返回結果的代碼;Future接口表示異步任務,是還沒有完成的任務給出的未來結果。所以說Callable用於產生結果,Future用於獲取結果。
以下內容來自http://www.trinea.cn/android/java-android-thread-pool/,再此簡單記錄.
new Thread的弊端:
a.每次new Thread新建對象性能差.
b.線程缺乏統一管理,可能無限制新建線程,相互之間競爭,及可能占用過多系統資源導致死機或oom.
c.缺乏更多功能,如定時執行、定期執行、線程中斷.
Java提供的四種線程池的好處:
a. 重用存在的線程,減少對象創建、消亡的開銷,性能佳。
b. 可有效控制最大並發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
c. 提供定時執行、定期執行、單線程、並發數控制等功能。
(1). newCachedThreadPool
創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。線程池為無限大,當執行第二個任務時第一個任務已經完成,會復用執行第一個任務的線程,而不用每次新建線程。
(2). newFixedThreadPool
創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。定長線程池的大小最好根據系統資源進行設置。如Runtime.getRuntime().availableProcessors()。
(3) newScheduledThreadPool
創建一個定長線程池,支持定時及周期性任務執行。延遲執行示例代碼如下
(4)、newSingleThreadExecutor
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。現行大多數GUI程序都是單線程的。Android中單線程可用於數據庫操作,文件操作,應用批量安裝,應用批量刪除等不適合並發但可能IO阻塞性及影響UI線程響應的操作。
Android 綜合揭秘 —— 全面剖釋 Service 服務,androidservice引言 Service 服務是 Android 系統最常用的四大部件之一,And
Android AutoLayout全新的適配方式 堪稱適配終結者 一、概述 相信Android的開發者對於設配問題都比較苦惱,Google官方雖
自定義控件之創建可以復用的組合控件(三) 前面已學習了兩種自定義控件的實現,分別是自定義控件之對現有控件拓展(一)和 自定義控件之直接繼承View創建全新視圖(二),
Android開發學習——android存儲,android開發存儲Android的存儲 內部存儲空間RAM內存:運行內存,相當於電腦的內存ROM內存:存儲內存,相當於電