Android Java Framework顯示Toast(無Activity和Service)(轉載)

原文(轉載自:http://my.oschina.net/shaorongjie/blog/146566):最近遇到一個問題是如何在Android Framework中顯示一個提示信息Toast。 從網上查了一下資料,但提供的都是有Activity或者Service的情況。但我的需求是要在一個沒有Activity或者Service的Java文件中去顯示一個Toast。怎麼辦呢?因爲要創建一個Toast就需要Context,怎樣獲取一個Context呢?苦思冥想沒有找到方法。無奈之下,就先找了一種臨時方案。

   臨時方案的做法是寫一個Service,在這個Service中加個提供顯示Toast的接口。將這個Service註冊到ServiceManager中。然後通過ServiceManager去獲取這個Service,調用這個Service的接口去顯示Toast。這種寫法雖然有效,但感覺很不方便。因爲後面有人又遇到這個問題。

  後來在Android的源代碼中發現ActivityThread.currentApplication()可以返回一個Application。通過Application.getApplicationContext()可以獲取一個Context。看起來是可行的。但實際試的時候發現ActivityThread.currentApplication()返回爲null。怎麼辦呢?通過分析ActivityThread的代碼發現如果是在非UI thread裏面調用,因爲這個時候ActivityThread調用currentActivityThread返回爲null.因此爲null.
1    public static Application currentApplication() {
2            ActivityThread am = currentActivityThread();
3            return am != null ? am.mInitialApplication : null;
4        }

悲劇啊,剛好那支Java文件的API都是運行在非UI thread裏面的。那有沒有辦法讓這段代碼運行在UI thread裏面呢?

於是苦逼的繼續查找,終於找到一種方法:

1.通過Looper.getMainLooper()獲取到main looper。在創建一個Handler,在創建Handler的時候將main looper傳遞給Handler.這樣就可以使這個Handler運行在UI thread中。

2.在Handler的handleMessages()中去調用ActivityThread.currentApplication()獲取Application。再通過Application.getApplicationContext()獲取到Context。然後創建Toast,顯示。

3.通過Handler.sendMessage的方式去通知Handler顯示一個Toast。

測試,大功告成。

附代碼:
01    public void connect() {
02        Looper looper = Looper.getMainLooper();
03        mHandler = new Handler(looper);
04        Message message = mHandler.obtainMessage(SHOW_TOAST);
05        mHandler.sendMessage(m);
06    }
07    
08    public void handleMessage(Message msg) {
09        switch(msg.what) {
10            case SHOW_TOAST:
11                showToast();
12                return;        
13    }
14    
15    public void showToast() {
16        Application application = ActivityThread.currentApplication();
17        Toast.makeText(application.getApplicationContext(), "test test test .....", Toast.LENGTH_SHORT).show();
18    }

由於這種做法有點小技巧,不大容易想到,因此記錄在此,供大家查看。

=========================================================================================================

參考上文的方法,我修改了\android\frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java

確實可以實現Toat顯示。但直接使用上文中的showToast()方法會報錯。原因是application.getApplicationContext()獲得空指針。

解決只要加一下判斷就可以了。

public void showToast(int i) {
    Application application = ActivityThread.currentApplication();
    if(i == 0){
            Toast.makeText(application.getApplicationContext() == null ? mContext : application.getApplicationContext(), "AUDIO MODE change to AUDIO_HDMI", Toast.LENGTH_SHORT).show();
    }else{
            Toast.makeText(application.getApplicationContext() == null? mContext : application.getApplicationContext(), "AUDIO MODE change to AUDIO_CODEC", Toast.LENGTH_SHORT).show();
         }
    }

mContext是類中的Context變量。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章