全域變數顧名思義就是在整個的類別中或可在多個函數中呼叫的變數。也稱為外部變數。局部變數則是特定過程或函數中可以存取的變數。宣告一個變數是很 容易的,但是講到使用的時候,卻不是想像的那麼簡單。至於本人則是經常定義全域變數使用,但也就是因為這樣,定義的是全域變數。也饒了不少的彎子。
在使用Adapter即適配器的時候,通常適配器總是與listView使用,因為一個listView 基本上都會有一個listView的Item的佈局,下面的情景是:在每個Item裡面都會有一個ImageView,當我點擊某一條的時候,則需要為該Item的ImageView換背景色或者換成別的背景圖片,這個時候可能會出現的一種情況是 你明明點的第一條,你會發現第三條或是第二條的圖片也變了。這就是因為你定義的是全域變數。程式碼部分如下:
public class Adapter extends BaseAdapter { private ImageView img; public View getView(int position, View convertView, ViewGroup parent) { convertView = mInflater.inflate(R.layout.group_listview_item,null); img = (ImageView) convertView.findViewById(R.id.logo); return convertView; } }
上面的部分,ImageView就是一個全域變數。而這個時候,我們則需要把 ImageView定義為局部變量,
public class Adapter extends BaseAdapter { public View getView(int position, View convertView, ViewGroup parent) { convertView = mInflater.inflate(R.layout.group_listview_item,null); ImageView img = (ImageView) convertView.findViewById(R.id.logo); return convertView; } }
這個時候則表示每一個Item裡的ImageView了。還有一種情況是在做購物車的時候,可以點擊加減的圖示去改變購物車內的商品數量。當你定義數量 num 的時候,也必須定義為局部變數。如果會使用ViewHolder的話更好了。
static修飾的靜態變量,使用很方便,在不同的類別和包中都可以使用,在虛擬機中單獨佔用內存,沒錯,這些都是它們的優點,不過在項目上線後,才發現static有一些不太好的地方。
在檢視專案的崩潰資訊時,發現許多地方莫明的出現空白指標異常的錯誤,經過排查,發現可能就是static的問題。我們在專案中,將使用者的資訊也就是User物件保存成了一個靜態變量,而在報錯的地方,也都發現有使用過這種變量,因此,可以大致推斷出與這種保存的方式有一定的聯繫。同時,有不少用戶反映在開啟應用程式的情況下,接個電話或長時間待機後,再回到應用也會出現崩潰的現象,而這些崩潰都與靜態變數的空指標有關係。
如此來說的話,static靜態修飾在Android的開發中是不是很危險?或許我們可以說如果是static User u = new User();這樣定義的話,那麼應該不會有太大問題,而如果是static User u;這樣定義的話,那麼很可以會出現NULL的現象。當然,前面的方法裡面的屬性也可能會現空的情況,但是這個可以用封裝來避免空指標。另外靜態常數還是很好用的。
那麼該如何儲存登入或全域的資訊呢?根據Google官方的推薦以及百度到的各位大神的推薦,我們應該盡量使用繼承自Application的自定義類,在我們繼承的類中定義需要全局使用的變量,並通過getApplicationContext()來獲取和保存相關的變數即可。
/** * 自定义的MyApplication继承Application * * @author way * */ public class MyApplication extends Application { /** * 引发异常:在一些不规范的代码中经常看到Activity或者是Service当中定义许多静态成员属性。这样做可能会造成许多莫名其妙的 null * pointer异常。 */ /** * 异常分析:Java虚拟机的垃圾回收机制会主动回收没有被引用的对象或属性。在内存不足时,虚拟机会主动回收处于后台的Activity或 * Service所占用的内存。当应用再次去调用静态属性或对象的时候,就会造成null pointer异常 */ /** * 解决异常:Application在整个应用中,只要进程存在,Application的静态成员变量就不会被回收,不会造成null pointer异常 */ private int number; @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } }
不過,為了讓我們的MyApplication取代android.app.Application的地位,在我們的程式碼中生效,我們需要修改AndroidManifest.xml:
<application android:name=".MyApplication" ...> </application>
下面我們就可以在Activity或Service中靈活使用了:
MyApplication application = (MyApplication) this.getApplicationContext(); //保存变量 application.setNumber(5); //取出变量 application.getNumber();
Application是與應用程式同時存在的,也就是應用在它就在,並不會被GC給莫名其妙的回收掉,因此,使用此方法更加安全。