数据存储和界面展示
常見布局
線性布局
- 有一個布局方向,水平或者豎直
- 在豎直布局下,左對齊、右對齊,水平居中生效
- 在水平布局下,頂部對齊、底部對齊、豎直居中生效
- 權重:按比例分配屏幕的剩余寬度或者高度
相對布局
- 組件默認位置都是左上角,組件之間可以重疊
- 可以相對于父元素上下左右對齊,相對于父元素,水平居中、豎直居中、水平豎直同時居中
- 可以相對于其他組件上下左右對齊
- 可以布局于其他組件的上方、下方、左邊、右邊
幀布局
- 組件默認位置都是左上角,組件之間可以重疊
- 可以設置上下左右對齊,水平豎直居中,設置方式與線性布局一樣
表格布局
- 每有一個TableRow子節點表示一行,該子節點的每一個子節點都表示一列
- TableLayout的一級子節點默認寬都是匹配父元素
- TableRow的子節點默認寬高都是包裹內容
Logcat
等級
- verbose:冗余,最低等級
- debug:調試
- info:正常等級的信息
- warn:警告
- error:錯誤
Android的存儲
內部存儲空間
- RAM內存:運行內存,相當于電腦的內存
- ROM內存:存儲內存,相當于電腦的硬盤
外部存儲空間
SD卡:相當于電腦的移動硬盤
- 2.2之前,sd卡路徑:sdcard
- 4.3之前,sd卡路徑:mnt/sdcard
- 4.3開始,sd卡路徑:storage/sdcard
所有存儲設備,都會被劃分成若干個區塊,每個區塊有固定的大小
- 存儲設備的總大小 = 區塊大小 * 區塊數量
文件訪問權限
- 指的是誰能訪問這個文件
- 在Android中,每一個應用,都是一個獨立的用戶
- 使用10個字母表示
- drwxrwxrwx
- 第一個字母:
- d:表示文件夾
- -:表示文件
- 第一組rwx:表示的是文件擁有者(owner)對文件的權限
- r:read,讀
- w:write
- x:execute
- 第二組rwx:表示的是跟文件擁有者屬于同一用戶組的用戶(grouper)對文件的權限
- 第三組rwx:表示的其他用戶(other)對文件的權限
SharedPreference
- 非常適合用來保存零散的簡單的數據
常見布局
相對布局
RelativeLayout
- 組件默認左對齊、頂部對齊
設置組件在指定組件的右邊
android:layout_toRightOf="@id/tv1"設置在指定組件的下邊
android:layout_below="@id/tv1"設置右對齊父元素
android:layout_alignParentRight="true"設置與指定組件右對齊
android:layout_alignRight="@id/tv1"
線性布局
LinearLayout
指定各個節點的排列方向
android:orientation="horizontal"設置右對齊
android:layout_gravity="right"- 當豎直布局時,只能左右對齊和水平居中,頂部底部對齊豎直居中無效
- 當水平布局時,只能頂部底部對齊和豎直居中
- 使用match_parent時注意不要把其他組件頂出去
線性布局非常重要的一個屬性:權重
android:layout_weight="1"- 權重設置的是按比例分配剩余的空間
幀布局
FrameLayout
- 默認組件都是左對齊和頂部對齊,每個組件相當于一個div
可以更改對齊方式
android:layout_gravity="bottom"- 不能相對于其他組件布局
表格布局
TableLayout
- 每個節點是一行,它的每個子節點是一列
表格布局中的節點可以不設置寬高,因為設置了也無效
- 根節點的子節點寬為匹配父元素,高為包裹內容
- 節點的子節點寬為包裹內容,高為包裹內容
- 以上默認屬性無法修改
根節點中可以設置以下屬性,表示讓第1列拉伸填滿屏幕寬度的剩余空間
android:stretchColumns="1"
絕對布局
AbsoluteLayout
直接指定組件的x、y坐標
android:layout_x="144dp" android:layout_y="154dp"
logcat
- 日志信息總共分為5個等級
- verbose
- debug
- info
- warn
- error
- 定義過濾器方便查看
- System.out.print輸出的日志級別是info,tag是System.out
Android提供的日志輸出api
Log.v(TAG, "加油吧,童鞋們"); Log.d(TAG, "加油吧,童鞋們"); Log.i(TAG, "加油吧,童鞋們"); Log.w(TAG, "加油吧,童鞋們"); Log.e(TAG, "加油吧,童鞋們");
文件讀寫操作
- Ram內存:運行內存,相當于電腦的內存
- Rom內存:內部存儲空間,相當于電腦的硬盤
- sd卡:外部存儲空間,相當于電腦的移動硬盤
在內部存儲空間中讀寫文件
小案例:用戶輸入賬號密碼,勾選“記住賬號密碼”,點擊登錄按鈕,登錄的同時持久化保存賬號和密碼
1. 定義布局
2. 完成按鈕的點擊事件
彈土司提示用戶登錄成功
Toast.makeText(this, "登錄成功", Toast.LENGTH_SHORT).show();
3. 拿到用戶輸入的數據
判斷用戶是否勾選保存賬號密碼
CheckBox cb = (CheckBox) findViewById(R.id.cb); if(cb.isChecked()){}
4. 開啟io流把文件寫入內部存儲
直接開啟文件輸出流寫數據
//持久化保存數據File file = new File("data/data/com.itheima.rwinrom/info.txt");FileOutputStream fos = new FileOutputStream(file);fos.write((name + "##" + pass).getBytes());fos.close();讀取數據前先檢測文件是否存在
if(file.exists())讀取保存的數據,也是直接開文件輸入流讀取
File file = new File("data/data/com.itheima.rwinrom/info.txt"); FileInputStream fis = new FileInputStream(file); //把字節流轉換成字符流 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]);- 應用只能在自己的包名目錄下創建文件,不能到別人家去創建
直接復制項目
- 需要改動的地方:
- 項目名字
- 應用包名
- R文件重新導包
使用路徑api讀寫文件
- getFilesDir()得到的file對象的路徑是data/data/com.itheima.rwinrom2/files
- 存放在這個路徑下的文件,只要你不刪,它就一直在
getCacheDir()得到的file對象的路徑是data/data/com.itheima.rwinrom2/cache
- 存放在這個路徑下的文件,當內存不足時,有可能被刪除
系統管理應用界面的清除緩存,會清除cache文件夾下的東西,清除數據,會清除整個包名目錄下的東西
在外部存儲讀寫數據
sd卡的路徑
- sdcard:2.3之前的sd卡路徑
- mnt/sdcard:4.3之前的sd卡路徑
storage/sdcard:4.3之后的sd卡路徑
最簡單的打開sd卡的方式
File file = new File("sdcard/info.txt");寫sd卡需要權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>讀sd卡,在4.0之前不需要權限,4.0之后可以設置為需要
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>使用api獲得sd卡的真實路徑,部分手機品牌會更改sd卡的路徑
Environment.getExternalStorageDirectory()判斷sd卡是否準備就緒
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
查看源代碼查找獲取sd卡剩余容量的代碼
- 導入Settings項目
查找“可用空間”得到
<string name="memory_available" msgid="418542433817289474">"可用空間"</string>查找”memory_available”,得到
<Preference android:key="memory_sd_avail" style="?android:attr/preferenceInformationStyle" android:title="@string/memory_available"android:summary="00"/>查找”memory_sd_avail”,得到
//這個字符串就是sd卡剩余容量 formatSize(availableBlocks * blockSize) + readOnly //這兩個參數相乘,得到sd卡以字節為單位的剩余容量 availableBlocks * blockSize存儲設備會被分為若干個區塊,每個區塊有固定的大小
- 區塊大小 * 區塊數量 等于 存儲設備的總大小
Linux文件的訪問權限
- 在Android中,每一個應用是一個獨立的用戶
- drwxrwxrwx
- 第1位:d表示文件夾,-表示文件
- 第2-4位:rwx,表示這個文件的擁有者用戶(owner)對該文件的權限
- r:讀
- w:寫
- x:執行
- 第5-7位:rwx,表示跟文件擁有者用戶同組的用戶(grouper)對該文件的權限
- 第8-10位:rwx,表示其他用戶組的用戶(other)對該文件的權限
openFileOutput的四種模式
- MODE_PRIVATE:-rw-rw—-
- MODE_APPEND:-rw-rw—-
- MODE_WORLD_WRITEABLE:-rw-rw–w-
- MODE_WORLD_READABLE:-rw-rw-r–
SharedPreference
用SharedPreference存儲賬號密碼
往SharedPreference里寫數據
//拿到一個SharedPreference對象 SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE); //拿到編輯器 Editor ed = sp.edit(); //寫數據 ed.putBoolean("name", name); ed.commit();從SharedPreference里取數據
SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE); //從SharedPreference里取數據 String name = sp.getBoolean("name", "");
生成XML文件備份短信
- 創建幾個虛擬的短信對象,存在list中
- 備份數據通常都是備份至sd卡
使用StringBuffer拼接字符串
把整個xml文件所有節點append到sb對象里
sb.append("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"); //添加smss的開始節點 sb.append("<smss>"); .......把sb寫到輸出流中
fos.write(sb.toString().getBytes());
使用XMl序列化器生成xml文件
得到xml序列化器對象
XmlSerializer xs = Xml.newSerializer();給序列化器設置輸出流
File file = new File(Environment.getExternalStorageDirectory(), "backupsms.xml"); FileOutputStream fos = new FileOutputStream(file); //給序列化器指定好輸出流 xs.setOutput(fos, "utf-8");開始生成xml文件
xs.startDocument("utf-8", true); xs.startTag(null, "smss"); ......
pull解析xml文件
- 先自己寫一個xml文件,存一些天氣信息
拿到xml文件
InputStream is = getClassLoader().getResourceAsStream("weather.xml");拿到pull解析器
XmlPullParser xp = Xml.newPullParser();開始解析
拿到指針所在當前節點的事件類型
int type = xp.getEventType();事件類型主要有五種
- START_DOCUMENT:xml頭的事件類型
- END_DOCUMENT:xml尾的事件類型
- START_TAG:開始節點的事件類型
- END_TAG:結束節點的事件類型
- TEXT:文本節點的事件類型
如果獲取到的事件類型不是END_DOCUMENT,就說明解析還沒有完成,如果是,解析完成,while循環結束
while(type != XmlPullParser.END_DOCUMENT)當我們解析到不同節點時,需要進行不同的操作,所以判斷一下當前節點的name
- 當解析到weather的開始節點時,new出list
- 當解析到city的開始節點時,創建city對象,創建對象是為了更方便的保存即將解析到的文本
當解析到name開始節點時,獲取下一個節點的文本內容,temp、pm也是一樣
case XmlPullParser.START_TAG: //獲取當前節點的名字if("weather".equals(xp.getName())){citys = new ArrayList<City>();}else if("city".equals(xp.getName())){city = new City();}else if("name".equals(xp.getName())){//獲取當前節點的下一個節點的文本String name = xp.nextText();city.setName(name);}else if("temp".equals(xp.getName())){String temp = xp.nextText();city.setTemp(temp);}else if("pm".equals(xp.getName())){String pm = xp.nextText();city.setPm(pm);}break;
當解析到city的結束節點時,說明city的三個子節點已經全部解析完了,把city對象添加至list
case XmlPullParser.END_TAG:if("city".equals(xp.getName())){citys.add(city);}
總結
- 上一篇: Java基础:继承、多态、抽象、接口
- 下一篇: 博客编辑神器:Markdown编辑器