版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第7章Android的數(shù)據(jù)存儲本章簡介數(shù)據(jù)存儲是Android應(yīng)用最常使用的功能之一;將應(yīng)用程序的參數(shù)設(shè)置、運(yùn)行結(jié)果等持久化存儲到外部存儲器,能夠有效防止關(guān)機(jī)后關(guān)鍵數(shù)據(jù)的丟失;本章將詳細(xì)介紹Android應(yīng)用開發(fā)中經(jīng)常使用到的數(shù)據(jù)存儲操作,包括SharedPreferences、文件存儲和數(shù)據(jù)庫存儲。本章目錄7.1數(shù)據(jù)持久化簡介7.2SharedPreferences存儲7.3文件存儲7.4數(shù)據(jù)庫存儲7.6小結(jié)7.7習(xí)題7.1數(shù)據(jù)持久化簡介數(shù)據(jù)持久化指的是將內(nèi)存中應(yīng)用程序的中間數(shù)據(jù)或運(yùn)行結(jié)果永久保存到存儲介質(zhì)中,以防止關(guān)機(jī)后數(shù)據(jù)的丟失。Android提供了持久化數(shù)據(jù)存儲技術(shù)能夠?qū)?shù)據(jù)在瞬時狀態(tài)和持久狀態(tài)之間互相轉(zhuǎn)換。持久化數(shù)據(jù)存儲技術(shù)主要包括以下3種。7.1.1SharedPreferences存儲7.1.2文件存儲7.1.3數(shù)據(jù)庫存儲7.1.1SharedPreferences存儲SharedPreferences采用“鍵-值”對組織和管理數(shù)據(jù),其數(shù)據(jù)存儲到XML文件中。該方式實(shí)現(xiàn)簡單,是一種“輕量級”的存儲機(jī)制,適合簡單數(shù)據(jù)的存儲。7.1.2文件存儲與SharedPreferences存儲相比,文件存儲能夠保存大容量數(shù)據(jù),是一種“重量級”的存儲機(jī)制。但是,這種數(shù)據(jù)存儲機(jī)制不適合處理結(jié)構(gòu)化數(shù)據(jù)。7.1.3數(shù)據(jù)庫存儲與前兩種存儲方式相比,數(shù)據(jù)庫存儲不僅能夠保存大容量數(shù)據(jù),而且適合處理結(jié)構(gòu)化數(shù)據(jù)。借助于Android系統(tǒng)內(nèi)嵌的SQLite數(shù)據(jù)庫管理系統(tǒng),數(shù)據(jù)存儲機(jī)制能夠方便地對數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行增加、插入、刪除和更新等操作。7.2SharedPreferences存儲許多應(yīng)用程序只需要保存少量數(shù)據(jù),并且這些數(shù)據(jù)的格式相對較為簡單。SharedPreferences存儲方式非常適合這種類型的應(yīng)用。SharedPreferences使用“鍵-值”對的方式來存儲數(shù)據(jù):在保存數(shù)據(jù)的同時為其指定唯一的鍵,并且將鍵與保存的數(shù)據(jù)同時存儲在存儲介質(zhì)中;這樣,當(dāng)讀取數(shù)據(jù)時就可以通過鍵快速地將目標(biāo)數(shù)據(jù)提取出來。SharedPreferences還支持多種數(shù)據(jù)類型的存儲。例如,如果存儲的是整型數(shù)據(jù),那么,通過鍵讀取出來的數(shù)據(jù)也是整數(shù)類型;如果存儲的是字符串類型數(shù)據(jù),那么,通過鍵讀取出來的數(shù)據(jù)仍然是字符串類型。7.2.1將數(shù)據(jù)存儲到SharedPreferences中7.2.2從SharedPreferences中讀取數(shù)據(jù)7.2.1將數(shù)據(jù)存儲到SharedPreferences中
在使用SharedPreferences存儲數(shù)據(jù)前,首先應(yīng)獲得Android提供的SharedPreferences對象??墒褂孟率?種方法得到SharedPreferences對象。Context.getSharedPreferences(Stringname,FileCreationModemode)第一個參數(shù)用于指定SharedPreferences文件的名稱。如果指定的文件不存在,則會在/data/data/<packagename>/shared_prefs/目錄下按照輸入的文件名創(chuàng)建一個新的SharedPreferences文件。第二個參數(shù)則用于指定SharedPreferences文件操作模式。在Android6.0版本之后,僅有MODE_PRIVATE這一模式可選,它也是SharedPreferences的默認(rèn)操作模式。該模式表示只有創(chuàng)建SharedPreferences的應(yīng)用程序才能夠?qū)haredPreferences文件執(zhí)行讀、寫操作。Activity.getPreferences(intmode)該方法只需要輸入操作模式參數(shù),便能夠得到SharedPreferences對象。因為,該方法調(diào)用時會自動地將當(dāng)前Activity的類名作為SharedPreferences的文件名。PreferenceManager.getDefaultSharedPreferences(Contextcontext)這是一個靜態(tài)方法,它接收一個Context參數(shù),并自動使用當(dāng)前應(yīng)用程序的包名作為前綴來命名SharedPreferences文件。
當(dāng)?shù)玫絊haredPreferences對象之后,就可以按照下述步驟向SharedPreferences文件中寫入待保存的數(shù)據(jù)。調(diào)用SharedPreferences.edit()方法來獲得一個SharedPreferences.Editor對象。使用Editor.putXXX()方法向SharedPreferences.Editor對象中添加待保存的數(shù)據(jù)。例如,可以使用Editor.putBoolean()方法暫存一個布爾類型數(shù)據(jù);使用Editor.putString()方法暫存一個字符串類型數(shù)據(jù)。使用Editor.apply()方法將添加的數(shù)據(jù)提交,從而完成數(shù)據(jù)存儲操作。下面給出應(yīng)用示例7-1,它只有一個Activity——MainActivity,如圖7-1所示。當(dāng)單擊“保存數(shù)據(jù)”按鈕后,SharedPreferences會將應(yīng)用程序的數(shù)據(jù)存儲到指定的文件中。在項目視圖中,雙擊打開“MainActivity.java”文件,找到onCreate(…)方法,為“保存數(shù)據(jù)”按鈕添加數(shù)據(jù)存儲代碼。publicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//獲取“保存數(shù)據(jù)”按鈕ButtonsaveData=(Button)findViewById(R.id.savedatabtn);saveData.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){//獲取SharedPreferences.Editor對象SharedPreferences.Editoreditor=getSharedPreferences("data",MODE_PRIVATE).edit();
//添加不同類型的數(shù)據(jù)editor.putString("Name","Zhangsan");editor.putInt("Age",20);editor.putBoolean("Male",true);
//提交數(shù)據(jù)存儲editor.apply();}});}}代碼解釋:將數(shù)據(jù)存儲到SharedPreferences中的方法用粗體字標(biāo)記的代碼段表示??墒褂肁ctivity.getSharedPreferences()方法得到文件名為“data”的SharedPreferences對象;然后,調(diào)用SharedPreferences對象的edit()方法來獲得一個SharedPreferences.Editor對象;接著,使用Editor.putXXX()方法為Editor對象中添加了3個不同類型的數(shù)據(jù);最后,調(diào)用Editor對象的apply()方法完成了待存儲數(shù)據(jù)的提交。編譯并運(yùn)行程序,點(diǎn)擊主界面上的“保存數(shù)據(jù)”按鈕;然后,在AndroidStudio的AndroidDeviceMonitor窗口中將標(biāo)簽切換至FileExplorer。在/data/data/com.example.sharedpreferencesdemo/shared_prefs目錄下,可以看到新生成的data.xml文件,如圖7-2所示。使用FileExplorer面板的導(dǎo)出文件按鈕,將data.xml文件導(dǎo)出到本地計算機(jī)。用記事本打開該文件,可看到下述內(nèi)容:<?xmlversion='1.0'encoding='utf-8'standalone='yes'?><map><stringname="name">Zhangsan</string><booleanname="Male"value="true"/><intname="Age"value="20"/></map>可以看到,sharedpreferences文件的根節(jié)點(diǎn)是<map>,它使用<string>、<boolean>和<int>標(biāo)簽將應(yīng)用程序的數(shù)據(jù)用“鍵-值”對的方式保存。7.2.1從SharedPreferences中讀取數(shù)據(jù)
SharedPreferences.Editor提供了一系列g(shù)etXXX()方法,讀取存儲在SharedPreferences文件中的數(shù)據(jù)。getXXX()方法與上文介紹的putXXX()方法一一對應(yīng)。例如,可使用getBoolean()方法讀取一個布爾類型的數(shù)據(jù),可使用getString()方法讀取一個字符串類型的數(shù)據(jù)。getXXX()方法有兩個輸入?yún)?shù)。其中第一個參數(shù)是傳入存儲數(shù)據(jù)時所使用的鍵名;第二個參數(shù)則表示當(dāng)未找到“鍵-值”對時需返回的默認(rèn)存儲值7.2.1從SharedPreferences中讀取數(shù)據(jù)
修改應(yīng)用示例7-1,在主界面上添加了一個“讀取數(shù)據(jù)”按鈕,用以從SharedPreferences文件中讀取數(shù)據(jù)。在項目視圖中,雙擊打開“MainActivity.java”文件,找到onCreate(…)方法,為“讀取數(shù)據(jù)”按鈕添加讀取數(shù)據(jù)代碼。publicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButtonsaveData=(Button)findViewById(R.id.savedatabtn);
//獲取“讀取數(shù)據(jù)”按鈕ButtonreadData=(Button)findViewById(R.id.readdatabtn);…readData.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){//獲取SharedPreferences對象SharedPreferencespref=getSharedPreferences("data",MODE_PRIVATE);//讀取不同類型的數(shù)據(jù)Stringresult="Name:"+pref.getString("Name","")+"Age:"+pref.getInt("Age",0)+"Male:"+pref.getBoolean("Male",false);//顯示讀取到的數(shù)據(jù)Toast.makeText(MainActivity.this,result,Toast.LENGTH_SHORT).show();}});}}代碼解釋:從SharedPreferences中讀取數(shù)據(jù)的方法用粗體字標(biāo)記的代碼段表示。可使用Activity.getSharedPreferences()方法得到文件名為“data”的SharedPreferences對象;然后,使用SharedPreferences對象pref的getXXX()方法使用鍵名讀取存儲在SharedPreferences文件中的數(shù)據(jù);最后,可調(diào)用Toast對象的makeText()方法將讀取的數(shù)據(jù)顯示出來。編譯并重新運(yùn)行程序,點(diǎn)擊主界面上的“讀取數(shù)據(jù)”按鈕,將彈出一個Toast對話框顯示存儲在SharedPreferences文件中的數(shù)據(jù),如圖7-3所示。7.3文件存儲SharedPreferences存儲方式雖然使用起來比較方便;但是,它只適合存儲簡單類型的數(shù)據(jù)。此外,SharedPreferences保存的數(shù)據(jù)也是局限在應(yīng)用程序內(nèi)部使用。對于在更大范圍內(nèi)交換的復(fù)雜信息,可使用文件存儲。為打開指定目錄下的文件I/O流,Android的Context對象提供了下述方法:openFileInput(Stringname)該方法可為讀取在應(yīng)用程序數(shù)據(jù)目錄下的名為name的文件打開輸入流。openFileOutput(Stringname,intmode)該方法可為寫入在應(yīng)用程序數(shù)據(jù)目錄下的名為name的文件打開輸出流。其中,第二個參數(shù)指定文件的打開模式,有如下預(yù)定義的常量:(1)MODE_PRIVATE:文件只能被當(dāng)前程序讀寫。(2)MODE_APPEND:以追加方式打開文件。(3)MODE_WORLD_READABLE:文件可被其它應(yīng)用程序讀取。(4)MODE_WORLD_WRITEABLE:文件可被其它應(yīng)用程序讀寫。除此之外,為訪問應(yīng)用程序的數(shù)據(jù)目錄,Context對象還提供了下述方法:(1)getDir(Stringname,intmode)在應(yīng)用程序數(shù)據(jù)目錄下獲取或創(chuàng)建以name命名的子目錄。(2)getFilesDir()獲取應(yīng)用程序數(shù)據(jù)目錄的絕對路徑。(3)fileList()返回應(yīng)用程序數(shù)據(jù)目錄下的全部文件。(4)deleteFile(stringname)刪除應(yīng)用程序數(shù)據(jù)目錄下的指定文件。7.3.1讀寫應(yīng)用程序數(shù)據(jù)目錄內(nèi)的文件下面給出應(yīng)用示例7-2,它只有一個包含了兩組文本輸入框和按鈕的Activity——MainActivity。如圖7-4所示,第一組文本輸入框和按鈕主要用于向文件寫入數(shù)據(jù):可向文本框輸入待保存的數(shù)據(jù),當(dāng)點(diǎn)擊“保存文件”按鈕后,相應(yīng)數(shù)據(jù)將寫入到應(yīng)用程序數(shù)據(jù)目錄下的指定文件。如圖7-5所示,第二組文本輸入框和按鈕主要用于從指定文件讀取數(shù)據(jù):當(dāng)點(diǎn)擊“讀取文件”按鈕時,文本框?qū)@示讀取的文件內(nèi)容。在項目視圖中,雙擊打開“MainActivity.java”文件,找到onCreate(…)方法,分別為“保存文件”和“讀取文件”按鈕添加文件讀寫代碼。publicclassMainActivityextendsAppCompatActivity{finalStringFILE_NAME="FileTest.bin";@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);finalEditTextWrttxt=(EditText)findViewById(R.id.WrtfileContent);ButtonWrtbtn=(Button)findViewById(R.id.writefilebtn);
finalEditTextRdtxt=(EditText)findViewById(R.id.RdfileContent);ButtonRdbtn=(Button)findViewById(R.id.readfilebtn);
Wrtbtn.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){//將文本輸入框中的內(nèi)容寫入到文件
write(Wrttxt.getText().toString());Wrttxt.setText("");}});Rdbtn.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){//將文件中的內(nèi)容讀取到文本顯示框
Rdtxt.setText(read());}});}privatevoidwrite(StringTxtContent){try{
//以追加方式打開文件輸出流FileOutputStreamfos=openFileOutput(FILE_NAME,MODE_APPEND);//將FileOutputStream封裝成PrintStreamPrintStreamps=newPrintStream(fos);//輸出文件內(nèi)容ps.println(TxtContent);//關(guān)閉文件輸出流ps.close();}catch(Exceptione){e.printStackTrace();}}代碼解釋:第一段粗體字標(biāo)記的代碼段表示了向應(yīng)用程序數(shù)據(jù)目錄寫入文件的方法??墒褂胦penFileOutput()方法得到一個以追加方式寫入指定文件的FileOutputStream對象。然后,將該對象進(jìn)一步封裝成PrintStream對象。當(dāng)使用PrintStream對象的println()方法將文本輸入框內(nèi)容逐行寫入到文件后,應(yīng)使用close()方法關(guān)閉文件輸出流。privateStringread(){try{
//打開文件輸入流FileInputStreamfis=openFileInput(FILE_NAME);byte[]buff=newbyte[1024];inthasRead=0;StringBuildersb=newStringBuilder("");//讀取文件內(nèi)容while((hasRead=fis.read(buff))>0){sb.append(newString(buff,0,hasRead));}//關(guān)閉文件輸入流fis.close();returnsb.toString();}catch(Exceptione){e.printStackTrace();}returnnull;}}代碼解釋:第二段粗體字標(biāo)記的代碼段表示了從應(yīng)用程序數(shù)據(jù)目錄讀取文件的方法??墒褂胦penFileInput()方法打開一個用于讀取指定文件的FileInputStream對象。當(dāng)使用FileInputStream對象的read()方法將文件內(nèi)容讀取到緩沖區(qū)后,應(yīng)使用close()方法關(guān)閉文件輸入流。編譯并運(yùn)行程序,點(diǎn)擊主界面上的“保存文件”按鈕;然后,在AndroidStudio的AndroidDeviceMonitor窗口中將標(biāo)簽切換至FileExplorer。在/data/data/com.example.filerwdemo/files目錄下,可以看到新生成的FileTest.bin文件,如圖7-6所示。使用FileExplorer面板的導(dǎo)出文件按鈕,將FileTest.bin文件導(dǎo)出到本地計算機(jī)。用記事本打開該文件,可看到如圖7-7所示的文件內(nèi)容。7.3.2讀寫SD卡存儲的文件當(dāng)應(yīng)用程序使用Context.openFileOutput()方法打開文件輸出流時,寫入的數(shù)據(jù)將被保存到移動設(shè)備的內(nèi)部存儲介質(zhì)。顯然,這種文件讀寫方式不適合存儲大規(guī)模數(shù)據(jù)。為了更完整地支持多存儲介質(zhì)下文件內(nèi)容的讀寫,Android提供了讀寫SD卡存儲文件的方法??砂凑障率霾襟E讀寫SD卡存儲的文件。(1)調(diào)用Environment對象的getExternalStorageState()方法判斷移動設(shè)備是否插入了SD卡,它同時能夠判斷應(yīng)用程序是否有權(quán)限讀寫SD卡。(2)調(diào)用Environment對象的getExternalStorageDiretory()方法獲得移動設(shè)備為SD卡分配的目錄。(3)使用FileInputStream、FileOutputStream、FileReader或FileWriter等對象讀寫SD卡中存儲的文件。下面給出應(yīng)用示例7-3,它在示例程序7-2的基礎(chǔ)上將讀寫文件的路徑修改到了SD卡的存儲目錄。在項目視圖中,雙擊打開“MainActivity.java”文件,修改由示例程序7-2編寫的write()方法和read()。privatevoidwrite(StringTxtContent){try{//如果手機(jī)插入了SD卡,并且應(yīng)用程序具有SD卡訪問權(quán)限if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){//獲取SDK卡目錄FileSdDir=Environment.getExternalStorageDirectory();FiletargetFile=newFile(SdDir.getCanonicalPath()+FILE_NAME);//以指定文件RandomAccessFile對象RandomAccessFileraf=newRandomAccessFile(targetFile,"rw");//將文件記錄指針移動到最后raf.seek(targetFile.length());//輸出文件內(nèi)容raf.write(TxtContent.getBytes());//關(guān)閉RandomAccessFileraf.close();}}catch(Exceptione){e.printStackTrace();}}代碼解釋:第一段粗體字標(biāo)記的代碼段表示了向SD卡目錄寫入文件數(shù)據(jù)的方法。首先,調(diào)用Environment對象的getExternalStorageState()方法判斷存儲卡狀態(tài)是否滿足文件讀寫的要求。然后,創(chuàng)建RandomAccessFile對象,并使用該對象的write()方法將文本輸入框的內(nèi)容寫入到SD卡的文件。最后,應(yīng)使用close()方法關(guān)閉RandomAccessFile對象。privateStringread(){try{//如果手機(jī)插入了SD卡,而且應(yīng)用程序具有SD卡訪問權(quán)限if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){//獲取SDK卡目錄FileSdDir=Environment.getExternalStorageDirectory();//獲得指定文件對應(yīng)的輸入流FileInputStreamfis=newFileInputStream(SdDir.getCanonicalPath()+FILE_NAME);//將指定輸入流包裝成BufferedReaderBufferedReaderbr=newBufferedReader(newInputStreamReader(fis));StringBuildersb=newStringBuilder("");Stringlinetxt=null;//循環(huán)讀取文件內(nèi)容while((linetxt=br.readLine())!=null){sb.append(linetxt);}//關(guān)閉資源br.close();returnsb.toString();}}catch(Exceptione){e.printStackTrace();}returnnull;}第二段粗體字標(biāo)記的代碼段表示了從SD卡讀取文件中存儲內(nèi)容的方法。與寫入文件數(shù)據(jù)類似,首先應(yīng)調(diào)用Environment對象的getExternalStorageState()方法判斷存儲卡狀態(tài)是否滿足文件讀寫的要求。然后,用FileInputStream包裝并創(chuàng)建一個BufferedReader對象,并使用該對象的readLine()方法按行讀取在SD卡中存儲的文件內(nèi)容。最后,還應(yīng)使用close()方法關(guān)閉BufferedReader對象。需要注意的是,在讀寫SD卡上存儲的文件前,應(yīng)為應(yīng)用程序授予讀寫SD卡的權(quán)限。在項目視圖中,雙擊打開“AndroidManifest.xml”清單文件,為應(yīng)用程序配置對SD卡上存儲文件的操作權(quán)限。<!--在SD卡中創(chuàng)建與刪除文件權(quán)限--><uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><!--在SD卡寫入數(shù)據(jù)權(quán)限--><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>編譯并運(yùn)行程序,單擊主界面中的“保存文件到SD卡”按鈕可將用戶在文本輸入框中輸入的內(nèi)容保存在SD卡的指定文件中,如圖7-8所示。類似地,也可打開移動設(shè)備為掛載SD卡生成的/mnt/sdcard目錄,查看應(yīng)用程序保存的“SDFileTest.bin”文件。7.4數(shù)據(jù)庫存儲SharedPreferences和文件存儲非常適合保存結(jié)構(gòu)簡單、存儲容量不大的數(shù)據(jù)。但是,難以適應(yīng)應(yīng)用程序大容量、復(fù)雜類型的數(shù)據(jù)保存要求。Android系統(tǒng)內(nèi)默認(rèn)集成了一個輕量級的嵌入式數(shù)據(jù)庫—SQLite。它運(yùn)算速度快、占用資源少,特別適合在移動設(shè)備上使用。SQLite不僅能夠支持標(biāo)準(zhǔn)的SQL語法,而且還支持ACID事務(wù)操作,十分適合開發(fā)數(shù)據(jù)庫應(yīng)用程序。7.4.1SQLite簡介與常見的關(guān)系數(shù)據(jù)庫管理系統(tǒng)相比,SQLite數(shù)據(jù)庫要簡單得多。它的底層實(shí)際上就是一個數(shù)據(jù)庫文件,很多情況下甚至無需使用用戶名和密碼,就可以訪問數(shù)據(jù)庫。為操作和訪問數(shù)據(jù)庫,AndroidSDK提供了SQLiteDatabase類??梢允褂肧QLiteDatabase類的下述靜態(tài)方法連接SQLite數(shù)據(jù)庫。(1)openDatabase(Stringpath,CursorFactoryfactory,intflags)該方法用于打開一個以path文件表示的SQLite數(shù)據(jù)庫連接。(2)openOrCreateDatabase(Filefile,CursorFactoryfactory)該方法打開或新建一個用file文件表示的SQLite數(shù)據(jù)庫連接。(3)openOrCreateDatabase(Stringpath,CursorFactoryfactory)該方法用于打開或新建以一個以path文件表示的SQLite數(shù)據(jù)庫連接當(dāng)獲取連接到數(shù)據(jù)庫的SQLiteDatabase對象以后,就可以使用下述方法對數(shù)據(jù)庫進(jìn)行操作。(1)execSQL(Stringsql)該方法用于執(zhí)行SQL語句。(2)insert(Stringtable,StringnullColumnHack,ContentValuesvalues)該方法用于向數(shù)據(jù)表插入記錄。(3)update(Stringtable,ContentValuesvalues,StringwhereClause,String[]whereArgs)該方法用于更新數(shù)據(jù)表中滿足條件的若干條記錄。(4)delete(Stringtable,StringwhereClause,String[]whereArgs)該方法用于刪除數(shù)據(jù)表中滿足條件的若干條記錄。(5)query(Stringtable,String[]colums,StringwhereClause,String[]whereArgs,StringgroupBy,Stringhaving,StringorderBy)該方法用于對數(shù)據(jù)表執(zhí)行按條件的查詢操作。(6)beginTransaction()該方法用于啟動數(shù)據(jù)庫事務(wù)。(7)endTransaction()該方法用于結(jié)束數(shù)據(jù)庫事務(wù)。使用query()方法能夠返回一個游標(biāo)對象(Cursor),這個對象提供了下述方法以移動查詢結(jié)果的指針。(1)move(intoffset)該方法將查詢記錄的指針向上或向下移動指定個數(shù)的記錄。(2)moveToFirst()該方法將查詢記錄的指針移動到第一條記錄。(3)moveToLast()該方法將查詢記錄的指針移動到最后一條記錄。(4)moveToNext()該方法將查詢記錄的指針移動到下一條記錄。(5)moveToPrevious()該方法將查詢記錄的指針移動到上一條記錄。一旦將查詢記錄指針移動到指定位置后,就可以使用Cursor.GetXXX()方法獲取該記錄指定列的數(shù)據(jù)。7.4.2創(chuàng)建和更新數(shù)據(jù)庫為方便用戶管理SQLite數(shù)據(jù)庫,Android提供了SQLiteOpenHelper類。使用該類可以非常簡單地創(chuàng)建數(shù)據(jù)庫和對數(shù)據(jù)庫進(jìn)行版本升級。SQLiteOpenHelper類包含下述常用方法。(1)getReadableDatabase()該方法以讀寫的方式打開數(shù)據(jù)庫對應(yīng)的SQLiteDatabase對象。(2)getWritableDatabase()該方法以寫的方式打開數(shù)據(jù)庫對應(yīng)的SQLiteDatabase對象。(3)onCreate(SQLiteDatabasedb)該方法用于初次創(chuàng)建數(shù)據(jù)庫時被調(diào)用。當(dāng)使用前兩種方法打開數(shù)據(jù)庫連接時,如果數(shù)據(jù)庫不存在,Android系統(tǒng)就會自動創(chuàng)建一個數(shù)據(jù)庫。onCreate()方法只有在第一次創(chuàng)建數(shù)據(jù)庫時才會被調(diào)用??稍诟矊懙膐nCreate()方法中為新創(chuàng)建的數(shù)據(jù)庫添加表結(jié)構(gòu)。(4)onUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion)該方法用于更新數(shù)據(jù)庫表結(jié)構(gòu),它將在數(shù)據(jù)庫的版本發(fā)生變化時被調(diào)用。當(dāng)創(chuàng)建SQLiteOpenHelper對象時指定的數(shù)據(jù)庫版本號高于歷史版本,Android系統(tǒng)就會自動觸發(fā)onUpgrade()方法。(5)close()關(guān)閉所有已打開的數(shù)據(jù)庫連接。下面創(chuàng)建一個名為BookStore.db的數(shù)據(jù)庫,它只包含一張Book數(shù)據(jù)表。該數(shù)據(jù)表包含書號(主鍵)、書名、作者、定價和總頁碼數(shù)據(jù)列??墒褂孟率鯯QL語句創(chuàng)建Book表的邏輯結(jié)構(gòu)。CreatetableBook(idintegerprimarykey,//書號authortext,//作者pricereal,//定價pagesinteger,//總頁碼nametext//書名)可從SQLiteOpenHelper類中派生出MyDatabseHelper子類,并在該類中覆寫onCreate()方法完成Book表的創(chuàng)建操作。publicclassMyDatabseHelperextendsSQLiteOpenHelper{//創(chuàng)建Book數(shù)據(jù)表的SQL語句字符串常量
publicstaticfinalStringCREATE_BOOK="createtableBook("+"idintegerprimarykey,"+"authortext,"+"pricereal,"+"pagesinteger,"+"nametext)";privateContextmContext;MyDatabseHelper(Contextcontext,Stringname,SQLiteDatabase.CursorFactoryfactory,intversion){super(context,name,factory,version);mContext=context;}@OverridepublicvoidonCreate(SQLiteDatabasedb){
//執(zhí)行Book表創(chuàng)建語句db.execSQL(CREATE_BOOK);Toast.makeText(mContext,"BookTableCreateSuccess!",Toast.LENGTH_SHORT).show();}@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){}}代碼解釋:第一段用粗體字標(biāo)記的代碼段定義了一個常量字符串,用以表示創(chuàng)建Book數(shù)據(jù)表時使用的SQL語句。第二段用粗體字標(biāo)記的代碼段給出了SQL語句的執(zhí)行方法??墒褂肧QLiteDatabase對象的execSQL()方法執(zhí)行SQL語句。當(dāng)SQL語句執(zhí)行完畢,可使用Toast對象提示Book表創(chuàng)建成功信息。下面給出應(yīng)用示例7-4,它只有一個包含了“創(chuàng)建BookStore數(shù)據(jù)庫”按鈕的Activity——MainActivity。如圖7-9所示,單擊“創(chuàng)建BookStore數(shù)據(jù)庫”按鈕即可新建一個上文定義的Book數(shù)據(jù)表。在項目視圖中,雙擊打開“MainActivity.java”文件,找到onCreate()方法,添加下述代碼創(chuàng)建數(shù)據(jù)庫和數(shù)據(jù)表。publicclassMainActivityextendsAppCompatActivity{privateMyDatabseHelperdbHelper;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//創(chuàng)建MyDatabseHelper對象dbHelper=newMyDatabseHelper(this,"BookStore.db",null,1);//獲取“創(chuàng)建Book表”按鈕ButtoncreateDbtn=(Button)findViewById(R.id.create_DbTable);//為按鈕創(chuàng)建點(diǎn)擊事件監(jiān)聽器createDbtn.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){
dbHelper.getWritableDatabase();}});}}代碼解釋:第一段用粗體字標(biāo)記的代碼段給出了SQLiteOpenHelper對象的構(gòu)造方法??墒褂米許QLiteOpenHelper類繼承的MyDatabseHelper子類的構(gòu)造函數(shù)將新創(chuàng)建的數(shù)據(jù)庫命名為BookStore.db,并將其版本號指定為1。第二段用粗體字標(biāo)記的代碼段給出了打開數(shù)據(jù)庫連接的實(shí)現(xiàn)方法??墒褂肧QLiteOpenHelper對象的getWritableDatabase()方法為操作數(shù)據(jù)庫打開一個訪問連接。當(dāng)?shù)谝淮握{(diào)用該方法時,由于未在系統(tǒng)中查找到BookStore.db文件,Android系統(tǒng)便會自動創(chuàng)建BookStore數(shù)據(jù)庫;然后,調(diào)用MyDatabaseHelper對象中的onCreate()方法創(chuàng)建Book數(shù)據(jù)表。編譯并運(yùn)行程序,點(diǎn)擊主界面上的“創(chuàng)建BOOK數(shù)據(jù)庫”按鈕,即可創(chuàng)建BookStore數(shù)據(jù)庫,如圖7-10所示??墒褂肁ndroidSDK自帶的adb調(diào)試工具查看新建的數(shù)據(jù)庫。操作步驟如下:(1)打開windos命令行工具,在提示符下輸入adbshell命令,進(jìn)入到Android模擬器的控制臺,如圖7-11所示。(2)使用su命令獲得系統(tǒng)權(quán)限,如圖7-12所示。(3)使用cd命令進(jìn)入到保存應(yīng)用程序數(shù)據(jù)庫的目錄,可使用ls命令查看到該目錄下的所有文件,如圖7-13所示??梢钥吹皆撃夸洶▋蓚€文件:一個是由應(yīng)用創(chuàng)建的BookStore.db文件,另一個文件則是Android系統(tǒng)為支持?jǐn)?shù)據(jù)庫事務(wù)處理而產(chǎn)生的日志文件。(4)將BookStore.db作為sqlite3命令的輸入?yún)?shù),打開BookStore數(shù)據(jù)庫,如圖7-14所示。(5)在sqlite提示符下,輸入.table命令列出所有數(shù)據(jù)表,如圖7-15所示??梢钥吹?,由MyDatabaseHelper類創(chuàng)建的Book數(shù)據(jù)表。(6)在sqlite提示符下,輸入.schema命令,可查看建立Book數(shù)據(jù)表所使用到的SQL語句,如圖7-16所示。由此可知,BookStore數(shù)據(jù)庫和Book表已成功創(chuàng)建。(7)在sqlite提示符下,輸入.exit命令可退出數(shù)據(jù)庫管理。為方便對BookStore數(shù)據(jù)庫中輸入的圖書信息進(jìn)行分類管理,可再添加一張名為Category的數(shù)據(jù)表,然后再更新數(shù)據(jù)庫??墒褂孟率鯯QL語句創(chuàng)建Category表的邏輯結(jié)構(gòu)。createtableCategory(idintegerprimarykey,//主鍵category_nametext,//圖書分類名category_codeinteger//圖書分類代碼)為創(chuàng)建Category數(shù)據(jù)表,可修改MyDataBaseHelper類的定義,并將下述代碼添加到MyDataBaseHelper類中。publicclassMyDatabseHelperextendsSQLiteOpenHelper{…//創(chuàng)建Category表SQL語句publicstaticfinalStringCREATE_CATEGORY="createtableCategory("+"idintegerprimarykeyautoincrement,"+"category_nametext,"+"category_codeinteger)";privateContextmContext;MyDatabseHelper(Contextcontext,Stringname,SQLiteDatabase.CursorFactoryfactory,intversion){super(context,name,factory,version);mContext=context;}代碼解釋:第一段用粗體字標(biāo)記的代碼段定義了一個常量字符串,用以表示創(chuàng)建Category數(shù)據(jù)表時使用的SQL語句。@OverridepublicvoidonCreate(SQLiteDatabasedb){//執(zhí)行Book表創(chuàng)建語句db.execSQL(CREATE_BOOK);
//執(zhí)行Category表創(chuàng)建語句db.execSQL(CREATE_CATEGORY);Toast.makeText(mContext,"BookTableCreateSuccess!",Toast.LENGTH_SHORT).show();}@OverridepublicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){db.execSQL("droptableifexistsBook");db.execSQL("droptableifexistsCategory");onCreate(db);
}}代碼解釋:第二段用粗體字標(biāo)記的代碼段給出了Category數(shù)據(jù)表的創(chuàng)建方法。第三段用粗體字標(biāo)記的代碼段給出了BookStore數(shù)據(jù)庫的更新方法。在覆寫的onUpgrade()方法中,可先執(zhí)行對數(shù)據(jù)庫中已經(jīng)存在Book表和Category表DROP操作,將這兩張數(shù)據(jù)表刪除;然后,再調(diào)用onCreate()方法重新創(chuàng)建數(shù)據(jù)表。為了觸發(fā)對數(shù)據(jù)庫更新操作,還應(yīng)同步修改創(chuàng)建SQLiteOpenHelper對象時指定的數(shù)據(jù)庫版本號。在項目視圖中,雙擊打開“MainActivity.java”文件,找到onCreate()方法,將創(chuàng)建MyDatabseHelper對象時指定數(shù)據(jù)庫版本號修改為2,見用粗體字標(biāo)記的代碼。publicclassMainActivityextendsAppCompatActivity{privateMyDatabseHelperdbHelper;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){…//創(chuàng)建MyDatabseHelper對象
dbHelper=newMyDatabseHelper(this,"BookStore.db",null,2);…}}編譯并運(yùn)行程序,點(diǎn)擊“創(chuàng)建BOOKSTORE數(shù)據(jù)庫”按鈕,此時將再次彈出數(shù)據(jù)庫創(chuàng)建成功提示。為驗證數(shù)據(jù)庫是否創(chuàng)建成功,可使用.table命令,列出數(shù)據(jù)庫中的所有表,如圖7-17所示??梢钥吹?,在BookStore數(shù)據(jù)庫中已經(jīng)通過更新操作成功創(chuàng)建了Category表。7.4.3添加數(shù)據(jù)庫記錄SQLiteDatabase類提供了insert()方法可以方便地為數(shù)據(jù)表添加記錄。該方法接收3個輸入?yún)?shù):第一個參數(shù)用于指定操作的數(shù)據(jù)庫表名;第二個參數(shù)用于為輸入可為空的列在未輸入數(shù)據(jù)時自動賦null值;第三個參數(shù)則是一個ContentValues對象,它提供了一系列put()方法的重載,可用于向ContentValues中添加數(shù)據(jù)。下面將在應(yīng)用示例7-4的基礎(chǔ)上,為Book數(shù)據(jù)表添加記錄。在項目視圖中,雙擊打開“activity_main.xml”文件,為MainActivity增加一個“添加數(shù)據(jù)庫記錄”按鈕,代碼如下:<LinearLayout…>…<Buttonandroid:id="@+id/add_data"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="添加數(shù)據(jù)庫記錄"/>…<LinearLayout/>然后,再修改“MainActivity.java”文件,為“添加數(shù)據(jù)庫記錄”按鈕增加點(diǎn)擊事件處理邏輯:publicclassMainActivityextendsAppCompatActivity{privateMyDatabseHelperdbHelper;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){…ButtonaddData=(Button)findViewById(R.id.add_data);addData.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){
SQLiteDatabasedb=dbHelper.getWritableDatabase();ContentValuesvalues=newContentValues();//添加第一條數(shù)據(jù)values.put("name","JavaLanguage");values.put("author","Zhangsan");values.put("pages",454);values.put("price",16.96);db.insert("Book",null,values);values.clear();//添加第二條數(shù)據(jù)values.put("name","CLanguage");values.put("author","Lisi");values.put("pages",510);values.put("price",19.95);db.insert("Book",null,values);}});}}代碼解釋:用粗體字標(biāo)記的代碼段給出了向Book數(shù)據(jù)表添加記錄的方法。可使用ContentValues對象的put()方法,按照列名將各列記錄值傳入到該對象存儲起來;然后,使用SQLiteDatabase對象的insert()方法將數(shù)據(jù)記錄逐一添加到Book數(shù)據(jù)表中。編譯并運(yùn)行程序,點(diǎn)擊“添加數(shù)據(jù)庫記錄”按鈕,如圖7-18所示。使用AndroidSDK自帶的adb調(diào)試工具,在命令提示符下輸入SQL查詢語句select*fromBook,可以查詢到新添加的兩條數(shù)據(jù)庫記錄,如圖7-19所示。7.4.4更新數(shù)據(jù)庫記錄SQLiteDatabase類提供了update()方法可以更新數(shù)據(jù)庫記錄。該方法接收4個輸入?yún)?shù):第一個參數(shù)用于指定執(zhí)行更新操作的數(shù)據(jù)庫表名;第二個參數(shù)是一個ContentValues對象,用于封裝更新的數(shù)據(jù)庫記錄;第三和第四個參數(shù)則用于設(shè)置記錄更新條件,默認(rèn)無條件更新所有記錄。下面將在應(yīng)用示例7-4的基礎(chǔ)上,修改Book數(shù)據(jù)表中書名為“JavaLanguage”的數(shù)據(jù)記錄的定價信息。在項目視圖中,雙擊打開“activity_main.xml”文件,為MainActivity增加一個“更新數(shù)據(jù)庫記錄”按鈕,代碼如下:<LinearLayout…>…
<Buttonandroid:id="@+id/update_data"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="更新數(shù)據(jù)庫記錄"/>…<LinearLayout/>然后,再修改“MainActivity.java”文件,為“更新數(shù)據(jù)庫記錄”按鈕增加點(diǎn)擊事件處理邏輯:publicclassMainActivityextendsAppCompatActivity{privateMyDatabseHelperdbHelper;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){…ButtonupdateData=(Button)findViewById(R.id.update_data);updateData.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){SQLiteDatabasedb=dbHelper.getWritableDatabase();ContentValuesvalues=newContentValues();values.put("price",10.99);db.update("Book",values,"name=?",newString[]{"JavaLanguage"});}}}代碼解釋:用粗體字標(biāo)記的代碼段給出了更新Book數(shù)據(jù)表指定數(shù)據(jù)記錄的方法??墒褂肅ontentValues對象的put()方法封裝數(shù)據(jù)記錄的更新值;然后,使用SQLiteDatabase對象的update()方法執(zhí)行數(shù)據(jù)更新操作。這里,使用update()方法的后兩個輸入?yún)?shù)指定數(shù)據(jù)記錄的更新條件:第三個參數(shù)是SQL語句的更新條件,它表示更新所有name列等于?(占位符)的數(shù)據(jù)記錄;第四個參數(shù)則提供了一個字符串?dāng)?shù)組以替換上述占位符的內(nèi)容。編譯并運(yùn)行程序,點(diǎn)擊“更新數(shù)據(jù)庫記錄”按鈕,如圖7-20所示。使用AndroidSDK自帶的adb調(diào)試工具,在命令提示符下輸入SQL查詢語句select*fromBook,可以觀察到數(shù)據(jù)更新成功,如圖7-21所示。7.4.5刪除數(shù)據(jù)庫記錄SQLiteDatabase類提供了delete()方法可以刪除數(shù)據(jù)庫記錄。該方法接收3個輸入?yún)?shù):第一個參數(shù)用于指定操作的數(shù)據(jù)庫表名;第三和第四個參數(shù)則用于設(shè)置記錄刪除條件,默認(rèn)無條件刪除所有記錄。下面將在應(yīng)用示例7-4的基礎(chǔ)上,將Book數(shù)據(jù)表中超過500頁的圖書全部刪除。在項目視圖中,雙擊打開“activity_main.xml”文件,為MainActivity增加一個“刪除數(shù)據(jù)庫記錄”按鈕,代碼如下:<LinearLayout…>…<Buttonandroid:id="@+id/delete_data"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="刪除數(shù)據(jù)庫記錄"/>…<LinearLayout/>然后,再修改“MainActivity.java”文件,為“刪除數(shù)據(jù)庫記錄”按鈕增加點(diǎn)擊事件處理邏輯:publicclassMainActivityextendsAppCompatActivity{privateMyDatabseHelperdbHelper;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){…ButtondeleteButton=(Button)findViewById(R.id.delete_data);deleteButton.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){
SQLiteDatabasedb=dbHelper.getWritableDatabase();db.delete("Book","pages>?",newString[]{"500"});}});}}}代碼解釋:用粗體字標(biāo)記的代碼段給出了刪除Book數(shù)據(jù)表中滿足指定條件的記錄的方法??墒褂肧QLiteDatabase對象的delete()方法執(zhí)行數(shù)據(jù)刪除操作。這里,使用delete()方法的后兩個輸入?yún)?shù)指定數(shù)據(jù)記錄的更新條件:第二個參數(shù)是SQL語句的刪除條件,它表示刪除所有pages列等于>?(占位符)的數(shù)據(jù)記錄;第三個參數(shù)則提供了一個字符串?dāng)?shù)組以替換上述占位符的內(nèi)容。編譯并運(yùn)行程序,點(diǎn)擊“刪除數(shù)據(jù)庫記錄”按鈕,如圖7-22所示。使用AndroidSDK自帶的adb調(diào)試工具,在命令提示符下輸入SQL查詢語句select*fromBook,可以觀察到所有頁碼大于500的圖書都已成功刪除,如圖7-23所示。7.4.6查詢數(shù)據(jù)庫記錄SQLiteDatabase類提供了query()方法用于查詢數(shù)據(jù)庫記錄。該方法接收7個輸入?yún)?shù):第一個參數(shù)用于指定查詢的數(shù)據(jù)庫表名;第二個參數(shù)用于指定查詢的數(shù)據(jù)列,默認(rèn)查詢所有數(shù)據(jù)列;第三個和第四個參數(shù)則用于設(shè)置記錄查詢條件,默認(rèn)查詢所有數(shù)據(jù)記錄;第五個參數(shù)用于對查詢結(jié)果進(jìn)行分組統(tǒng)計的列名;第六個參數(shù)用于設(shè)定對查詢結(jié)果的過濾條件,默認(rèn)不過濾查詢結(jié)果;第七個參數(shù)則指定查詢結(jié)果的排序方式,不指定則使用默認(rèn)的排序方式。調(diào)用query()方法后會返回一個Cursor對象,可從該對象取出查詢到的結(jié)果。下面將在應(yīng)用示例7-4的基礎(chǔ)上,將Book數(shù)據(jù)表中所有圖書全部查詢出來。在項目視圖中,雙擊打開“activity_main.xml”文件,為MainActivity增加一個“查詢數(shù)據(jù)庫記錄”按鈕,代碼如下:<LinearLayout…>…<Buttonandroid:id="@+id/query_data"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="查詢數(shù)據(jù)庫記錄"/>…<LinearLayout/>然后,再修改“MainActivity.java”文件,為“查詢數(shù)據(jù)庫記錄”按鈕增加點(diǎn)擊事件處理邏輯:publicclassMainActivityextendsAppCompatActivity{privateMyDatabseHelperdbHelper;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){…ButtonqueryButton=(Button)findViewById(R.id.query_data);queryButton.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){
SQLiteDatabasedb=dbHelper.getWritableDatabase();//查詢Book表中所有的數(shù)據(jù)Cursorcursor=db.query("Book",null,null,null,null,null,null);if(cursor.moveToFirst()){do{//遍歷Cursor對象,取出數(shù)據(jù)并打印Stringname=cursor.getString(cursor.getColumnIndex("name"));
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 機(jī)械課程設(shè)計底圖
- 研學(xué)課程設(shè)計點(diǎn)評方案
- 2024年融資借款增補(bǔ)協(xié)議標(biāo)準(zhǔn)文本
- 病理性感染課程設(shè)計
- 福州幼兒園校本課程設(shè)計
- 鹽城師范課程設(shè)計表
- 2025黑龍江省安全員B證(項目經(jīng)理)考試題庫
- 白酒市場營銷課程設(shè)計
- 童話森林主題課程設(shè)計
- 2024年遼寧省安全員B證考試題庫
- 水泥常規(guī)試驗作業(yè)指導(dǎo)書
- 國有土地上房屋裝修備案申請表
- 遼寧盤錦浩業(yè)化工“1.15”泄漏爆炸著火事故
- 紅黃綠白黑五色食物巧選擇紅黃綠白黑五色健康法
- 辦公樓裝修工程難點(diǎn)、重點(diǎn)分析及對策
- 動物行為學(xué)論文(無刪減范文8篇),動物學(xué)論文
- 社會工作理論復(fù)習(xí)資料
- 某市自來水廠工藝設(shè)計
- 2023年公務(wù)員體檢表
- GB/T 9115-2010對焊鋼制管法蘭
- GB/T 20882.2-2021淀粉糖質(zhì)量要求第2部分:葡萄糖漿(粉)
評論
0/150
提交評論