標籤:
開發這個程式之前先解釋一下,為什麼Toast資訊氣球在顯示一定時間後會自己主動消失?由於在Android系統中有一個Toast隊列,系統會依次從這個隊列中取出一個Toast,並顯示它。在顯示了指定時間之後,便關閉它。那麼可不能夠讓Toast資訊氣球一直顯示呢?這個要求對於Toast來說有點強人所難了,由於,Toast本身並沒有提供這個功能。那麼怎麼才幹讓Toast一直顯示,並在我們的控制之下關閉呢?代碼是死的,人是活的。以下就叫代碼說話:
看一下Toast的show方法的原始碼:
public void show() { if (mNextView == null) { throw new RuntimeException("setView must have been called"); } INotificationManager service = getService(); String pkg = mContext.getPackageName(); TN tn = mTN; tn.mNextView = mNextView; try { service.enqueueToast(pkg, tn, mDuration); } catch (RemoteException e) { // Empty } }
在上面的代碼中Toast已經告訴我們了,它本身並不負責資訊氣球的顯示與關閉,它僅僅是將Toast增加到系統的Toast隊列中,再由系統依據Toast隊列來顯示和關閉Toast資訊氣球。如今我們能夠做一個大膽的判斷,既然Toast的show方法是將Toast放到系統的Toast隊列中,那麼我們就不使用show方法,我們自己來控制Toast的顯示與關閉。
查看Toast類原始碼能夠找到一個TN類,該類是Toast的一個內嵌類。在TN類中有個show方法,系統是從Toast隊列中獲得Toast對象之後,利用TN對象的show方法顯示Toast再利用TN.hide方法關閉Toast。假設我們能夠擷取TN對象那麼就能控制Toast的顯示與關閉。但TN被聲明成private,外部無法訪問。只是Toast類中有個mTN對象,儘管它不是我public但我們能夠通過Java反射技術來訪問該對象。mTN會在建立Toast對象時初始化。所以,僅僅要獲得mTN對象也就獲得了TN對象。以下代碼顯示了一個永不關閉的Toast資訊氣球。
Toast toast = Toast.makeText(context, msg, Toast.LENGTH_SHORT); //設定Toast的顯示位置 toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 0); try { //通過反射技術,從toast對象中擷取mTN對象 Field field = toast.getClass().getDeclaredField("mTN"); field.setAccessible(true); obj = field.get(toast); //從TN對象中獲得show方法 Method method = obj.getClass().getDeclaredMethod("show", null); //調用TN對象的show方法來顯示Toast資訊氣球 method.invoke(obj, null); } catch (Exception e) { }
上面代碼先通過事先建立好的Toast對象獲得mTN對象,然後在利用反射技術獲得TN對象的show方法。
關閉Toast的方法和顯示Toast的方法類似,僅僅須要獲得hide方法就可以。
Method method = obj.getClass().getDeclaredMethod("hide", null);method.invoke(obj, null);
程式執行:
Android開發之控制Toast的開啟與關閉