Android應用之——不要將資料存放區在Application類中,androidapplication
前言:最近在開發中發現了一個比較嚴重的問題,當我們將應用按home鍵放入後台運行,一段時間後,當我們再次開啟應用的時候,十有八九會出現一個NullPointException的null 指標異常,根據logcat的日誌,就會定位到一個去全域性到變數去,這是什麼原因呢?原來,是因為我們我們將很多資料放入了application中作為全域變數,導致了問題的產生,下面來說下為什麼不能將資料放在application中。
一、application類的簡介Application和Activity,Service一樣是android架構的一個系統組件,當android程式啟動時系統會建立一個 application對象,用來儲存系統的一些資訊。一般情況下,系統會預設幫我們建立一個application類,我們不需要在其中進行任何操作,程式會自動建立。當如果需要建立自己的Application,在其中進行一些操作,也很簡單,建立一個類繼承 Application並在manifest的application標籤中進行註冊(只需要給Application標籤增加個name屬性把自己的 Application的名字定入即可)。
<application android:name="com.example.applicationdemo.MyApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
其中MyApplication類就是我們自訂的一個類,繼承自Application類
public class MyApplication extends Application {public String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();}}
二、application中為什麼不能儲存資料
下面我們來看一個簡單的樣本:我們在application繼承類中寫一個set get變數的方法,然後通過第一個activity利用application的set方法來設定這個變數的值,在另一個activity中取得這個值,並將其轉換為大寫顯示出來。代碼如下:MainActivity:
public class MainActivity extends Activity {private MyApplication application;private Button btnName;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);application = (MyApplication) getApplication();application.setName("YangLiang");btnName = (Button) findViewById(R.id.btn_name);btnName.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, ShowNameActivity.class);startActivity(intent);}});}}MyApplication類
public class MyApplication extends Application {public String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic void onCreate() {// TODO Auto-generated method stubsuper.onCreate();}}另一個activity,顯示內容
public class ShowNameActivity extends Activity {private MyApplication app;private TextView tv;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.showname);app = (MyApplication) getApplication();String name = app.getName();tv = (TextView) findViewById(R.id.tv_showname);tv.setText(name.toLowerCase());}}開啟應用後,進入ShowNameActivity介面中,然後按home鍵進入後台,一段時間後,再次開啟demo,就出現了null 指標異常
logcat中的錯誤記錄檔
定位到了這句代碼:
tv.setText(name.toLowerCase());
name在這個時候已經為空白了
這是什麼原因呢?因為當應用程式在後台啟動並執行時候,當我們將應用程式切入到後台或者當記憶體不足時,系統可能會將當前應用的application進程幹掉,當我們再次從後台將應用程式切換到前台的時候,系統會重建一個application類,這個時候,我們在顯示的activity中調用
app = (MyApplication) getApplication();String name = app.getName();tv.setText(name.toLowerCase());
上面的name就是空的,因此會出現null 指標異常,也就是說,我們儲存在application中的資料,有可能會因為程式運行在背景時候導致application的銷毀和重建進而導致資料的丟失,這對於程式來說是致命的,直接導致null 指標異常的出現,程式崩潰。
三、有什麼更好的辦法?1、通過intent來傳遞資料,而不是將資料放在全域變數application中,當然這麼做是有局限性的,並不是所有地方都適合用intent來傳遞資料,也並不是所有類型的資料都適合用intent來傳遞,關於intent的資料傳遞,讀者可參考其他資料。
2、將資料進行持久化操作,寫入檔案,shareprefrence,資料庫等等各種能夠安全儲存資料的方法。然後在需要使用資料的地方進行檔案讀取操作。
3、在所有需要使用此類資料的地方進行非空的判斷,然後進行相應的操作。
四、總結:不要輕易在application類中進行資料的儲存操作,application類中應當做的是進行一些全域性的配置的初始化操作,而資料的儲存應該使用前面推薦的幾種方法。
demo:http://download.csdn.net/detail/yanglfree/7709955
Android應用資料存放區幾種方式(2)
SQLite 是Android 所帶的一個標準的資料庫,它支援SQL 陳述式,它是一個輕量級的嵌入式資料庫.一個 SQLiteDatabase 的執行個體代表了一個SQLite 的資料庫,通過SQLiteDatabase 執行個體的一些方法,我們可以執行SQL 陳述式,對資料庫進行增,刪,查,改的操作.需要注意的是,資料庫對於一個應用來說是私人的,並且在一個應用當中,資料庫的名字也是惟一的.根據這名字,我們可以看出這個類是一個輔助類.這個類主要產生一個資料庫,並對資料庫的版本進行管理.當在程式當中調用這個類的方法getWritableDatabase(),或者getReadableDatabase()方法的時候,如果當時沒有資料,那麼Android 系統就會自動產生一個資料庫.SQLiteOpenHelper 是一個抽象類別,我們通常需要繼承它,並且實現裡邊的3 個函數,具體函數如下所示:onCreate(SQLiteDatabase):在資料庫第一次產生的時候會調用這個方法,一般我們在這個方法裡邊產生資料庫表.onUpgrade(SQLiteDatabase, int, int) :當資料庫需要升級的時候,Android 系統會主動的調用這個方法.一般我們在這個方法裡邊刪除資料表,並建立新的資料表,當然是否還需要做其他的操作,完全取決於應用的需求.另外我們在進行查詢的時候後調用這句代碼:Cursor cur = db.query(TABLE_NAME, col, null, null, null, null, null);下面對裡面的參數進行一下說明:第一個參數是資料庫裡邊表的名字,比如在我們這個例子,表的名字就是TABLE_NAME,也就是"diary".第二個欄位是我們想要返回資料包含的列的資訊.在這個例子當中我們想要得到的列有title、body.我們把這兩個列的名字放到字串數組裡邊來.第三個參數為selection,相當於sql 語句的where 部分,如果想返回所有的資料,那麼就直接置為null.第四個參數為selectionArgs。在selection 部分,你有可能用到?,那麼在selectionArgs 定義的字串會代替selection 中的?.
android應用程式中的一些固定的資料應該怎儲存
首先瞭解一下android的資料存放區方式:檔案流的讀取,SQLite,Content Provider以及Preference.。 註:resource和assets中的檔案使用者方面是只可以讀取不能夠進行寫的操作的。
Content Provider作為程式之間唯一共用資料途徑,用在這裡不是很合適。所以,
第一種方式,使用FileInputStream,FileOutputStreamdui類實現檔案I/O操作,直接往手機中儲存資料。
第二種方式,使用SQLite,通過SQLiteDatabase類中方法操作資料。
第三種方式,Preference用於儲存單一資料型別的資料,一些設定資訊的儲存。個人認為用在這裡最合適。 它利用索引值對儲存的。例:
儲存:SharedPreferences.Editor editor =sp.edit();
editor.putString(KEY_TEXT,"yonghu");
editor.commit();
擷取 :sp =getPreferences(MODE_PRIVATE);
String result =sp.getString(KEY_TEXT,null);