Android应用开发:数据存储和界面展现-1
1. 相對(duì)布局RelativeLayout
特點(diǎn):相對(duì)布局所有組件可以疊加在一起;各個(gè)組件的布局是獨(dú)立的,互不影響;所有組件的默認(rèn)位置都是在左上角(頂部、左部對(duì)齊)
| android:layout_toRightOf | 在指定控件的右邊 |
| android:layout_toLeftOf | 在指定控件的左邊 |
| android:layout_above | 在指定控件的上邊 |
| android:layout_below | 在指定控件的下邊 |
| android:layout_alignBaseline | 跟指定控件水平對(duì)齊 |
| android:layout_alignLeft | 跟指定控件左對(duì)齊 |
| android:layout_alignRight | 跟指定控件右對(duì)齊 |
| android:layout_alignTop | 跟指定控件頂部對(duì)齊 |
| android:layout_alignBottom | 跟指定控件底部對(duì)齊 |
| android:layout_alignParentLeft | 是否跟父元素左對(duì)齊 |
| android:layout_alignParentTop | 是否跟父元素頂部對(duì)齊 |
| android:layout_alignParentRight | 是否跟父元素右對(duì)齊 |
| android:layout_alignParentBottom | 是否跟父元素底部對(duì)齊 |
| android:layout_centerVertical | 在父元素中垂直居中 |
| android:layout_centerHorizontal | 在父元素中水平居中 |
| android:layout_centerInParent | 在父元素中居中 |
示例1:res\layout\activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><!-- android:layout_alignParentRight="true"表示與父元素右對(duì)齊(這里,父元素指的就是RelativeLayout,而RelativeLayout占滿了整個(gè)屏幕) --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個(gè)" android:layout_alignParentRight="true"/><!-- android:layout_alignParentBottom="true"表示與父元素底部對(duì)齊(這里,父元素指的就是RelativeLayout,而RelativeLayout占滿了整個(gè)屏幕) --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第二個(gè)" android:layout_alignParentBottom="true"/><!-- android:layout_centerVertical="true"表示在父元素中垂直居中(這里,父元素指的就是RelativeLayout,而RelativeLayout占滿了整個(gè)屏幕) --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第三個(gè)" android:layout_centerVertical="true"/><!-- android:layout_centerHorizontal="true"表示在父元素中水平居中(這里,父元素指的就是RelativeLayout,而RelativeLayout占滿了整個(gè)屏幕) --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第四個(gè)" android:layout_centerHorizontal="true"/><!-- android:layout_centerInParent="true"表示在父元素中水平垂直都居中(這里,父元素指的就是RelativeLayout,而RelativeLayout占滿了整個(gè)屏幕) --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第五個(gè)" android:layout_centerInParent="true"/> </RelativeLayout>運(yùn)行結(jié)果:
示例2:res\layout\activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><TextView android:id="@+id/tv1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一一一一個(gè)" /><!-- android:layout_alignRight="true"表示與指定組件右對(duì)齊。 --><!-- @+id/就是為組件添加id,@id就是通過(guò)id引用組件 --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第二個(gè)" android:layout_centerVertical="true"android:layout_alignRight="@id/tv1"/><!-- 如果同時(shí)使用android:layout_alignRight="true",android:layout_alignLeft="true",組件就會(huì)被拉伸 --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第三個(gè)" android:layout_alignParentBottom="true"android:layout_alignRight="@id/tv1"android:layout_alignLeft="@id/tv1"/> </RelativeLayout>運(yùn)行結(jié)果:
示例3:res\layout\activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><TextView android:id="@+id/tv1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個(gè)"android:layout_centerHorizontal="true"/><!-- android:layout_below="@id/tv1"表示在對(duì)應(yīng)組件的下面 --><TextView android:id="@+id/tv2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第二個(gè)"android:layout_below="@id/tv1"/><!-- android:layout_above="@id/tv2"表示在對(duì)應(yīng)組件的上面 --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第三個(gè)"android:layout_above="@id/tv2"/><!-- android:layout_toRightOf="@id/tv2"表示在對(duì)應(yīng)組件的右邊 --><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第四個(gè)"android:layout_toRightOf="@id/tv2"/> </RelativeLayout>運(yùn)行結(jié)果:
練習(xí):實(shí)現(xiàn)如下效果
代碼:res\layout\activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><Button android:id="@+id/center"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="中間"android:layout_centerInParent="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="上邊"android:layout_above="@id/center"android:layout_alignLeft="@id/center"android:layout_alignRight="@id/center"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下邊"android:layout_below="@id/center"android:layout_alignLeft="@id/center"android:layout_alignRight="@id/center"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="左邊"android:layout_toLeftOf="@id/center"android:layout_alignTop="@id/center"android:layout_alignBottom="@id/center"android:layout_alignParentLeft="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="右邊"android:layout_toRightOf="@id/center"android:layout_alignTop="@id/center"android:layout_alignBottom="@id/center"android:layout_alignParentRight="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="左上"android:layout_toLeftOf="@id/center"android:layout_above="@id/center"android:layout_alignParentLeft="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="左下"android:layout_toLeftOf="@id/center"android:layout_below="@id/center"android:layout_alignParentLeft="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="右上"android:layout_toRightOf="@id/center"android:layout_above="@id/center"android:layout_alignParentRight="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="右下"android:layout_toRightOf="@id/center"android:layout_below="@id/center"android:layout_alignParentRight="true"/> </RelativeLayout>運(yùn)行結(jié)果:
2. 幀布局FrameLayout
特點(diǎn):幀布局和相對(duì)布局一樣,組件可以重疊;所有組件的默認(rèn)位置是在左上角(頂部、左部對(duì)齊)
示例:res\layout\activity_main.xml
運(yùn)行結(jié)果:
練習(xí):實(shí)現(xiàn)如下效果
代碼:res\layout\activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><TextView android:layout_width="240dp"android:layout_height="240dp"android:background="#ff0000"android:layout_gravity="center"/><TextView android:layout_width="200dp"android:layout_height="200dp"android:background="#00ff00"android:layout_gravity="center"/><TextView android:layout_width="160dp"android:layout_height="160dp"android:background="#0000ff"android:layout_gravity="center"/><TextView android:layout_width="120dp"android:layout_height="120dp"android:background="#ffff00"android:layout_gravity="center"/><TextView android:layout_width="80dp"android:layout_height="80dp"android:background="#ff00ff"android:layout_gravity="center"/><TextView android:layout_width="40dp"android:layout_height="40dp"android:background="#ffffff"android:layout_gravity="center"/> </FrameLayout>運(yùn)行結(jié)果:
3. 表格布局TableLayout
示例:res\layout\activity_main.xml
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><!-- 表格布局寬高可以不用設(shè)置,TableRow的寬度只能是match_parent,高度只能是wrap_content。調(diào)正寬度可以通過(guò)權(quán)重解決。--><TableRow><TextView android:text="姓名:"/><EditText android:layout_weight="1"/></TableRow><TableRow><TextView android:text="年齡:"/><EditText android:layout_weight="1"/></TableRow> </TableLayout>*復(fù)制代碼* 運(yùn)行結(jié)果:
4. 絕對(duì)布局AbsoluteLayout
絕對(duì)布局是直接使用android:layout_x,android:layout_y定位控件的坐標(biāo),做不了屏幕適配,所以不常使用。某些沒(méi)有必要做屏幕適配的開(kāi)發(fā)可以用絕對(duì)布局,例如:電視屏幕固定,做機(jī)頂盒開(kāi)發(fā)。
示例:res\layout\activity_main.xml
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><Button android:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_x="109dp"android:layout_y="83dp"android:text="Button" /> </AbsoluteLayout>*復(fù)制代碼* 運(yùn)行結(jié)果:
4. LogCat
Console只能顯示W(wǎng)indows下運(yùn)行的平臺(tái)信息,例如:模擬器的運(yùn)行狀態(tài)(模擬器是運(yùn)行在Windows平臺(tái)上的程序)。但模擬器內(nèi)的程序運(yùn)行狀態(tài)就不能顯示在Console上了,因?yàn)檫@些程序不是運(yùn)行到Windows上,這些信息會(huì)在LogCat中顯示。
LogCat分為5個(gè)等級(jí),依次為:error(錯(cuò)誤)、warn(情報(bào))、info(信息)、debug(調(diào)試)、verbose(冗余)
示例:為L(zhǎng)ogCat添加過(guò)濾器,便于篩選信息
src/cn.itcast.logcat/MainActivity.java
package cn.itcast.logcat; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {String tag = "黑馬程序員";super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);System.out.println("云鶴,兒童節(jié)快樂(lè)");//tag表示標(biāo)簽,msg表示正文//下面這種寫(xiě)法是在日志需要長(zhǎng)期保留時(shí)使用。Log.v(tag, "云鶴就業(yè)薪資13000");Log.d(tag, "云鶴就業(yè)薪資13000");Log.i(tag, "云鶴就業(yè)薪資13000");Log.w(tag, "云鶴就業(yè)薪資13000");Log.e(tag, "云鶴就業(yè)薪資13000");} }運(yùn)行結(jié)果:
第一步:點(diǎn)擊加號(hào)
第二步:填入過(guò)濾器設(shè)置信息。
第三步:進(jìn)行過(guò)濾。
5. 在內(nèi)部存儲(chǔ)中讀寫(xiě)文件
Android內(nèi)存
- RAM:運(yùn)行內(nèi)存,相當(dāng)于電腦內(nèi)存。關(guān)機(jī),數(shù)據(jù)就會(huì)丟失。
- ROM:內(nèi)部存儲(chǔ)空間,Android系統(tǒng)必須的存儲(chǔ)空間,持久化保持?jǐn)?shù)據(jù),相當(dāng)于電腦的硬盤。
- SD卡/USB存儲(chǔ)器(內(nèi)置在手機(jī)內(nèi)):外部存儲(chǔ)空間,對(duì)于Android系統(tǒng)是可有可無(wú)的,相當(dāng)于移動(dòng)硬盤。
- 內(nèi)部存儲(chǔ)路徑:data/data/包名文件夾/,每個(gè)包名文件夾都是一個(gè)應(yīng)用的專屬空間。
示例:res\layout\activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" android:orientation="vertical"><EditText android:id="@+id/et_name"android:layout_width="match_parent"android:layout_height="wrap_content"/><!-- android:inputType="textPassword"表示輸入的是密碼,顯示時(shí)用密文代替 --><EditText android:id="@+id/et_pass"android:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="textPassword"/><RelativeLayout android:layout_width="match_parent"android:layout_height="wrap_content"><CheckBox android:id="@+id/cb"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="記住賬號(hào)密碼"android:layout_centerVertical="true"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="登陸"android:onClick="login"android:layout_alignParentRight="true"/></RelativeLayout> </LinearLayout>src/cn.itcast.rwinrom/MainActivity.java
package cn.itcast.rwinrom; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends Activity {private EditText et_name;private EditText et_pass;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_name = (EditText) findViewById(R.id.et_name);et_pass = (EditText) findViewById(R.id.et_pass);readAccount();}public void login(View v){//獲取用戶輸入的數(shù)據(jù)String name = et_name.getText().toString();String pass = et_pass.getText().toString();CheckBox cb = (CheckBox) findViewById(R.id.cb);if(cb.isChecked()){File file = new File("data/data/cn.itcast.rwinrom/info.txt");try{FileOutputStream fos = new FileOutputStream(file);fos.write((name + "##" + pass).getBytes());fos.close();}catch(Exception e){e.printStackTrace();}}//彈出吐司對(duì)話框//Activity是Context的子類//Toast.LENGTH_LONG表示顯示5秒//Toast.LENGTH_SHORT表示顯示3秒Toast.makeText(this, "登陸成功", Toast.LENGTH_LONG).show();}public void readAccount(){File file = new File("data/data/cn.itcast.rwinrom/info.txt");if(file.exists()){try{FileInputStream fis = new FileInputStream(file);//把字節(jié)流轉(zhuǎn)換成字符流BufferedReader br = new BufferedReader(new InputStreamReader(fis));String text = br.readLine();String[] s = text.split("##");et_name.setText(s[0]);et_pass.setText(s[1]);fis.close();}catch(Exception e){e.printStackTrace();}}} }運(yùn)行結(jié)果:
1、在模擬器上運(yùn)行應(yīng)用程序,輸入用戶名、密碼,勾上記住賬號(hào)密碼,點(diǎn)擊登陸。可以看到彈出吐司,登陸成功。
2、在Android設(shè)備文件目錄下,可以看到成功生成info.txt文件,點(diǎn)擊右上角的“pull a file from the device”按鈕,將info.txt提取出來(lái),保存到桌面。
3、打開(kāi)info.txt文件,可以看到成功存入數(shù)據(jù)。
4、重新運(yùn)行應(yīng)用程序,可以看到讀取數(shù)據(jù)成功,用戶名、密碼成功顯示。
PS:
1、點(diǎn)擊返回鍵,會(huì)摧毀當(dāng)前Activity,重新點(diǎn)擊應(yīng)用圖標(biāo),會(huì)重新創(chuàng)建Activity。
2、點(diǎn)擊HOME鍵,只會(huì)將Activity放到后臺(tái)去,重新點(diǎn)擊圖標(biāo),只是重新提取出來(lái)。
所以,上面的應(yīng)用程序,即使是第一次運(yùn)行,輸入用戶名、密碼,并且不勾選“記住賬戶密碼”。如果此時(shí)點(diǎn)擊HOME鍵,Activity消失。然后,再點(diǎn)擊應(yīng)用程序圖標(biāo),竟然可以看到Activity顯示出了用戶名、密碼!然而,這根本不是回顯,Activity只是暫時(shí)放到后臺(tái),然后重新提取出來(lái)罷了。
3、在內(nèi)部存儲(chǔ)空間中讀寫(xiě)不需要任何權(quán)限!
5.1 使用API獲取內(nèi)部存儲(chǔ)空間的路徑
如果將上面應(yīng)用程序的MainActivity類中的代碼進(jìn)行如下修改,可以看到后臺(tái)報(bào)警告。原因是不能訪問(wèn)其他應(yīng)用程序的專屬空間,只能訪問(wèn)自己的。
為了防止內(nèi)部存儲(chǔ)空間不小心寫(xiě)錯(cuò),API提供了獲取內(nèi)部存儲(chǔ)空間路徑的方法。修改后,代碼如下:
運(yùn)行結(jié)果,如下:
getFilesDir方法所在的類為上下文包裝類,ContextWrapper。
并且,Activity就是ContextWrapper的子類。
所謂的上下文就是一個(gè)應(yīng)用環(huán)境全局信息的接口,也就是說(shuō),通過(guò)上下文的API可以拿到應(yīng)用環(huán)境的全局信息,例如:包名、版本號(hào)、內(nèi)部存儲(chǔ)等信息。
Toast.makeText(this,”登陸成功”,0).show();語(yǔ)句中的this就是上下文,表示吐司需要顯示在哪個(gè)上下文中。
Button bt = new Button(this);語(yǔ)句中的this也是上下文,表示該組件創(chuàng)建出來(lái)之后,顯示在哪個(gè)上下文中。
谷歌的API還提供了另一個(gè)方法獲取內(nèi)部存儲(chǔ)空間路徑:getCacheDir(),它返回的路徑為data/data/cn.itcast.rwinrom/cache,得到的是緩存路徑,也就是cache文件夾路徑。修改后,代碼如下:
運(yùn)行結(jié)果,如下:
區(qū)別:
- getFilesDir方法返回的路徑中的files文件夾是持久化保存數(shù)據(jù)的。
- getCacheDir方法返回的路徑中的Cache文件夾是保存緩存數(shù)據(jù)的。當(dāng)設(shè)備內(nèi)存可用存儲(chǔ)空間比較少時(shí),Cache中的文件可能會(huì)被系統(tǒng)刪除。
6. 在外部存儲(chǔ)中讀寫(xiě)文件
SD卡路徑為storage/sdcard(4.3版本),之所以還存在根目錄sdcard(2.3版本之前)及mnt/sdcard(2.3版本~4.3版本),是因?yàn)樵缙诎姹镜膕d卡路徑正是在根目錄,后期移到了mnt/sdcard,為了與低版本兼容,所以現(xiàn)在他們還存在,其實(shí)只是快捷方式而已,指向的路徑依然是storage/sdcard。
往SD卡中寫(xiě)數(shù)據(jù)需要權(quán)限。而從SD卡中讀取數(shù)據(jù)在4.0版本以前是不需要權(quán)限,后來(lái)谷歌在Android系統(tǒng)中添加了保護(hù)SD卡的選項(xiàng)(如下圖)。如果勾選了,那么在真機(jī)上是有效的(也就是說(shuō),模擬器上是無(wú)效的)。不過(guò),一般情況下,不勾選。因?yàn)?#xff0c;很多應(yīng)用程序并沒(méi)有申請(qǐng)讀取SD卡的權(quán)限,一旦勾上,很多應(yīng)用程序?qū)o(wú)法讀取SD卡。因此,為了向下兼容,一般不勾。
示例:將上面“在內(nèi)部存儲(chǔ)中讀取文件”中示例的MainActivity類中代碼做一下修改,如下。
為讀寫(xiě)SD卡添加權(quán)限(讀SD卡權(quán)限可加可不加):
運(yùn)行結(jié)果:
6.1 檢測(cè)SD卡狀態(tài)
很多手機(jī)廠商都修改了SD卡路徑,因此,很多手機(jī)SD卡的路徑不是storage/sdcard。但是,sdcard的快捷方式基本上都是存在的,并且指向真實(shí)的SD卡路徑。因此,訪問(wèn)SD卡路徑,可以通過(guò)獲取SD卡快捷方式的方法。當(dāng)然,也可以調(diào)用API中提供的相應(yīng)方法獲取SD卡路徑:Environment.getExternalStorageDirectory()
外部存儲(chǔ)空間對(duì)于手機(jī)來(lái)說(shuō)并不一定是必須的。所以,在使用前,一定要做確認(rèn)手機(jī)的SD卡是否存在。可以通過(guò)Environment.getExternalStorageState()確定SD卡的狀態(tài),此方法的常見(jiàn)返回值說(shuō)明如下:
- MEDIA_REMOVED:sd卡被拔出
- MEDIA_UNMOUNTED:sd卡未掛載(4.0版本以前,手機(jī)可以通過(guò)點(diǎn)擊settings–>Storage–>Storage settings–>Unmounted SD card,使SD卡未掛載)
- MEDIA_- CHECKING:sd卡正在準(zhǔn)備
- MEDIA_MOUNTED:sd卡已掛載,當(dāng)前可用
- MEDIA_READ_ONLY:sd卡掛載可用,但是只讀
示例:將上面“在內(nèi)部存儲(chǔ)中讀取文件”中示例的MainActivity類中代碼做一下修改,如下
運(yùn)行結(jié)果:由于在4.0版本之前才有手動(dòng)使SD卡未掛載的功能,這里使用2.3.3版本測(cè)試。首先,Unmounted SD card,觀察效果,可以看到提示:sd不可用。
然后,mounted SD card,觀察效果,成功保存用戶名、密碼信息。
當(dāng)有多個(gè)模擬器運(yùn)行時(shí),想要觀察某一個(gè)模擬器的文件目錄,只需要在Devices選項(xiàng)卡中點(diǎn)擊那個(gè)模擬器,即可在File Explorer選項(xiàng)卡中看到那個(gè)模擬器的文件目錄。
6.2 獲取SD卡剩余容量
當(dāng)用戶做下載等操作時(shí),SD卡的空間可能不足,所以需要提前獲取SD卡剩余容量,給予用戶提示信息。在Android系統(tǒng)中,可以查看SD卡剩余容量,點(diǎn)擊Setting–>Storage
sdk文件夾中的sources文件夾中的源碼是Android jar包的源碼,Android系統(tǒng)源碼則不同,一定要區(qū)分開(kāi)。如下圖。
其中,packages/apps路徑為Android系統(tǒng)級(jí)應(yīng)用程序所在的目錄,可以看到settings應(yīng)用程序。
7. 查看settings應(yīng)用程序的源碼
7.1 導(dǎo)入settings應(yīng)用程序到eclipse中
點(diǎn)擊File–>New–>Other….
點(diǎn)擊Android下的Android Project from Existing Code–>Next
點(diǎn)擊Root Directory右側(cè)的Browse…按鈕,找到settings應(yīng)用程序所在的目錄,點(diǎn)擊確定
下圖中的tests為測(cè)試settings的應(yīng)用程序,不勾
導(dǎo)入成功
之所以會(huì)報(bào)錯(cuò),是因?yàn)槠胀☉?yīng)用開(kāi)發(fā)是無(wú)法訪問(wèn)系統(tǒng)級(jí)API的(settings工程導(dǎo)入eclipse就成為了一個(gè)普通應(yīng)用開(kāi)發(fā)項(xiàng)目)
7.2 查找實(shí)現(xiàn)查看SD卡剩余空間的源碼
通過(guò)搜索關(guān)鍵字“Available space”開(kāi)始查找
通過(guò)eclipse的“File Search”在整個(gè)工作空間中搜索“Available space”
查找到以后,雙擊
再搜索“memory_available”
再搜索“memory_sd_avail”
再在本文件內(nèi)搜索“MEMORY_SD_AVAIL”
再在本文件內(nèi)搜索“mSdAvail”,可以看到,已經(jīng)查找到了該段代碼
7.3 解析源碼
所有存儲(chǔ)設(shè)備都會(huì)被劃分成若干個(gè)區(qū)塊,存儲(chǔ)設(shè)備的總?cè)萘?= 每個(gè)區(qū)塊大小 * 區(qū)塊總數(shù)量
其中的formatSize函數(shù)實(shí)際上就是將得出的字節(jié)數(shù),轉(zhuǎn)換成MB、GB、TB及PB顯示給用戶
示例:我們自己寫(xiě)程序獲取SD卡剩余容量
res\layout\activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><TextView android:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world" /> </RelativeLayout>src/cn.itcast.getsdavail/MainActivity.java
package cn.itcast.getsdavail; import java.io.File; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.StatFs; import android.app.Activity; import android.text.format.Formatter; import android.view.Menu; import android.widget.TextView; public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);File path = Environment.getExternalStorageDirectory();StatFs stat = new StatFs(path.getPath());long blockSize;long availableBlocks;//下面的很多方法已經(jīng)過(guò)時(shí)了,因?yàn)間etBlockSize等方法的返回值都是int類型,如果設(shè)備較大,返回的blockSize數(shù)值可能超過(guò)int類型的范圍,導(dǎo)致溢出。//改為使用最新的getBlockSizeLong等方法返回為long類型數(shù)據(jù)即可。由于,只有4.3以上版本的API才支持這些方法。因此,最好做一下判斷。運(yùn)行結(jié)果:
8. 文件訪問(wèn)權(quán)限
Android的文件訪問(wèn)權(quán)限是從Linux繼承來(lái)的
drwxrwxrwx:
第一個(gè)字母:如果是d,表示文件夾;如果是-,表示文件;如果是l,表示快捷方式。
三組rwx(r(read),w(write),x(exeute,執(zhí)行))表示三種不同用戶的權(quán)限。
在Android中,每個(gè)應(yīng)用,都是一個(gè)獨(dú)立的用戶。也就是說(shuō),創(chuàng)建一個(gè)應(yīng)用,就是創(chuàng)建了一個(gè)新的用戶。刪除一個(gè)應(yīng)用,就是刪除了一個(gè)用戶。
第一組rwx:描述文件擁有者(owner)對(duì)文件的權(quán)限。例如,上圖中的data/cn.itcast.rwinrom/cache/info.txt文件的創(chuàng)建者就是擁有者,也就是cn.itcast.rwinrom應(yīng)用程序。
第二組rwx:描述與文件擁有者同一用戶組(grouper)的用戶對(duì)文件的權(quán)限。默認(rèn)情況,各個(gè)應(yīng)用程序彼此是獨(dú)立的用戶。可以手動(dòng)設(shè)置同組用戶,不過(guò)只有系統(tǒng)應(yīng)用為了方便才會(huì)設(shè)置同組用戶,我們不用管。
第三組rwx:描述其他用戶(other)對(duì)文件的權(quán)限。其他應(yīng)用程序就可以稱為某一個(gè)應(yīng)用程序的其他用戶。
實(shí)驗(yàn):其他應(yīng)用程序讀取當(dāng)前應(yīng)用程序的文件。
res\layout\activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" android:orientation="vertical"><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="click1"android:text="按鈕一" /><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="click2"android:text="按鈕二" /> </LinearLayout>src/cn.itcast.permission/MainActivity.java
package cn.itcast.permission; import java.io.FileNotFoundException; import java.io.FileOutputStream; import android.app.Activity; import android.os.Bundle; import android.view.View; public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click1(View v){//Android中提供的openFileOutput方法可以直接獲取FileOutputStream,文件會(huì)被寫(xiě)在內(nèi)部文件空間中(data/data/報(bào)名文件夾/files/)try {//MODE_PRIVATE表示擁有者和同組用戶可以讀寫(xiě),其他用戶無(wú)法訪問(wèn)FileOutputStream fos = openFileOutput("info1.txt", MODE_PRIVATE);fos.write("haha".getBytes());} catch (Exception e) {e.printStackTrace();}}public void click2(View v){try {//MODE_WORLD_READABLE表示任何用戶都對(duì)其可讀,MODE_WORLD_WRITEABLE表示任何用戶都對(duì)其可寫(xiě)FileOutputStream fos = openFileOutput("info2.txt", MODE_WORLD_READABLE|MODE_WORLD_WRITEABLE);fos.write("hehe,你來(lái)讀我啊".getBytes());} catch (Exception e) {e.printStackTrace();} } }創(chuàng)建新的名為“其他用戶”的應(yīng)用程序,代碼如下:
res\layout\activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context=".MainActivity" ><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="讀取" android:onClick="click"/> </RelativeLayout>src/cn.itcast.other/MainActivity.java
package cn.itcast.other; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void click(View v){File file = new File("data/data/cn.itcast.permission/files","info2.txt");try {FileInputStream fis = new FileInputStream(file);BufferedReader br = new BufferedReader(new InputStreamReader(fis));Toast.makeText(this,br.readLine(),Toast.LENGTH_LONG).show();} catch (Exception e) {e.printStackTrace();}} }運(yùn)行結(jié)果:
點(diǎn)擊按鈕一、按鈕二,生成文件info1.txt、info2.txt
可以看到info1.txt為擁有者和同一用戶組具備讀寫(xiě)權(quán)限,info2.txt則為任何用戶都具備讀寫(xiě)權(quán)限。
運(yùn)行“其他用戶”應(yīng)用程序,點(diǎn)擊按鈕,可以看到讀取info2.txt文件成功。
9. SharedPreferences
在真實(shí)開(kāi)發(fā)中,類似于賬號(hào)及密碼保存功能等持久化保存比較零散、簡(jiǎn)單數(shù)據(jù)的情況使用SharedPerferences比較方便,它是以鍵值對(duì)的方式將數(shù)據(jù)存儲(chǔ)進(jìn)xml文件中。
示例:修改保存用戶登錄名,密碼的案例,用SharedPreferences保存數(shù)據(jù)的方式實(shí)現(xiàn)。
src/cn.itcast.sharedpreference/MainActivity.java
運(yùn)行結(jié)果:
可以看到,數(shù)據(jù)成功保存到xml文件中。
回顯成功。
10. 生成xml文件
雖然SharedPreferences可以實(shí)現(xiàn)保存數(shù)據(jù)到xml中,但是,對(duì)于類似于用戶保存短信等Android應(yīng)用程序來(lái)說(shuō)還是不行的。例如,保存短信功能,需要保存內(nèi)容、發(fā)送時(shí)間、接收人號(hào)碼、短信類型(發(fā)送、接收)等等多種類型數(shù)據(jù),尤其是數(shù)據(jù)組織結(jié)構(gòu)比較復(fù)雜時(shí),使用SharedPreferences會(huì)相當(dāng)?shù)穆闊?/p>
示例:通過(guò)xml方式保存短信。
res\layout\activity_main.xml
src/cn.itcast.createxml/MainActivity.java
package cn.itcast.createxml; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.view.View; public class MainActivity extends Activity {List<Sms> smsList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);smsList = new ArrayList<Sms>();for(int i = 0; i < 10; i++){Sms sms = new Sms("云鶴" + i + "號(hào)","138" + i + i,System.currentTimeMillis(),1);smsList.add(sms);}}public void click(View v){StringBuffer sb = new StringBuffer();sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");sb.append("<smss>");for(Sms sms : smsList){sb.append("<sms>");sb.append("<body>");sb.append(sms.getBody());sb.append("</body>");sb.append("<address>");sb.append(sms.getAddress());sb.append("</address>");sb.append("<date>");sb.append(sms.getDate());sb.append("</date>");sb.append("<type>");sb.append(sms.getType());sb.append("</type>");sb.append("</sms>");}//備份數(shù)據(jù)的應(yīng)用一般都存在外部存儲(chǔ)空間中。因?yàn)?#xff0c;一旦應(yīng)用程序被刪,內(nèi)部存儲(chǔ)空間內(nèi)的該應(yīng)用程序就會(huì)被清除,而外部存儲(chǔ)空間不會(huì)被清掉。File file = new File("sdcard/sms.xml");try {FileOutputStream fos = new FileOutputStream(file);fos.write(sb.toString().getBytes());fos.close();} catch (Exception e) {e.printStackTrace();}} }運(yùn)行結(jié)果:
點(diǎn)擊“生成xml文件”按鈕,可以看到成功生成了sms.xml文件。
11. xml序列化器
上面拼接字符串的方法過(guò)于麻煩,Android中有一個(gè)xml序列化器可以幫助我們解決這個(gè)問(wèn)題。
示例:將上面示例中拼接字符串的方式修改為通過(guò)xml序列化器生成xml文件。
src/cn.itcast.createxml/MainActivity.java
package cn.itcast.createxml; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlSerializer; import android.app.Activity; import android.os.Bundle; import android.util.Xml; import android.view.View; public class MainActivity extends Activity {List<Sms> smsList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);smsList = new ArrayList<Sms>();for(int i = 0; i < 10; i++){Sms sms = new Sms("云鶴" + i + "號(hào)","138" + i + i,System.currentTimeMillis(),1);smsList.add(sms);}}public void click(View v){//獲取xml序列化器XmlSerializer xs = Xml.newSerializer();try{//初始化,指定生成的xml文件路徑和文件名File file = new File("sdcard/sms2.xml");FileOutputStream fos = new FileOutputStream(file);//編碼:xml文件使用什么編碼生成xs.setOutput(fos,"utf-8");//開(kāi)始生成xml文件//生成頭結(jié)點(diǎn)//兩個(gè)參數(shù)分別用來(lái)定義XML文件的頭部<?xml version="1.0" encoding="utf-8" standalone="yes"?>中encoding和standalone的值xs.startDocument("utf-8", true);//開(kāi)始節(jié)點(diǎn),第一個(gè)參數(shù)為名稱空間,用不到,設(shè)置為null。xs.startTag(null, "smss");for(Sms sms : smsList){xs.startTag(null, "sms");xs.startTag(null, "body");xs.text(sms.getBody());xs.endTag(null, "body");xs.startTag(null, "address");xs.text(sms.getAddress());xs.endTag(null, "address");xs.startTag(null, "date");xs.text(sms.getDate() + "");xs.endTag(null, "date");xs.startTag(null, "type");xs.text(sms.getType() + "");xs.endTag(null, "type");xs.endTag(null, "sms");}//結(jié)束節(jié)點(diǎn)xs.endTag(null, "smss");//告知序列化器xml文件生成完畢xs.endDocument();}catch(Exception e){e.printStackTrace();}} }運(yùn)行結(jié)果:可以看到,生成xml文件成功。
PS:使用xml序列化器生成xml文件還有一個(gè)好處,那就是會(huì)自動(dòng)對(duì)特殊字符進(jìn)行轉(zhuǎn)義。
示例:對(duì)上面示例中加上如下代碼,其中“<”及“>”都是特殊字符
運(yùn)行結(jié)果:可以看到成功生成xml文件,但是其中的特殊字符已經(jīng)轉(zhuǎn)義了。
下一章 Android應(yīng)用開(kāi)發(fā):數(shù)據(jù)存儲(chǔ)和界面展現(xiàn)-2
常見(jiàn)布局
相對(duì)布局
RelativeLayout
- 組件默認(rèn)左對(duì)齊、頂部對(duì)齊
- 設(shè)置組件在指定組件的右邊
- 設(shè)置在指定組件的下邊
- 設(shè)置右對(duì)齊父元素
- 設(shè)置與指定組件右對(duì)齊
線性布局
LinearLayout
- 指定各個(gè)節(jié)點(diǎn)的排列方向
- 設(shè)置右對(duì)齊
- 當(dāng)豎直布局時(shí),只能左右對(duì)齊和水平居中,頂部底部對(duì)齊豎直居中無(wú)效
- 當(dāng)水平布局時(shí),只能頂部底部對(duì)齊和豎直居中
- 使用match_parent時(shí)注意不要把其他組件頂出去
- 線性布局非常重要的一個(gè)屬性:權(quán)重
- 權(quán)重設(shè)置的是按比例分配剩余的空間
幀布局
FrameLayout
- 默認(rèn)組件都是左對(duì)齊和頂部對(duì)齊,每個(gè)組件相當(dāng)于一個(gè)div
- 可以更改對(duì)齊方式
- 不能相對(duì)于其他組件布局
表格布局
TableLayout
- 每個(gè)節(jié)點(diǎn)是一行,它的每個(gè)子節(jié)點(diǎn)是一列
表格布局中的節(jié)點(diǎn)可以不設(shè)置寬高,因?yàn)樵O(shè)置了也無(wú)效
- 根節(jié)點(diǎn)的子節(jié)點(diǎn)寬為匹配父元素,高為包裹內(nèi)容
- 節(jié)點(diǎn)的子節(jié)點(diǎn)寬為包裹內(nèi)容,高為包裹內(nèi)容
- 以上默認(rèn)屬性無(wú)法修改
根節(jié)點(diǎn)中可以設(shè)置以下屬性,表示讓第1列拉伸填滿屏幕寬度的剩余空間
絕對(duì)布局
AbsoluteLayout
- 直接指定組件的x、y坐標(biāo)
logcat
- 日志信息總共分為5個(gè)等級(jí)
- verbose 冗余,最低等級(jí)
- debug 調(diào)試信息
- info 正常信息
- warn 警告
- error 錯(cuò)誤
- 定義過(guò)濾器方便查看
- System.out.print輸出的日志級(jí)別是info,tag是System.out
- Android提供的日志輸出api,打印出來(lái)的是error級(jí)別的信息
文件讀寫(xiě)操作
- Ram內(nèi)存:運(yùn)行內(nèi)存,相當(dāng)于電腦的內(nèi)存
- Rom內(nèi)存:內(nèi)部存儲(chǔ)空間,相當(dāng)于電腦的硬盤
- sd卡:外部存儲(chǔ)空間,相當(dāng)于電腦的移動(dòng)硬盤
在內(nèi)部存儲(chǔ)空間中讀寫(xiě)文件
小案例:用戶輸入賬號(hào)密碼,勾選“記住賬號(hào)密碼”,點(diǎn)擊登錄按鈕,登錄的同時(shí)持久化保存賬號(hào)和密碼
1. 定義布局
2. 完成按鈕的點(diǎn)擊事件
- 彈土司提示用戶登錄成功
3. 拿到用戶輸入的數(shù)據(jù)
- 判斷用戶是否勾選保存賬號(hào)密碼
4. 開(kāi)啟io流把文件寫(xiě)入內(nèi)部存儲(chǔ)
- 直接開(kāi)啟文件輸出流寫(xiě)數(shù)據(jù)
- 讀取數(shù)據(jù)前先檢測(cè)文件是否存在
- 讀取保存的數(shù)據(jù),也是直接開(kāi)文件輸入流讀取
- 讀取到數(shù)據(jù)之后,回顯至輸入框
- 應(yīng)用只能在自己的包名目錄下創(chuàng)建文件,不能到別人家去創(chuàng)建
直接復(fù)制項(xiàng)目
- 需要改動(dòng)的地方:
- 項(xiàng)目名字
- 應(yīng)用包名
- R文件重新導(dǎo)包
使用路徑api讀寫(xiě)文件
- getFilesDir()得到的file對(duì)象的路徑是data/data/com.itheima.rwinrom2/files
- 存放在這個(gè)路徑下的文件,只要你不刪,它就一直在
getCacheDir()得到的file對(duì)象的路徑是data/data/com.itheima.rwinrom2/cache
- 存放在這個(gè)路徑下的文件,當(dāng)內(nèi)存不足時(shí),有可能被刪除
系統(tǒng)管理應(yīng)用界面的清除緩存,會(huì)清除cache文件夾下的東西,清除數(shù)據(jù),會(huì)清除整個(gè)包名目錄下的東西
- getCacheDir():獲取緩存文件夾
在外部存儲(chǔ)讀寫(xiě)數(shù)據(jù)
sd卡的路徑
- sdcard:2.3之前的sd卡路徑
- mnt/sdcard:4.3之前的sd卡路徑
storage/sdcard:4.3之后的sd卡路徑
最簡(jiǎn)單的打開(kāi)sd卡的方式
- 寫(xiě)sd卡需要權(quán)限
- 讀sd卡,在4.0之前不需要權(quán)限,4.0之后可以設(shè)置為需要
- 使用api獲得sd卡的真實(shí)路徑,部分手機(jī)品牌會(huì)更改sd卡的路徑
- 判斷sd卡是否準(zhǔn)備就緒
查看源代碼查找獲取sd卡剩余容量的代碼
- 導(dǎo)入Settings項(xiàng)目
- 查找“可用空間”得到
- 查找”memory_available”,得到
- 查找”memory_sd_avail”,得到
- 存儲(chǔ)設(shè)備會(huì)被分為若干個(gè)區(qū)塊,每個(gè)區(qū)塊有固定的大小
- 區(qū)塊大小 * 區(qū)塊數(shù)量 等于 存儲(chǔ)設(shè)備的總大小
Linux文件的訪問(wèn)權(quán)限
- 在Android中,每一個(gè)應(yīng)用是一個(gè)獨(dú)立的用戶
- drwxrwxrwx
- 第1位:d表示文件夾,-表示文件
- 第2-4位:rwx,表示這個(gè)文件的擁有者用戶(owner)對(duì)該文件的權(quán)限
- r:讀
- w:寫(xiě)
- x:執(zhí)行
- 第5-7位:rwx,表示跟文件擁有者用戶同組的用戶(grouper)對(duì)該文件的權(quán)限
- 第8-10位:rwx,表示其他用戶組的用戶(other)對(duì)該文件的權(quán)限
openFileOutput的四種模式
- MODE_PRIVATE:-rw-rw—-
- MODE_APPEND:-rw-rw—-
- MODE_WORLD_WRITEABLE:-rw-rw–w-
- MODE_WORLD_READABLE:-rw-rw-r–
SharedPreference
用SharedPreference存儲(chǔ)賬號(hào)密碼
- 往SharedPreference里寫(xiě)數(shù)據(jù)
- 從SharedPreference里取數(shù)據(jù)
生成XML文件備份短信
- 創(chuàng)建幾個(gè)虛擬的短信對(duì)象,存在list中
- 備份數(shù)據(jù)通常都是備份至sd卡
使用StringBuffer拼接字符串
- 把整個(gè)xml文件所有節(jié)點(diǎn)append到sb對(duì)象里
- 把sb寫(xiě)到輸出流中
使用XMl序列化器生成xml文件
- 得到xml序列化器對(duì)象
- 給序列化器設(shè)置輸出流
- 開(kāi)始生成xml文件
pull解析xml文件
- 先自己寫(xiě)一個(gè)xml文件,存一些天氣信息
拿到xml文件
InputStream is = getClassLoader().getResourceAsStream("weather.xml");拿到pull解析器
XmlPullParser xp = Xml.newPullParser();開(kāi)始解析
- 拿到指針?biāo)诋?dāng)前節(jié)點(diǎn)的事件類型
int type = xp.getEventType();
事件類型主要有五種
- START_DOCUMENT:xml頭的事件類型
- END_DOCUMENT:xml尾的事件類型
- START_TAG:開(kāi)始節(jié)點(diǎn)的事件類型
- END_TAG:結(jié)束節(jié)點(diǎn)的事件類型
- TEXT:文本節(jié)點(diǎn)的事件類型
如果獲取到的事件類型不是END_DOCUMENT,就說(shuō)明解析還沒(méi)有完成,如果是,解析完成,while循環(huán)結(jié)束
while(type != XmlPullParser.END_DOCUMENT)- 當(dāng)我們解析到不同節(jié)點(diǎn)時(shí),需要進(jìn)行不同的操作,所以判斷一下當(dāng)前節(jié)點(diǎn)的name
- 當(dāng)解析到weather的開(kāi)始節(jié)點(diǎn)時(shí),new出list
- 當(dāng)解析到city的開(kāi)始節(jié)點(diǎn)時(shí),創(chuàng)建city對(duì)象,創(chuàng)建對(duì)象是為了更方便的保存即將解析到的文本
- 當(dāng)解析到name開(kāi)始節(jié)點(diǎn)時(shí),獲取下一個(gè)節(jié)點(diǎn)的文本內(nèi)容,temp、pm也是一樣
- 當(dāng)解析到city的結(jié)束節(jié)點(diǎn)時(shí),說(shuō)明city的三個(gè)子節(jié)點(diǎn)已經(jīng)全部解析完了,把city對(duì)象添加至list
常見(jiàn)布局
線性布局
- 有一個(gè)布局方向,水平或者豎直
- 在豎直布局下,左對(duì)齊、右對(duì)齊,水平居中生效
- 在水平布局下,頂部對(duì)齊、底部對(duì)齊、豎直居中生效
- 權(quán)重:按比例分配屏幕的剩余寬度或者高度
相對(duì)布局
- 組件默認(rèn)位置都是左上角,組件之間可以重疊
- 可以相對(duì)于父元素上下左右對(duì)齊,相對(duì)于父元素,水平居中、豎直居中、水平豎直同時(shí)居中
- 可以相對(duì)于其他組件上下左右對(duì)齊
- 可以布局于其他組件的上方、下方、左邊、右邊
幀布局
- 組件默認(rèn)位置都是左上角,組件之間可以重疊
- 可以設(shè)置上下左右對(duì)齊,水平豎直居中,設(shè)置方式與線性布局一樣
表格布局
- 每有一個(gè)TableRow子節(jié)點(diǎn)表示一行,該子節(jié)點(diǎn)的每一個(gè)子節(jié)點(diǎn)都表示一列
- TableLayout的一級(jí)子節(jié)點(diǎn)默認(rèn)寬都是匹配父元素
- TableRow的子節(jié)點(diǎn)默認(rèn)寬高都是包裹內(nèi)容
Logcat
等級(jí)
- verbose:冗余,最低等級(jí)
- debug:調(diào)試
- info:正常等級(jí)的信息
- warn:警告
- error:錯(cuò)誤
Android的存儲(chǔ)
內(nèi)部存儲(chǔ)空間
- RAM內(nèi)存:運(yùn)行內(nèi)存,相當(dāng)于電腦的內(nèi)存
- ROM內(nèi)存:存儲(chǔ)內(nèi)存,相當(dāng)于電腦的硬盤
外部存儲(chǔ)空間
SD卡:相當(dāng)于電腦的移動(dòng)硬盤
- 2.2之前,sd卡路徑:sdcard
- 4.3之前,sd卡路徑:mnt/sdcard
- 4.3開(kāi)始,sd卡路徑:storage/sdcard
所有存儲(chǔ)設(shè)備,都會(huì)被劃分成若干個(gè)區(qū)塊,每個(gè)區(qū)塊有固定的大小
- 存儲(chǔ)設(shè)備的總大小 = 區(qū)塊大小 * 區(qū)塊數(shù)量
文件訪問(wèn)權(quán)限
- 指的是誰(shuí)能訪問(wèn)這個(gè)文件
- 在Android中,每一個(gè)應(yīng)用,都是一個(gè)獨(dú)立的用戶
- 使用10個(gè)字母表示
- drwxrwxrwx
- 第一個(gè)字母:
- d:表示文件夾
- -:表示文件
- 第一組rwx:表示的是文件擁有者(owner)對(duì)文件的權(quán)限
- r:read,讀
- w:write
- x:execute
- 第二組rwx:表示的是跟文件擁有者屬于同一用戶組的用戶(grouper)對(duì)文件的權(quán)限
- 第三組rwx:表示的其他用戶(other)對(duì)文件的權(quán)限
SharedPreference
- 非常適合用來(lái)保存零散的簡(jiǎn)單的數(shù)據(jù)
測(cè)試
- 黑盒測(cè)試
- 測(cè)試邏輯業(yè)務(wù)
白盒測(cè)試
- 測(cè)試邏輯方法
根據(jù)測(cè)試粒度
- 方法測(cè)試:function test
- 單元測(cè)試:unit test
- 集成測(cè)試:integration test
- 系統(tǒng)測(cè)試:system test
根據(jù)測(cè)試暴力程度
- 冒煙測(cè)試:smoke test
- 壓力測(cè)試:pressure test
單元測(cè)試junit
- 定義一個(gè)類繼承AndroidTestCase,在類中定義方法,即可測(cè)試該方法
- 在指定指令集時(shí),targetPackage指定你要測(cè)試的應(yīng)用的包名
- 定義使用的類庫(kù)
- 斷言的作用,assertEquals(期待值,實(shí)際值),檢測(cè)運(yùn)行結(jié)果和預(yù)期是否一致
- 如果應(yīng)用出現(xiàn)異常,會(huì)拋給測(cè)試框架
SQLite數(shù)據(jù)庫(kù)
- 輕量級(jí)關(guān)系型數(shù)據(jù)庫(kù)
- 創(chuàng)建數(shù)據(jù)庫(kù)需要使用的api:SQLiteOpenHelper
- 必須定義一個(gè)構(gòu)造方法:
創(chuàng)建數(shù)據(jù)庫(kù)
//創(chuàng)建OpenHelper對(duì)象 MyOpenHelper oh = new MyOpenHelper(getContext(), "person.db", null, 1); //獲得數(shù)據(jù)庫(kù)對(duì)象,如果數(shù)據(jù)庫(kù)不存在,先創(chuàng)建數(shù)據(jù)庫(kù),后獲得,如果存在,則直接獲得 SQLiteDatabase db = oh.getWritableDatabase();- getWritableDatabase():打開(kāi)可讀寫(xiě)的數(shù)據(jù)庫(kù)
- getReadableDatabase():在磁盤空間不足時(shí)打開(kāi)只讀數(shù)據(jù)庫(kù),否則打開(kāi)可讀寫(xiě)數(shù)據(jù)庫(kù)
- 在創(chuàng)建數(shù)據(jù)庫(kù)時(shí)創(chuàng)建表
數(shù)據(jù)庫(kù)的增刪改查
SQL語(yǔ)句
- insert into person (name, phone, money) values (‘張三’, ‘159874611’, 2000);
- delete from person where name = ‘李四’ and _id = 4;
- update person set money = 6000 where name = ‘李四’;
- select name, phone from person where name = ‘張三’;
執(zhí)行SQL語(yǔ)句實(shí)現(xiàn)增刪改查
//插入 db.execSQL("insert into person (name, phone, money) values (?, ?, ?);", new Object[]{"張三", 15987461, 75000}); //查找 Cursor cs = db.rawQuery("select _id, name, money from person where name = ?;", new String[]{"張三"}); * 測(cè)試方法執(zhí)行前會(huì)調(diào)用此方法 protected void setUp() throws Exception {super.setUp();// 獲取虛擬上下文對(duì)象oh = new MyOpenHelper(getContext(), "people.db", null, 1); } //測(cè)試方法執(zhí)行完畢之后,此方法調(diào)用 @Override protected void tearDown() throws Exception {// TODO Auto-generated method stubsuper.tearDown();db.close(); }查詢
public void select(){Cursor cursor = db.rawQuery("select name, salary from person", null);while(cursor.moveToNext()){//通過(guò)列索引獲取列的值String name = cursor.getString(cursor.getColumnIndex("name"));String salary = cursor.getString(1);System.out.println(name + ";" + salary);} }使用api實(shí)現(xiàn)增刪改查
- 插入
- 刪除
- 修改
- 查詢
事務(wù)
- 保證多條SQL語(yǔ)句要么同時(shí)成功,要么同時(shí)失敗
- 最常見(jiàn)案例:銀行轉(zhuǎn)賬
- 事務(wù)api
把數(shù)據(jù)庫(kù)的數(shù)據(jù)顯示至屏幕
- 定義業(yè)務(wù)bean:Person.java
- 讀取數(shù)據(jù)庫(kù)的所有數(shù)據(jù)
- 把集合中的數(shù)據(jù)顯示至屏幕
- 分頁(yè)查詢
Cursor cs = db.query(“person”, null, null, null, null, null, null, “0, 10”);
ListView
- 就是用來(lái)顯示一行一行的條目的
- MVC結(jié)構(gòu)
- M:model模型層,要顯示的數(shù)據(jù) ————people集合
- V:view視圖層,用戶看到的界面 ————ListView
- c:control控制層,操作數(shù)據(jù)如何顯示 ————adapter對(duì)象
- 每一個(gè)條目都是一個(gè)View對(duì)象
- 點(diǎn)擊監(jiān)聽(tīng):lv.setOnItemClickListener();
BaseAdapter
必須實(shí)現(xiàn)的兩個(gè)方法
第一個(gè)
//系統(tǒng)調(diào)用此方法,用來(lái)獲知模型層有多少條數(shù)據(jù) @Override public int getCount() {return people.size(); }第二個(gè)
- 屏幕上能顯示多少個(gè)條目,getView方法就會(huì)被調(diào)用多少次,屏幕向下滑動(dòng)時(shí),getView會(huì)繼續(xù)被調(diào)用,創(chuàng)建更多的View對(duì)象顯示至屏幕
條目的緩存
- 當(dāng)條目劃出屏幕時(shí),系統(tǒng)會(huì)把該條目緩存至內(nèi)存,當(dāng)該條目再次進(jìn)入屏幕,系統(tǒng)在重新調(diào)用getView時(shí)會(huì)把緩存的條目作為convertView參數(shù)傳入,但是傳入的條目不一定是之前被緩存的該條目,即系統(tǒng)有可能在調(diào)用getView方法獲取第一個(gè)條目時(shí),傳入任意一個(gè)條目的緩存
布局填充
- View.inflate(context , resourceid , viewgroup)
- LayoutInflater.from()布局填充器
- LayoutInflater inflater2 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
- ViewGroup
ListView的優(yōu)化
public class MainActivity extends Activity {List<Person> personList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);personList = new ArrayList<Person>();//把數(shù)據(jù)庫(kù)的數(shù)據(jù)查詢出來(lái)MyOpenHelper oh = new MyOpenHelper(this);SQLiteDatabase db = oh.getWritableDatabase();Cursor cursor = db.query("person", null, null, null, null, null, null, null);while(cursor.moveToNext()){String _id = cursor.getString(0);String name = cursor.getString(1);String salary = cursor.getString(2);String phone = cursor.getString(3);Person p = new Person(_id, name, phone, salary);personList.add(p);}ListView lv = (ListView) findViewById(R.id.lv);lv.setAdapter(new MyAdapter());}class MyAdapter extends BaseAdapter{//系統(tǒng)調(diào)用,用來(lái)獲知集合中有多少條元素@Overridepublic int getCount() {return personList.size();}//由系統(tǒng)調(diào)用,獲取一個(gè)View對(duì)象,作為L(zhǎng)istView的條目//position:本次getView方法調(diào)用所返回的View對(duì)象,在listView中是處于第幾個(gè)條目,那么position的值就是多少@Overridepublic View getView(int position, View convertView, ViewGroup parent) {Person p = personList.get(position);// TextView tv = new TextView(MainActivity.this);System.out.println("getView調(diào)用:" + position + ";" + convertView); // tv.setText(p.toString()); // tv.setTextSize(18);View v = null;//判斷條目是否有緩存,ListView優(yōu)化if(convertView == null){//把布局文件填充成一個(gè)View對(duì)象v = View.inflate(MainActivity.this, R.layout.item_listview, null);}else{v = convertView;}//獲取布局填充器對(duì)象 // LayoutInflater inflater = LayoutInflater.from(MainActivity.this); // 使用布局填充器填充布局文件 // View v2 = inflater.inflate(R.layout.item_listview, null);// LayoutInflater inflater2 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); // View v3 = inflater2.inflate(R.layout.item_listview, null);//通過(guò)資源id查找組件,注意調(diào)用的是View對(duì)象的findViewByIdTextView tv_name = (TextView) v.findViewById(R.id.tv_name);tv_name.setText(p.getName());TextView tv_phone = (TextView) v.findViewById(R.id.tv_phone);tv_phone.setText(p.getPhone());TextView tv_salary = (TextView) v.findViewById(R.id.tv_salary);tv_salary.setText(p.getSalary());return v;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}} }ArrayAdapter、SimpleAdapter
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);String[] objects = new String[]{"小志","小志的兒子","萌萌"};ListView lv = (ListView) findViewById(R.id.lv); // lv.setAdapter(new ArrayAdapter<String>(this, R.layout.item_listview, R.id.tv_name, objects));//集合中每個(gè)元素都包含ListView條目需要的所有數(shù)據(jù),該案例中每個(gè)條目需要一個(gè)字符串和一個(gè)整型,所以使用一個(gè)map來(lái)封裝這兩種數(shù)據(jù)List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();Map<String, Object> map1 = new HashMap<String, Object>();map1.put("photo", R.drawable.photo1);map1.put("name", "小志的兒子");data.add(map1);Map<String, Object> map2 = new HashMap<String, Object>();map2.put("photo", R.drawable.photo2);map2.put("name", "小志");data.add(map2);Map<String, Object> map3 = new HashMap<String, Object>();map3.put("photo", R.drawable.photo3);map3.put("name", "趙帥哥");data.add(map3);lv.setAdapter(new SimpleAdapter(this, data, R.layout.item_listview,new String[]{"photo", "name"}, new int[]{R.id.iv_photo, R.id.tv_name}));} }- 圖片:R.drawable.name
- 控件:R.id.name
- 布局:R.layout.name
對(duì)話框
確定取消對(duì)話框
- 創(chuàng)建對(duì)話框構(gòu)建器對(duì)象,類似工廠模式
AlertDialog.Builder builder = new Builder(this);
- 設(shè)置標(biāo)題和正文
- 設(shè)置確定和取消按鈕
- 使用構(gòu)建器創(chuàng)建出對(duì)話框?qū)ο?/li>
單選對(duì)話框
AlertDialog.Builder builder = new Builder(this); builder.setTitle("選擇你的性別"); // 定義單選選項(xiàng) final String[] items = new String[]{"男", "女", "其他" }; //-1表示沒(méi)有默認(rèn)選擇 //點(diǎn)擊偵聽(tīng)的導(dǎo)包要注意別導(dǎo)錯(cuò) builder.setSingleChoiceItems(items, -1, new OnClickListener() {//which表示點(diǎn)擊的是哪一個(gè)選項(xiàng)@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(MainActivity.this, "您選擇了" + items[which], 0).show();//對(duì)話框消失dialog.dismiss();} });builder.show();多選對(duì)話框
AlertDialog.Builder builder = new Builder(this);builder.setTitle("請(qǐng)選擇你認(rèn)為最帥的人"); // 定義多選的選項(xiàng),因?yàn)榭梢远噙x,所以需要一個(gè)boolean數(shù)組來(lái)記錄哪些選項(xiàng)被選了final String[] items = new String[]{"趙帥哥","趙師哥","趙老師","侃哥" }; //true表示對(duì)應(yīng)位置的選項(xiàng)被選了 final boolean[] checkedItems = new boolean[]{true,false,false,false, }; builder.setMultiChoiceItems(items, checkedItems, new OnMultiChoiceClickListener() {//點(diǎn)擊某個(gè)選項(xiàng),如果該選項(xiàng)之前沒(méi)被選擇,那么此時(shí)isChecked的值為true@Overridepublic void onClick(DialogInterface dialog, int which, boolean isChecked) {checkedItems[which] = isChecked;} });builder.setPositiveButton("確定", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {StringBuffer sb = new StringBuffer();for(int i = 0;i < items.length; i++){sb.append(checkedItems[i] ? items[i] + " " : "");}Toast.makeText(MainActivity.this, sb.toString(), 0).show();} }); builder.show();常見(jiàn)布局
線性布局
- 有一個(gè)布局方向,水平或者豎直
- 在豎直布局下,左對(duì)齊、右對(duì)齊,水平居中生效
- 在水平布局下,頂部對(duì)齊、底部對(duì)齊、豎直居中生效
- 權(quán)重:按比例分配屏幕的剩余寬度或者高度
相對(duì)布局
- 組件默認(rèn)位置都是左上角,組件之間可以重疊
- 可以相對(duì)于父元素上下左右對(duì)齊,相對(duì)于父元素,水平居中、豎直居中、水平豎直同時(shí)居中
- 可以相對(duì)于其他組件上下左右對(duì)齊
- 可以布局于其他組件的上方、下方、左邊、右邊
幀布局
- 組件默認(rèn)位置都是左上角,組件之間可以重疊
- 可以設(shè)置上下左右對(duì)齊,水平豎直居中,設(shè)置方式與線性布局一樣
表格布局
- 每有一個(gè)TableRow子節(jié)點(diǎn)表示一行,該子節(jié)點(diǎn)的每一個(gè)子節(jié)點(diǎn)都表示一列
- TableLayout的一級(jí)子節(jié)點(diǎn)默認(rèn)寬都是匹配父元素
- TableRow的子節(jié)點(diǎn)默認(rèn)寬高都是包裹內(nèi)容
Logcat
等級(jí)
- verbose:冗余,最低等級(jí)
- debug:調(diào)試
- info:正常等級(jí)的信息
- warn:警告
- error:錯(cuò)誤
Android的存儲(chǔ)
內(nèi)部存儲(chǔ)空間
- RAM內(nèi)存:運(yùn)行內(nèi)存,相當(dāng)于電腦的內(nèi)存
- ROM內(nèi)存:存儲(chǔ)內(nèi)存,相當(dāng)于電腦的硬盤
外部存儲(chǔ)空間
SD卡:相當(dāng)于電腦的移動(dòng)硬盤
- 2.2之前,sd卡路徑:sdcard
- 4.3之前,sd卡路徑:mnt/sdcard
- 4.3開(kāi)始,sd卡路徑:storage/sdcard
所有存儲(chǔ)設(shè)備,都會(huì)被劃分成若干個(gè)區(qū)塊,每個(gè)區(qū)塊有固定的大小
- 存儲(chǔ)設(shè)備的總大小 = 區(qū)塊大小 * 區(qū)塊數(shù)量
文件訪問(wèn)權(quán)限
- 指的是誰(shuí)能訪問(wèn)這個(gè)文件
- 在Android中,每一個(gè)應(yīng)用,都是一個(gè)獨(dú)立的用戶
- 使用10個(gè)字母表示
- drwxrwxrwx
- 第一個(gè)字母:
- d:表示文件夾
- -:表示文件
- 第一組rwx:表示的是文件擁有者(owner)對(duì)文件的權(quán)限
- r:read,讀
- w:write
- x:execute
- 第二組rwx:表示的是跟文件擁有者屬于同一用戶組的用戶(grouper)對(duì)文件的權(quán)限
- 第三組rwx:表示的其他用戶(other)對(duì)文件的權(quán)限
SharedPreference
- 非常適合用來(lái)保存零散的簡(jiǎn)單的數(shù)據(jù)
案例1:SharedPreference
public class MainActivity extends Activity {private EditText et_name;private EditText et_pass;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_name = (EditText) findViewById(R.id.et_name);et_pass = (EditText) findViewById(R.id.et_pass);readAccount();}public void readAccount(){SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);String name = sp.getString("name", "");String pass = sp.getString("pass", "");et_name.setText(name);et_pass.setText(pass);}public void login(View v){String name = et_name.getText().toString();String pass = et_pass.getText().toString();CheckBox cb = (CheckBox) findViewById(R.id.cb);//判斷選框是否被勾選if(cb.isChecked()){//使用sharedPreference來(lái)保存用戶名和密碼//路徑在data/data/com.itheima.sharedpreference/share_SharedPreferences sp = getSharedPreferences("info", MODE_PRIVATE);//拿到sp的編輯器Editor ed = sp.edit();ed.putString("name", name);ed.putString("pass", pass);//提交ed.commit();}//創(chuàng)建并顯示吐司對(duì)話框Toast.makeText(this, "登錄成功", 0).show();}}案例2:生成XML文件
public class MainActivity extends Activity {List<Message> smsList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//虛擬10條短信smsList = new ArrayList<Message>();for(int i = 0; i < 10; i++){Message sms = new Message("小志好棒" + i, System.currentTimeMillis() + "", "138"+i+i, "1");smsList.add(sms);}}public void click(View v){//在內(nèi)存中把xml備份短信的格式拼接出來(lái)StringBuffer sb = new StringBuffer();sb.append("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>");sb.append("<messages>");for (Message sms : smsList) {sb.append("<sms>");sb.append("<body>");sb.append(sms.getBody());sb.append("</body>");sb.append("<date>");sb.append(sms.getDate());sb.append("</date>");sb.append("<type>");sb.append(sms.getType());sb.append("</type>");sb.append("<address>");sb.append(sms.getAddress());sb.append("</address>");sb.append("</sms>");}sb.append("</messages>");File file = new File("sdcard/sms.xml");try {FileOutputStream fos = new FileOutputStream(file);fos.write(sb.toString().getBytes());fos.close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}案例3:XML序列化器
public class MainActivity extends Activity {List<Message> smsList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 虛擬10條短信smsList = new ArrayList<Message>();for (int i = 0; i < 10; i++) {Message sms = new Message("小志好棒" + i, System.currentTimeMillis()+ "", "138" + i + i, "1");smsList.add(sms);}}public void click(View v){//使用xml序列化器生成xml文件//1.拿到序列化器對(duì)象XmlSerializer xs = Xml.newSerializer();//2.初始化File file = new File("sdcard/sms2.xml");try {FileOutputStream fos = new FileOutputStream(file);//enconding:指定用什么編碼生成xml文件xs.setOutput(fos, "utf-8");//3.開(kāi)始生成xml文件//enconding:指定頭結(jié)點(diǎn)中的enconding屬性的值xs.startDocument("utf-8", true);xs.startTag(null, "message");for (Message sms : smsList) {xs.startTag(null, "sms");xs.startTag(null, "body");xs.text(sms.getBody() + "<body>");xs.endTag(null, "body");xs.startTag(null, "date");xs.text(sms.getDate());xs.endTag(null, "date");xs.startTag(null, "type");xs.text(sms.getType());xs.endTag(null, "type");xs.startTag(null, "address");xs.text(sms.getAddress());xs.endTag(null, "address");xs.endTag(null, "sms");}xs.endTag(null, "message");//告訴序列化器,文件生成完畢xs.endDocument();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}案例4:PULL解析
public class MainActivity extends Activity {List<Message> smsList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 虛擬10條短信smsList = new ArrayList<Message>();for (int i = 0; i < 10; i++) {Message sms = new Message("小志好棒" + i, System.currentTimeMillis()+ "", "138" + i + i, "1");smsList.add(sms);}}public void click(View v){//使用xml序列化器生成xml文件//1.拿到序列化器對(duì)象XmlSerializer xs = Xml.newSerializer();//2.初始化File file = new File("sdcard/sms2.xml");try {FileOutputStream fos = new FileOutputStream(file);//enconding:指定用什么編碼生成xml文件xs.setOutput(fos, "utf-8");//3.開(kāi)始生成xml文件//enconding:指定頭結(jié)點(diǎn)中的enconding屬性的值xs.startDocument("utf-8", true);xs.startTag(null, "message");for (Message sms : smsList) {xs.startTag(null, "sms");xs.startTag(null, "body");xs.text(sms.getBody() + "<body>");xs.endTag(null, "body");xs.startTag(null, "date");xs.text(sms.getDate());xs.endTag(null, "date");xs.startTag(null, "type");xs.text(sms.getType());xs.endTag(null, "type");xs.startTag(null, "address");xs.text(sms.getAddress());xs.endTag(null, "address");xs.endTag(null, "sms");}xs.endTag(null, "message");//告訴序列化器,文件生成完畢xs.endDocument();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}} 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的Android应用开发:数据存储和界面展现-1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JNI与底层调用-2
- 下一篇: Android应用开发:数据存储和界面展