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變量。
臨時方案的做法是寫一個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變量。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.