androidBasic
一、? 概述
android是一種基于Linux的自由開源代碼的操作系統,主要用于移動設備,如智能手機和平板電腦。
1.????????手機通信技術代世
手機根據通信技術的代世分為1G,2G,3G,4G,未來向5G發展。第1代通信技術使用模擬網絡傳遞信號,如早期的大哥大,類似簡單的無線電雙工電臺。第2代技術主要是gsm、chma,比如moto、nokia等的手機采用這個頻段的無線技術,速度約在10kb左右。第3代使用的技術主要是wcdma、cdma2000,傳輸速度遠遠快于2G,約為100kb左右,圖片和語音的傳播質量提高,主要產品如android和ios,電容屏、多點觸控技術和手勢操作等技術促進手機智能化。第4代,速度比3G提高了10倍左右,視頻的傳播質量提高。預計未來5G的速度比4G提高10倍左右,預計有可能促進VR的普及化。
2.????????android操作系統和版本
android系統最初由安迪-魯賓等人開發。2005年8月被google公司收購。android的版本從1.5開始基本是都是以食物命名。4.0以下的使用率較低,主要以4.0以上為主。
3.????????android系統的體系結構
如下表:
| APPLICATION | |||||||||||||
| Home | Contacts | Phone | Browser | …… | |||||||||
| APPLICATION? FRAMEWORK | |||||||||||||
| Activity? Manager | Window? Manager | Content? Manager | View? Manager | ||||||||||
| Package? Manager | Telephone? Manager | Resource? Manager | Location? Manager | Notification? Manager | |||||||||
| LIBRARIES | ????????????? ANDROID? RUNTIME | ||||||||||||
| Surface? Manager | Media? Framework | SQLite | Core? Libraries | ||||||||||
| OpenGL|ES | FreeType | WebKit | Dalvik? Virtual? Machine | ||||||||||
| SGL | SSL | Libc | ? | ||||||||||
| LINUX? KERNEL | |||||||||||||
| Display? Driver | Camera? Driver | Flash? Memery? Driver | Binder(IPC)? Driver | ||||||||||
| Keypad? Driver | WiFi? Driver | Audio? Drivers | Power? Management | ||||||||||
application?framework應用框架層,可以是采用java編寫的api。這一層表現在最高層應用層,向下可以調用c、c++、java編寫的庫文件。
4.????????android虛擬機
java代碼需要運行在jvm虛擬機上。android中的java代碼運行在dalvik虛擬機上。由于利益的關系,google沒有使用jvm而是自己開發了dvm。兩者的比較是,jvm基于的架構是棧,也就是內存,dvm基于寄存器,也就是cpu;jvm編譯后的文件是從java編譯為.class或這.jar;dvm編譯后的文件是從java編譯為.class,然后為.dex或者.odex。從4.4以后,采用art模式,android? runtime來替代dalvik(可選的),以提高系統的運行速度;5.0之后放棄了art徹底替代dalvik,dalvik被放棄使用。java是解釋性語言,就是說在編譯后,運行時需要將二進制的字節碼文件翻譯為機器碼才能被設備讀取,art虛擬機的優化處理是在安裝程序時就將字節碼翻譯為機器碼,相比dalvik的邊翻譯邊運行就提高了速度,區別是程序的安裝速度滿了,程序占的空間也相對變大了,是一種用空間換時間的策略。
5.????????搭建集成開發環境
常用的集成開發環境有eclipse和google發布的android? studio。
google提供了android的軟件開發包。從官網下載4.0以上版本的sdk包。sdk包的目錄結構為:
add-ons,是google提供的相關的服務,比如goole地圖、google云、google推送、用戶統計。
build-tools,編譯工具,對android項目打包。
docs,android幫助文檔。
extras,android的支持庫,對低的版本的支持補丁或者對其他設備或接口的支持。intel的硬件加速器。
platforms,android的平臺。
platform-tools,與平臺相關的打包的文件。
sources,android應用框架層相關的源碼。
system-images,android自帶的虛擬機,不同的系統的鏡像。
temp,臨時文件夾。
tools,一些相關的工具。
使用sdk自帶的sdk? manager可以下載安裝和更新sdk。需要通過設置代理下載。通過tools>options設置。
在eclipse中安裝adt插件,如果不能在線安裝,可以離線安裝,下載一個ADT包,然后,在eclipse中help>install? new?software>add>archive>選擇adt壓縮包的路徑>ok>選中develop?tools>next>next>安裝>安裝完畢,重啟eclipse。
6.????????android虛擬機
安裝好ADT插件后,在控制面板就看到Android? sdk? manager和android? virtual? device?manager的圖標,如果沒有,設置window>perspective>customize? perspective>action? set?availability>選中這兩項的選項。然后,點擊android? virtual?device? manager,create虛擬設備,分辨率選擇3.2寸的;cpu架構選擇arm或者intel的,一般是arm的,如果要使用intel加速器要選intel的cpu;攝像頭選擇none,做攝像頭相關的開發需要用真機;內存選項都默認。設置好后,start可以開啟設備。再create一個設備,開啟,兩者可以互通電話和發信息。
7.????????ddms透視圖
Dalvik Debug? Monitor?Services,Dalvik虛擬機調試監控服務。在Java? EE按鈕隔壁有DDMS按鈕,如果沒有在window>perspective>open? perspective>other中可以找到。打開ddms視圖,可以看到devices選項卡,顯示當前啟動的移動設備。在選項卡中screen? capture可以截屏,file? explore可以查看設備的文件目錄,data>app目錄下放安裝的應用,data>data放設備本身程序的文件,mnt>sdcard是sdcard的路徑。emulator? control是虛擬機的控制器,可以給指定的設備打電話、發短信、設置位置信息等。
8.????????第一個android程序
file>new>android? application?project。填寫應用名,應用名和項目名一致,包名采用域名反轉方式、不可以出現中文字符。next,勾選創建自定義登陸圖標,創建activity,在工作空間創建項目;next,設置一個圖標;next,選擇一個activity;next,給activity命名;finish。
創建完成后,通過graphical? layout視圖可以看預覽,activity_main.xml是布局的xml文檔,MainActivity.java是程序代碼,右鍵項目run? as>android?application,可以運行到avd上。
Android程序的目錄結構
| scr | 程序源文件 | |
| gen | 自動生成的java文件 | |
| Android4.x.x | 編譯依賴的jar包 | |
| Android? Private? Libraries | android支持庫 | |
| assets | 不被編譯的文件 | |
| bin | 編譯后的內容放在bin目錄 | |
| libs | 項目依賴的其他庫文件 | |
| res?? resource? 項目相關的資源 | drawable | 像素率,放置圖片的文件 |
| layout | 布局文件夾,放布局的文件 | |
| menu | 菜單,一般是3個按鈕 | |
| values | 值,放一些相關的值的文件 | |
| values-v11 | 放版本適配的文件 | |
| values-v14 | 放版本適配的文件 | |
| values-w820dp | 放屏幕適配的文件 | |
| AndroidManifest.xml | 項目的清單文件,注意包名的重名問題 | |
9.????????android項目打包
打包就是做成apk文件,也就是app安裝包。一個android項目的唯一性的標志是項目的包名和簽名,右鍵項目>android?tools>export? signed? application?packeg,生成項目簽名包,進行打包。需要注意的是keystore文件不能丟失,密碼不能丟失,有效期設置的時間足夠長。打包后,通過adb,android? debug?bridge,android調試橋發布到設備上。
10.????? adb指令
進入命令行。
adb?kill-server,關閉adb服務。通過任務管理器可以查看服務進程,一般在第一個進程的位置。
adb?start-server,開啟adb服務。
adb?uninstall? 項目的包名,卸載app。
adb?install? res目錄下的apk文件,安裝app。
adb? push? 本地pc文件全路徑? avd路徑(sdcard/),將本地pc的文件推到avd設備。
adb?pull? avd路徑(sdcard/1.apk)? 本地pc路徑可以(重命名)C:\Users\Administrator\Desktop\2.apk,從avd設備拖拽文件到本地pc。注意,avd的路徑使用/。
adb?shell,進入avd的shell,實際上avd是一個linux設備,可以使用linux命令操作。
11.????? 編寫一個電話撥號器
首先,畫ui,畫用戶界面,在layout->xml布局文件中做;
然后,對著ui寫java代碼;
然后,部署到設備看效果。
在eclipse中創建項目。
在res>layout>activity_main.xml中,畫ui。
RelativeLayout是一個相對布局的容器,里面的TextView用于顯示文本,用戶不可以修改的。TextView標簽下,layout_width表示布局寬度,layout_height表示布局的高度,wrap_content表示自適應內容大小,match_parent表示適應父級組件大小。通過修改RelativeLayout中的內邊距標簽可以修改TextView中文本框與父級的距離:
???android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"在TextView標簽的text標簽中設置要顯示的文本內容,比如:
???<TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:text="請輸入電話號碼"/>然后,添加EditText,相當于web中的文本域,添加一個Button。
最終ui的xml為:
<RelativeLayoutxmlns: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="com.example.dailer.MainActivity" ><TextViewandroid:id="@+id/textView1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:text="請輸入電話號碼"/><EditTextandroid:id="@+id/editText1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_below="@+id/textView1"android:hint="請輸入電話號"android:ems="10" ><requestFocus /></EditText><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_below="@+id/editText1"android:text="撥打號碼" /></RelativeLayout>編寫java代碼
Activity類很重要,代表了一個用戶的界面,每一個android界面都對應一個activity。activity可以創建一個窗口上加載用戶的界面(UI),這個界面就是用來跟用戶交互的。
當Activity創建的時候調用onCreate方法。
public class MainActivity extendsActionBarActivity {privateEditText editText;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);editText= (EditText) findViewById(R.id.editText1);Buttonbutton = (Button) findViewById(R.id.button1);button.setOnClickListener(newMyOnClickListener());}privateclass MyOnClickListener implements OnClickListener {@SuppressLint("NewApi")@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//按鈕點擊事件//1,獲取用戶的輸入//空校驗StringinputNum = editText.getText().toString();if(inputNum.isEmpty()) {//Toast,向界面輸出一個短暫的提示Toast.makeText(MainActivity.this,"輸入不能為空",Toast.LENGTH_SHORT).show();System.out.println("輸入不能為空");}else {System.out.println("打電話");//開啟打電話的avtivity,Intent對要進行的操作的抽象描述。可以開啟一個ActivityIntentintent = new Intent();intent.setAction(Intent.ACTION_CALL);//給意圖設置內容Uridata = Uri.parse("tel:" + inputNum);intent.setData(data);startActivity(intent);}}}}出于經濟安全的考慮,有些應用需要獲得權限后才能執行,打電話需要獲得打電話的權限,在清單文件中設置,AndroidManifest.xml>permissions>add>users? permission>選擇CALL_PHONE>保存。
運行app測試。
注意,在撥號中對于美國認定的緊急號碼不能直接播出,需要手動點擊撥打。
12.????? 點擊事件的4種寫法
第一種,通過內部類的方式,如上。
第二種,通過匿名內部類的方式,優點是節省內存。
button.setOnClickListener(new OnClickListener(){@SuppressLint("NewApi")@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//TODO Auto-generated method stub// 按鈕點擊事件//1,獲取用戶的輸入//空校驗StringinputNum = editText.getText().toString();if(inputNum.isEmpty()) {//Toast,向界面輸出一個短暫的提示Toast.makeText(MainActivity.this,"輸入不能為空",Toast.LENGTH_SHORT).show();System.out.println("輸入不能為空");}else {System.out.println("打電話");//開啟打電話的avtivity,Intent對要進行的操作的抽象描述。可以開啟一個ActivityIntentintent = new Intent();intent.setAction(Intent.ACTION_CALL);//給意圖設置內容Uridata = Uri.parse("tel:" + inputNum);intent.setData(data);startActivity(intent);}}});第三種寫法,activity類實現OnClickListener接口。
public class MainActivity extendsActionBarActivity implements OnClickListener {privateEditText editText;privateButton button;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);editText= (EditText) findViewById(R.id.editText1);button= (Button) findViewById(R.id.button1);button.setOnClickListener(this);}@SuppressLint("NewApi")@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//TODO Auto-generated method stub//按鈕點擊事件//1,獲取用戶的輸入//空校驗StringinputNum = editText.getText().toString();if(inputNum.isEmpty()) {//Toast,向界面輸出一個短暫的提示Toast.makeText(this,"輸入不能為空",Toast.LENGTH_SHORT).show();System.out.println("輸入不能為空");}else {System.out.println("打電話");//開啟打電話的avtivity,Intent對要進行的操作的抽象描述。可以開啟一個ActivityIntentintent = new Intent();intent.setAction(Intent.ACTION_CALL);//給意圖設置內容Uridata = Uri.parse("tel:" + inputNum);intent.setData(data);startActivity(intent);}}}如果一個主控件中有多個button按鈕,當這個主控件實現了點擊偵聽接口后,為了區別是哪個按鈕的事件,可以使用onClick()方法的參數,來區分。
?? private class MyOnClickListener implements OnClickListener {@SuppressLint("NewApi")@Overridepublicvoid onClick(View v) {//獲得控件的id,根據id執行不同的操作intid = v.getId();switch(id){caseR.id.button1:break;caseR.id.button2:break;caseR.id.button3:break;}第四種,布局文件中添加onclick屬性
? ??<Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignLeft="@+id/editText1"android:layout_below="@+id/editText1"android:onClick="call"android:text="撥打此號" />然后在主控件中編寫call方法
???????? publicvoid call(View v) {Stringnumber = editText.getText().toString().trim();if(TextUtils.isEmpty(number)) {Toast.makeText(this,"輸入不能為空",Toast.LENGTH_SHORT).show();}else {Intentintent = new Intent();intent.setAction(Intent.ACTION_CALL);intent.setData(Uri.parse("tel:"+ number));startActivity(intent);}}注意,參數一定要是View類型的,且方法名和布局文件中定義的一致。
第四種方法比較少用,由于使得類的內部內容顯得不清晰。
13.????? 五種布局
1)????????線性布局
只能在垂直方向或水平方向布局的,通過設置屬性orientation的值為垂直或水平。
<?xml version="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個textview"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個textview"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個textview"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個textview"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個textview"/></LinearLayout>2)????????相對布局
創建項目時默認創建的布局文件就是相對布局的。相對布局是相對某個主件的布局,通過指定相對組件的距離可以設置主件的位置。相對布局,擺放控件的位置更靈活。
<RelativeLayoutxmlns: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="com.example.fivelayout.MainActivity" ><TextViewandroid:id="@+id/textview1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world" /><TextViewandroid:id="@+id/textview2"android:layout_below="@id/textview1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview2" /><TextViewandroid:id="@+id/textview3"android:layout_toRightOf="@id/textview1"android:layout_alignBottom="@id/textview1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview3" /><TextViewandroid:id="@+id/textview4"android:layout_toRightOf="@id/textview3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview4" /><TextViewandroid:id="@+id/textview5"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview5" /><TextViewandroid:id="@+id/textview6"android:layout_alignParentBottom="true"android:layout_centerHorizontal="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview6" /></RelativeLayout>3)????????幀布局
可以通過組合屬性將控件擺放在屏幕的類似九宮格的位置。使用外邊距可以更靈活的擺放。
<?xml version="1.0"encoding="utf-8"?><FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><TextViewandroid:id="@+id/textview1"android:layout_gravity="bottom"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="text1" /><TextViewandroid:id="@+id/textview2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:text="text2" /><TextViewandroid:id="@+id/textview3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:text="text3" /><TextViewandroid:id="@+id/textview4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical|center"android:text="text4" /><TextViewandroid:id="@+id/textview5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_marginLeft="100dp"android:text="text5" /></FrameLayout>4)????????表格布局
通過表格的行和列來布局控件。
<?xml version="1.0"encoding="utf-8"?><TableLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><TableRow>??<TextViewandroid:id="@+id/textview1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview1" /><TextViewandroid:id="@+id/textview2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview2" /><TextViewandroid:id="@+id/textview3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview3" /></TableRow><TextViewandroid:id="@+id/textview4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview4" /></TableLayout>5)????????絕對布局
通過絕對的坐標來定位控件。絕對布局對不同分辨率尺寸的屏幕適應性較差,已經很少被使用了。
<?xml version="1.0"encoding="utf-8"?><AbsoluteLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><TextViewandroid:id="@+id/textview1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="textview1" /><TextViewandroid:id="@+id/textview3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_x="113dp"android:layout_y="43dp"android:text="textview3" /><TextViewandroid:id="@+id/textview2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_x="12dp"android:layout_y="54dp"android:text="textview2" /></AbsoluteLayout>五種布局的使用度從高到低排序是:相對》線性》幀》表格》絕對。
14.????? 測試
從代碼可以見的角度,測試分為黑盒測試和白盒測試。黑盒測試,看不見代碼的情況下,通過點擊等方式測試軟件,自動化測試等。白盒測試,可以看見代碼的,比如單元測試、集成測試、系統測試等。從對軟件的施力程度,分為壓力測試、冒煙測試等,壓力測試,在高并發訪問或者高頻率使用軟件的情況下的反應,android中使用的monkey測試,monkey? 1000或者monkey? -p? 包名? 次數,對某一個應用的點擊;冒煙測試,就是不停的測試直到軟件崩潰。
在android中使用單元測試。
編寫一個測試類繼承AndroidTextCase類,然后在清單文件中添加Instrumentation,包名填寫測試類在的包,類名為android.test.InstrumentationTestRunner。在清單文件的application標簽中添加<uses-libraryandroid:name="android.test.runner" />。在測試類中編寫方法,右鍵run? as>Android? JUnit?Test進行測試。
15.????? 日志貓
日志貓logcat可以查看文件的輸出以及錯誤警告等提醒。使用saved? filter可以添加過濾條件。可以選擇日志的級別進行過濾。也可以使用Log類的方法進行過濾。
???????? protectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);System.out.println("輸出日志");Log.v("MainActivity","vervbose");Log.d("MainActivity","debug");Log.i("MainActivity","info");Log.w("MainActivity","warning");Log.e("MainActivity","error");}一般,為了方便項目在測試和上線之間顯示或不顯示logcat數據,不會直接使用Log類的方法,而是通過一個工具類,設置開關間接使用Log類的方法。這樣,在測試時,打開開關,可以查看輸出;項目上線后,關閉開關,可以不顯示測試時出現的logcat輸出。這樣,主要是為了避免直接使用Log方法,而待上線后需要大量工作去注釋這些方法。
public class LogUtils {privatestatic boolean openLog = true;publicstatic void LOGV(String tag, String msg) {if(openLog) {Log.d(tag,msg);}}publicstatic void LOGD(String tag, String msg) {if(openLog) {Log.d(tag,msg);}}publicstatic void LOGI(String tag, String msg) {if(openLog) {Log.d(tag,msg);}}publicstatic void LOGW(String tag, String msg) {if(openLog) {Log.d(tag,msg);}}publicstatic void LOGE(String tag, String msg) {if(openLog) {Log.d(tag,msg);}}}二、?數據存儲
關于android系統的數據存儲方面的東西。
1.????????一個用到數據存儲的案例
使用java的io流來存儲用戶數據的登陸案例。
首先,UI設計。
<RelativeLayoutxmlns: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="com.example.logintest1.MainActivity" ><TextViewandroid:id="@+id/title"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="登錄界面" /><EditTextandroid:id="@+id/username"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/title"android:hint="請輸入用戶名"/><EditTextandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/username"android:inputType="textPassword"android:hint="請輸入密碼"/><CheckBoxandroid:id="@+id/isShow"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/password"android:text="勾選保存密碼"/><Buttonandroid:id="@+id/loginButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_below="@id/password"android:text="登陸"/></RelativeLayout>編寫主類入口方法,實現業務邏輯?
??????? protectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//獲取用戶名輸入框控件finalEditText usernameV = (EditText) findViewById(R.id.username);finalEditText passwordV = (EditText) findViewById(R.id.password);finalCheckBox isShowV = (CheckBox) findViewById(R.id.isShow);Stringresult = UserUtils.getInfo();if(result != null) {String[]results = result.split(":");if("true".equals(results[2])) {usernameV.setText(results[0]);passwordV.setText(results[1]);isShowV.setChecked(true);}}ButtonloginV = (Button) findViewById(R.id.loginButton);//給登陸按鈕添加點擊監聽loginV.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//檢驗用戶名和密碼Stringusername = usernameV.getText().toString().trim();Stringpassword = passwordV.getText().toString().trim();if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {Toast.makeText(MainActivity.this,"用戶名或密碼不能為空",Toast.LENGTH_SHORT).show();}else {BooleanisShow = isShowV.isChecked();Toast.makeText(MainActivity.this,isShow.toString(),Toast.LENGTH_SHORT).show();Toast.makeText(MainActivity.this,"登陸成功",Toast.LENGTH_SHORT).show();//在用戶設備上保存用戶名和密碼booleansaveResult = UserUtils.saveInfo(username, password,isShow);if(saveResult) {Toast.makeText(MainActivity.this,"保存成功",Toast.LENGTH_SHORT).show();}else {Toast.makeText(MainActivity.this,"保存失敗",Toast.LENGTH_SHORT).show();}}}});}編寫使用io流的工具
/*** 用戶工具類**@author Administrator*@version 1.0*/public class UserUtils {/*** 保存用戶名和密碼** @param username*???????????,用戶名* @param password*???????????,密碼* @param isShow* @return,保存成功,反悔true;否則返回fasle*/publicstatic boolean saveInfo(String username, String password,BooleanisShow) {//TODO Auto-generated method stubStringinfo = username + ":" + password + ":" + isShow.toString();Filefile = new File("data/data/com.example.logintest1/info.data");try{BufferedWriterbw = new BufferedWriter(new FileWriter(file));bw.write(info);bw.newLine();bw.close();returntrue;}catch (IOException e) {e.printStackTrace();returnfalse;}}/*** 獲取用戶信息的方法** @return 返回用戶信息的字符串*/publicstatic String getInfo() {Filefile = new File("data/data/com.example.logintest1/info.data");try{BufferedReaderbr = new BufferedReader(new FileReader(file));Stringinfo = null;if((info = br.readLine()) != null) {returninfo;}returnnull;}catch (IOException e) {e.printStackTrace();returnnull;}}}2.????????通過上下文獲取常見目錄
通過上下文類Context可以訪問跟當前應用相關的信息,也可以訪問當前應用的私有資源和類,也可以做系統級的調用,比如開啟另外一個avtivity、發廣播和開啟服務。
修改后的保存數據和獲取數據的方法
???????? publicstatic boolean saveInfoByContext(Context context, String username,Stringpassword, Boolean isShow) {//TODO Auto-generated method stubStringinfo = username + ":" + password + ":" + isShow.toString();//File file = new File("data/data/com.example.logintest1/info.data");//File file = new File(context.getFilesDir().getAbsoluteFile()//+ "/info.data");try{//BufferedWriter bw = new BufferedWriter(new FileWriter(file));FileOutputStreamfos = context.openFileOutput("info2.data",Context.MODE_PRIVATE);BufferedWriterbw = new BufferedWriter(new OutputStreamWriter(fos));bw.write(info);bw.newLine();bw.close();returntrue;}catch (IOException e) {e.printStackTrace();returnfalse;}}publicstatic String getInfoByContext(Context context) {//File file = new File("data/data/com.example.logintest1/info.data");try{FileInputStreamfis = context.openFileInput("info2.data");BufferedReaderbr = new BufferedReader(new InputStreamReader(fis));Stringinfo = null;if((info = br.readLine()) != null) {returninfo;}returnnull;}catch (IOException e) {e.printStackTrace();returnnull;}}3.????????數據保存至sd卡
使用Environment類獲取sd卡的一些數據。
?? ?????????????????? public voidonClick(View v) {//TODO Auto-generated method stub//檢驗用戶名和密碼Stringusername = usernameV.getText().toString().trim();Stringpassword = passwordV.getText().toString().trim();booleansaveResult = false;BooleanisShow = isShowV.isChecked();if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {Toast.makeText(MainActivity.this,"用戶名或密碼不能為空",Toast.LENGTH_SHORT).show();}else {if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){Toast.makeText(MainActivity.this,isShow.toString(),Toast.LENGTH_SHORT).show();Toast.makeText(MainActivity.this,"登陸成功",Toast.LENGTH_SHORT).show();//在用戶設備上保存用戶名和密碼//boolean saveResult = UserUtils.saveInfo(username,//password,//isShow);//boolean saveResult = UserUtils.saveInfoByContext(//MainActivity.this, username, password, isShow);saveResult= UserUtils.saveInfo2sd(username, password,isShow);Toast.makeText(MainActivity.this,saveResult? "保存到sd卡成功" : "保存到sd卡失敗",Toast.LENGTH_SHORT).show();}else {saveResult= UserUtils.saveInfoByContext(MainActivity.this,username, password, isShow);Toast.makeText(MainActivity.this,saveResult? "保存到內存卡成功" : "保存到內存卡失敗",Toast.LENGTH_SHORT).show();}}}保存數據到sd卡的方法
???????? publicstatic boolean saveInfo2sd(String username, String password,BooleanisShow) {//TODO Auto-generated method stubStringinfo = username + ":" + password + ":" + isShow.toString();//File file = new File("mnt/sdcard/info.data");FilesdDir = Environment.getExternalStorageDirectory().getAbsoluteFile();Filefile = new File(sdDir, "info.data");try{BufferedWriterbw = new BufferedWriter(new FileWriter(file));bw.write(info);bw.newLine();bw.close();returntrue;}catch (IOException e) {e.printStackTrace();returnfalse;}}4.????????獲取sd卡的大小
???????? protectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextViewfreeSpaceV = (TextView) findViewById(R.id.sdFreeSpace);TextViewtotalSpaceV = (TextView) findViewById(R.id.sdTotalSpace);FilestorageDir = Environment.getExternalStorageDirectory();longtotalSpace = storageDir.getTotalSpace();longfreeSpace = storageDir.getFreeSpace();totalSpace/= (1024 * 1024);freeSpaceV.setText("剩余空間:" + Long.toString(freeSpace) + "bytes");totalSpaceV.setText("總空間:" + Long.toString(totalSpace) + "Mb");}5.????????android中常用的像素單位
長度單位,px和dp。px,pixel,表示像素,是絕對的單位,屏幕適配性不好。dp,device? in? dependent?pixels,虛擬的像素,在不同的像素密度的設備上會自動適配。sp,類似dp,會根據用戶的字體大小偏好來縮放,常用于表示字體大小。
6.????????文件權限
android的操作系統的內核是linux內核,linux對文件的權限有嚴格的控制。每個應用的權限一般僅限于該應用讀寫,其他用戶也就是其他應用,沒有任何權限。為了訪問其他應用的私有文件,需要通過root用戶修改這個應用的文件的權限,使用adb? shell獲得root的shell。使用chmod? -R? xxx? 文件名,修改權限。
???????? publicvoid read(View v) {Filefile = new File("data/data/com.example.logintest1/info.data");try{BufferedReaderbr = new BufferedReader(new FileReader(file));Stringresult = br.readLine();Toast.makeText(this,result, Toast.LENGTH_SHORT).show();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();Toast.makeText(this,"訪問失敗",Toast.LENGTH_SHORT).show();}}7.????????通過上下文保存文件的模式
通過上下文保存文件可以設置為不同的模式,主要是關于文件的權限方面的。
設計保存按鈕的UI。
<LinearLayoutxmlns: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="com.example.contextSaveMode.MainActivity"android:orientation="vertical" ><Buttonandroid:id="@+id/privateB"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="private" /><Buttonandroid:id="@+id/append"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="append" /><Buttonandroid:id="@+id/world_readable"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="world_readable" /><Buttonandroid:id="@+id/worldWritable"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="worldWritable" /></LinearLayout>編寫主類入口方法,給按鈕添加事件
???????? protectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButtonprivateB = (Button) findViewById(R.id.privateB);ButtonappendB = (Button) findViewById(R.id.append);Buttonworld_readableB = (Button) findViewById(R.id.world_readable);ButtonworldWritable = (Button) findViewById(R.id.worldWritable);privateB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubtry{FileOutputStreamfos = openFileOutput("private.txt",MODE_PRIVATE);fos.write("private".getBytes());fos.close();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}});appendB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubtry{FileOutputStreamfos = openFileOutput("append.txt",MODE_APPEND);fos.write("append".getBytes());fos.close();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}});world_readableB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubtry{FileOutputStreamfos = openFileOutput("world_readableB.txt",MODE_WORLD_READABLE);fos.write("world_readableB".getBytes());fos.close();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}});worldWritable.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubtry{FileOutputStreamfos = openFileOutput("worldWritable.txt",MODE_WORLD_WRITEABLE);fos.write("worldWritable".getBytes());fos.close();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}});}運行程序,到文件夾查看保存的文件的權限。一般常用的是append模式或者private模式,兩者的區別是append是追加寫,private是覆蓋寫。
8.????????SharedPreferences
訪問或修改配置數據的接口,通過Context對象的getSharedPreferences(String?name,int? mode)方法可以獲得這個接口對象。是輕量級的存儲數據的API,通過xml文件存儲數據。
使用SharedPreferences保存用戶登陸信息。
???????? privateEditText usernameV;privateEditText passwordV;privateCheckBox isShowV;privateSharedPreferences sp;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);usernameV= (EditText) findViewById(R.id.username);passwordV= (EditText) findViewById(R.id.password);isShowV= (CheckBox) findViewById(R.id.isShow);ButtonloginV = (Button) findViewById(R.id.login);loginV.setOnClickListener(this);sp= this.getSharedPreferences("info", MODE_PRIVATE);booleanisShow = sp.getBoolean("isShow", false);if(isShow) {Stringusername = sp.getString("username", "");Stringpassword = sp.getString("password", "");usernameV.setText(username);passwordV.setText(password);isShowV.setChecked(true);}}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringusername = usernameV.getText().toString().trim();Stringpassword = passwordV.getText().toString().trim();BooleanisShow = isShowV.isChecked();if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {Toast.makeText(this,"用戶名或密碼不能為空",Toast.LENGTH_SHORT).show();}else {Editoreditor = sp.edit();if(isShow) {editor.putString("username",username);editor.putString("password",password);}editor.putBoolean("isShow",isShow.booleanValue());editor.commit();}}9.????????xml序列化
將數據輸出為xml格式的文件,就是xml序列化的表現之一。
使用StringBuilder拼接xml字符串。
???????? ArrayList<SMS>smslist = new ArrayList<SMS>();@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);for(int i = 0; i < 20; i++) {SMSsms = new SMS();sms.from= "1000" + i;sms.content= "nihao" + i;sms.time= "19:40:" + i;smslist.add(sms);}for(SMS sms : smslist) {System.out.println(sms);}ButtonsaveB = (Button) findViewById(R.id.saveB);saveB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {// TODOAuto-generated method stubStringBuildersb = new StringBuilder();sb.append("<?xmlversion=\"1.0\" encoding=\"utf-8\"?>");sb.append("<SMSList>");for(SMS sms : smslist) {sb.append("<SMS><from>").append(sms.from).append("</from><content>").append(sms.content).append("</content><time>").append(sms.time).append("</time></SMS>");}sb.append("</SMSList>");Stringxml = sb.toString();try{FileOutputStreamfos = openFileOutput("sms.xml",MODE_PRIVATE);fos.write(xml.getBytes());fos.close();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}});}使用XmlSerializer類序列化xml
?? ???????? Button saveB2 =(Button) findViewById(R.id.saveB2);saveB2.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//獲取xml序列化器類XmlSerializerserializer = Xml.newSerializer();try{serializer.setOutput(openFileOutput("smslist2.xml",MODE_PRIVATE),"utf-8");//寫文檔開始的聲明serializer.startDocument("utf-8",true);serializer.startTag(null,"SMSLIST");for(SMS sms : smslist) {serializer.startTag(null,"SMS");serializer.startTag(null,"from");serializer.text(sms.from);serializer.endTag(null,"from");serializer.startTag(null,"content");serializer.text(sms.content);serializer.endTag(null,"content");serializer.startTag(null,"time");serializer.text(sms.time);serializer.endTag(null,"time");serializer.endTag(null,"SMS");}serializer.endTag(null,"SMSLIST");serializer.endDocument();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}});云備份等服務可以使用xml序列化文件,將xml文件上傳到云服務器。
10.?????pull解析xml文件
?? ???????? Button parseB =(Button) findViewById(R.id.parse);parseB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {ArrayList<SMS>smslist = null;SMSsms = null;//TODO Auto-generated method stubXmlPullParserxpp = Xml.newPullParser();try{xpp.setInput(openFileInput("smslist2.xml"),"utf-8");inteventType = xpp.getEventType();while(eventType != xpp.END_DOCUMENT) {switch(eventType) {caseXmlPullParser.START_TAG:if("SMSLIST".equals(xpp.getName())) {smslist= new ArrayList<SMS>();}else if ("SMS".equals(xpp.getName())) {sms= new SMS();}else if ("from".equals(xpp.getName())) {sms.from= xpp.nextText();}else if ("content".equals(xpp.getName())) {sms.content= xpp.nextText();}else if ("time".equals(xpp.getName())) {sms.time= xpp.nextText();}break;caseXmlPullParser.END_TAG:if("SMS".equals(xpp.getName())) {smslist.add(sms);}break;}eventType= xpp.next();}//for (SMS sm : smslist) {//System.out.println(sm);//}Toast.makeText(MainActivity.this,smslist.toString(),Toast.LENGTH_SHORT).show();}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}});}11.?????SQLite
lite表示輕量級的,SQLite是一個輕量級的數據庫,主要表現在體積小,適合嵌入式設備,綠色免安裝,擴平臺,單一文件。不足是多線程操作比較差,對sql的支持不全面,有的sql是不支持的,比如alter,多表查詢等。
1)????????使用SQLiteOpenHelper類操作sqlite數據庫。
創建一個項目,創建一個類繼承自SQLiteOpenHelpter。
public class MyOpenHelper extendsSQLiteOpenHelper {publicMyOpenHelper(Context context) {super(context,"ten1.db", null, 1, null);//TODO Auto-generated const ructor stub}@Overridepublicvoid onCreate(SQLiteDatabase db) {//TODO Auto-generated method stubdb.execSQL("createtable info(_id integer primary key autoincrement,name varchar(20),phonevarchar(20));");System.out.println("oncreate被調用");}//當版本號發生變化時,就會調用數據庫升級的方法@Overridepublicvoid onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//TODO Auto-generated method stub//表結構修改,比如增加字段//db.execSQL("alter table info add age integer");//獲取版本號是為了統計用戶版本分布System.out.println("oldversion:"+ oldVersion + ";newversion:"+newVersion);}@Overridepublicvoid onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {//TODO Auto-generated method stub//super.onDowngrade(db, oldVersion, newVersion);System.out.println("onDowngrade");}}在項目的主控件類的入口方法中調用sqllite數據庫對象和方法。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyOpenHelpermyOpenHelper = new MyOpenHelper(this);myOpenHelper.getWritableDatabase();}}2)????????直接執行sql語句操作
增查改刪?
? ???????? Button queryB =(Button) findViewById(R.id.query);ButtoninsertB = (Button) findViewById(R.id.insert);ButtonupdateB = (Button) findViewById(R.id.update);ButtondeleteB = (Button) findViewById(R.id.delete);queryB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//獲取sqlitedatebase對象SQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();//String[] strs = { "zhangsan", "23" };Cursorresult = database.rawQuery("select * from info", null);System.out.println("總記錄數:" + result.getCount());while(result.moveToNext()) {Stringname = result.getString(1);Stringphone = result.getString(result.getColumnIndex("phone"));intage = result.getInt(3);System.out.println("name:"+ name + "--phone:" + phone+"--age:" + age);}result.close();database.close();}});insertB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();database.execSQL("insertinto info (name,phone,age) values ('zhangsan','xiaomi',23)");database.execSQL("insertinto info (name,phone,age) values ('lisi','meizu',34)");database.close();}});updateB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();database.execSQL("updateinfo set age=100 where name = 'zhangsan'");database.close();}});deleteB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();database.execSQL("deletefrom info where name = 'lisi'");database.close();}});3)????????使用google封裝的api操作數據庫
?? ???????? // 使用google封裝的api操作數據庫ButtongqueryB = (Button) findViewById(R.id.gquery);ButtonginsertB = (Button) findViewById(R.id.ginsert);ButtongupdateB = (Button) findViewById(R.id.gupdate);ButtongdeleteB = (Button) findViewById(R.id.gdelete);gqueryB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();Cursorresult = database.query(false, "info", new String[] {"name","phone", "age" }, "name=?",newString[] { "maliu" }, null, null, null, null, null);while(result.moveToNext()) {Stringname = result.getString(0);Stringphone = result.getString(result.getColumnIndex("phone"));intage = result.getInt(2);System.out.println("name:"+ name + "--phone:" + phone+"--age:" + age);}result.close();database.close();}});ginsertB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();StringnullColumnHack = null;ContentValuesvalues = new ContentValues();values.put("name","maliu");values.put("age",25);values.put("phone","1234");longid = database.insert("info", nullColumnHack, values);System.out.println("當前插入的數據的id:" + id);database.close();}});gdeleteB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();intcount = database.delete("info", "name = ?",newString[] { "zhangsan" });Toast.makeText(MainActivity.this,"刪除了" + count +"條數據",Toast.LENGTH_SHORT).show();database.close();}});gupdateB.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubSQLiteDatabasedatabase = myOpenHelper.getReadableDatabase();ContentValuesvalues = new ContentValues();values.put("age",100);intcount = database.update("info", values, "name=?",newString[] { "maliu" });Toast.makeText(MainActivity.this,"更新了" + count +"條數據",Toast.LENGTH_SHORT).show();database.close();}});對比原始api和google封裝的api,返回值上,原始的沒有,google的有;當操作大量數據時,原始的較快;sql的靈活性,原始的api可以任意寫,google的有一定的限制;使用原始sql,可能會寫錯,而且幾率大于google提供的api。使用原始sql操作時,可以先在可視化軟件中測試下,通過后再復制sql語句,減小出錯率。
12.?????數據庫事務
事務,通俗的解釋,就是一系列操作,要么全部成功,要么全部失敗。
android中使用事務的案例。
創建MyOpenHelper,初始化方法中,創建表和插入數據。
然后,在主類中執行事務操作。
public class MainActivity extends Activity {privateMyOpenHelper openHelper;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);openHelper= new MyOpenHelper(this);}publicvoid transact(View v) {SQLiteDatabasedatabase = openHelper.getReadableDatabase();database.beginTransaction();try{database.execSQL("updateinfo set money=money-100 where name=?",newString[] { "張三" });inta = 10 / 0;database.execSQL("updateinfo set money=money+100 where name=?",newString[] { "李四" });database.setTransactionSuccessful();}catch (Exception e) {Toast.makeText(this,"服務器忙,異常碼1234",Toast.LENGTH_SHORT).show();}finally {database.endTransaction();database.close();}}publicvoid query(View v) {SQLiteDatabasedatabase = openHelper.getReadableDatabase();Cursorresult = database.rawQuery("select * from info", null);while(result.moveToNext()) {Stringname = result.getString(result.getColumnIndex("name"));Stringmoney = result.getString(3);System.out.println("name:"+ name + "--money:" + money);}result.close();database.close();}}三、? ListView
列表顯示,是app中廣泛使用的展示頁面的api。以垂直滾動列表的形式展示條目。一般配合ListAdapter使用。
1.????????ListView的入門使用
創建項目,在UI文件創建一個Listview。
在入口方法中給ListView添加條目。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ListViewlistview = (ListView) findViewById(R.id.listview);//創建一個列表適配器,給listview提供數據listview.setAdapter(newMyListAdapter());}privateclass MyListAdapter extends BaseAdapter {@Overridepublic int getCount() {//TODO Auto-generated method stubreturn5;}@OverridepublicObject getItem(int position) {//TODO Auto-generated method stubreturnnull;}@Overridepubliclong getItemId(int position) {//TODO Auto-generated method stubreturn0;}@OverridepublicView getView(int position, View convertView, ViewGroup parent) {//TODO Auto-generated method stubTextViewtextview1 = new TextView(MainActivity.this);textview1.setText("這是第" + position + "個條目");returntextview1;}}}在上述的例子中,如果給ListView添加大量的條目,那么在使用app的過程中,如果快速的滾動條目,會由于dvm來不及回收滾出屏幕的條目的占用的內存資源,而導致出現內存溢出的異常。
優化的方法是,一個屏幕能夠顯示的條目的量是有限的,對于大量的條目,比如說100000條,如果每條都創建一個TextView對象,就容易造成垃圾回收不及時的內存溢出,可以創建屏幕最大顯示量稍多的TextView的數量,然后重復利用這些TextView而不回收。android的ListAdapter提供了實現這樣操作的方法。
主要就是修改ListAdapter的getView方法
?? ???????? public ViewgetView(int position, View convertView, ViewGroup parent) {//TODO Auto-generated method stubTextViewtextview1 = null;if(convertView == null) {//為空說明沒有可用的對象,則創建新的view對象textview1= new TextView(MainActivity.this);System.out.println("創建新的對象:" + position);}else {//如果不為空,則當前的converView可以重復使用textview1= (TextView) convertView;System.out.println("重用舊的對象");}textview1.setText("這是第" + position + "個條目");returntextview1;}}2.????????顯示復雜條目
創建項目,主界面UI添加一個ListView。
創建一個xml文件,作為ListView內條目的模版。
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="5dp"><ImageViewandroid:id="@+id/iv_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher"/><TextViewandroid:id="@+id/iv_title"android:layout_toRightOf="@id/iv_icon"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="標題"android:textSize="20sp"android:padding="5dp"/><TextViewandroid:id="@+id/iv_content"android:layout_toRightOf="@id/iv_icon"android:layout_below="@id/iv_title"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="內容內容"android:textSize="10sp"android:textColor="#88000000"android:padding="5dp"/></RelativeLayout>在入口方法中實現給UI添加模版條目。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ListViewlv_list = (ListView) findViewById(R.id.lv_list);lv_list.setAdapter(newMyAdapter());}privateclass MyAdapter extends BaseAdapter {@Overridepublicint getCount() {//TODO Auto-generated method stubreturn10;}@OverridepublicObject getItem(int position) {//TODO Auto-generated method stubreturnnull;}@Overridepubliclong getItemId(int position) {//TODO Auto-generated method stubreturn0;}@OverridepublicView getView(int position, View convertView, ViewGroup parent) {//TODO Auto-generated method stubViewview = null;if(convertView == null) {view= View.inflate(MainActivity.this, R.layout.item, null);}else {view= convertView;}returnview;}}}3.????????獲取LayoutInflate的三種方法
????? public View getView(int position, View convertView, ViewGroupparent) {//TODO Auto-generated method stubViewview = null;if(convertView == null) {//view = View.inflate(MainActivity.this, R.layout.item, null);LayoutInflaterinflater = LayoutInflater.from(MainActivity.this);view= inflater.inflate(R.layout.item, null);LayoutInflaterinflater2 = getLayoutInflater();//google的源代碼中使用getSystemService這個方法獲取的LayoutInflater,google推薦使用這個方法LayoutInflaterinflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);}else {view= convertView;}returnview;4.????????Adapter子類展示數據
一般使用ArrayAdapter和SimpleAdapter。ArrayAdapter適合數據比較簡單的布局,比如只有一個TextView的內容需要修改時。SimpleAdapter適合布局比較復雜的情況,比如一個新聞界面或博客文章界面等。
使用ArrayAdapter的例子。
創建項目,在主UIxml中添加一個ListView,創建一個只有一個TextView的線性布局文件。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher"/><TextViewandroid:id="@+id/tv_text"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout>在入口方法中,給UI添加數據。
???????? protectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ListViewlv_list = (ListView) findViewById(R.id.lv_list);String[]objects = { "hello", "爪哇", "安卓", "配合片", "磁盤片" };ArrayAdapter<String>adapter = new ArrayAdapter<String>(this,R.layout.item,objects);lv_list.setAdapter(adapter);ArrayAdapter<String>adapter2 = new ArrayAdapter<String>(this,R.layout.item2,R.id.tv_text, objects);lv_list.setAdapter(adapter2);}SimpleAdapter的例子
創建一個項目,在主UI添加一個ListView,創建一個item作為內容的模版。
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:padding="5dp" ><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher"/><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20sp"android:text="標題"/><TextViewandroid:id="@+id/tv_content"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="12sp"android:text="內容內容內容內容太"android:textColor="#88000000"android:layout_marginTop="2dp"/></LinearLayout></LinearLayout>在入口方法中給界面添加數據
?? protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ListViewlv_list = (ListView) findViewById(R.id.lv_list);List<Map<String,String>> data = new ArrayList<Map<String, String>>();String[]from = { "title", "content" };int[]to = { R.id.tv_title, R.id.tv_content };Map<String,String> item1 = new HashMap<String, String>();item1.put("title","新聞1");item1.put("content","內容1內容1內容1內容1");data.add(item1);Map<String,String> item2 = new HashMap<String, String>();item2.put("title","新聞2");item2.put("content","內容2內容2內容2內容2");data.add(item2);Map<String,String> item3 = new HashMap<String, String>();item3.put("title","新聞3");item3.put("content","內容3內容3內容3內容3");data.add(item3);SimpleAdapteradapter = new SimpleAdapter(this, data, R.layout.item,from,to);lv_list.setAdapter(adapter);}5.????????ListView展示數據庫數據
創建一個項目,創建UI主界面,里面兩個按鈕一個ListView。
創建一個javabean。
創建一個模版文件。
創建數據庫操作類。
public class MyOpenHelper extendsSQLiteOpenHelper {publicMyOpenHelper(Context context) {super(context,"ten.db", null, 1);//TODO Auto-generated constructor stub}@Overridepublicvoid onCreate(SQLiteDatabase db) {//TODO Auto-generated method stubdb.execSQL("createtable info(_id integer primary key autoincrement,name varchar(20),phonevarchar(20))");}@Overridepublicvoid onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//TODO Auto-generated method stub}}在主控件中編寫業務代碼
public class MainActivity extends Activity {privateMyOpenHelper openHelper;privateArrayList<User> userList = new ArrayList<User>();privateListView lv_list;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv_list= (ListView) findViewById(R.id.lv_list);Buttonbtn_insert = (Button) findViewById(R.id.btn_insert);Buttonbtn_query = (Button) findViewById(R.id.btn_query);openHelper= new MyOpenHelper(this);}publicvoid insert(View v) {SQLiteDatabasedatabase = openHelper.getWritableDatabase();database.execSQL("insertinto info values(null,'照樣','12342')");database.execSQL("insertinto info values(null,'上述','345334')");database.execSQL("insertinto info values(null,'滾動','5676765')");database.execSQL("insertinto info values(null,'更好','4565645')");database.execSQL("insertinto info values(null,'改天','4586786')");database.close();}publicvoid query(View v) {SQLiteDatabasedatabase = openHelper.getWritableDatabase();Cursorresult = database.rawQuery("select * from info", null);while(result.moveToNext()) {Useruser = new User();intid = result.getInt(result.getColumnIndex("_id"));Stringname = result.getString(result.getColumnIndex("name"));Stringphone = result.getString(result.getColumnIndex("phone"));user.id = id;user.name= name;user.phone= phone;userList.add(user);}result.close();database.close();for(User user : userList) {System.out.println(user);}lv_list.setAdapter(newMyAdapter());}privateclass MyAdapter extends BaseAdapter {@Overridepublicint getCount() {//TODO Auto-generated method stubreturnuserList.size();}@OverridepublicObject getItem(int position) {//TODO Auto-generated method stubreturnuserList.get(position);}@Overridepubliclong getItemId(int position) {//TODO Auto-generated method stubreturnposition;}@OverridepublicView getView(int position, View convertView, ViewGroup parent) {//TODO Auto-generated method stubViewview = null;if(convertView == null) {view= View.inflate(MainActivity.this, R.layout.item, null);}else {view= convertView;}TextViewtv_name = (TextView) view.findViewById(R.id.tv_name);TextViewtv_phone = (TextView) view.findViewById(R.id.tv_phone);tv_name.setText(userList.get(position).name);tv_phone.setText(userList.get(position).phone);returnview;}}}四、? 網絡編程
關于網絡方面的編程。
1.????????網頁源碼查看器
創建項目,設計UI
<RelativeLayoutxmlns: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="com.example.htmlcodeviewer.MainActivity" ><EditTextandroid:id="@+id/et_url"android:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="textUri"android:hint="請輸入網址"/><Buttonandroid:id="@+id/btn_show"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="查看"android:layout_below="@id/et_url"/><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_below="@id/btn_show"><TextViewandroid:id="@+id/tv_code"android:layout_width="match_parent"android:layout_height="match_parent"???/></ScrollView>???????</RelativeLayout>編寫入口方法
public class MainActivity extends Activity {privateEditText et_url;privateButton btn_show;privateTextView tv_code;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if(android.os.Build.VERSION.SDK_INT > 9) {StrictMode.ThreadPolicypolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();StrictMode.setThreadPolicy(policy);}et_url= (EditText) findViewById(R.id.et_url);btn_show= (Button) findViewById(R.id.btn_show);tv_code= (TextView) findViewById(R.id.tv_code);btn_show.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringurlStr = et_url.getText().toString().trim();if(urlStr == null) {return;}else {try{URLurl = new URL(urlStr);HttpURLConnectionurlConnection = (HttpURLConnection) url.openConnection();urlConnection.setRequestMethod("GET");urlConnection.setConnectTimeout(10000);intresCode = urlConnection.getResponseCode();if(resCode == 200) {InputStreaminputStream = urlConnection.getInputStream();Stringresult = Utils.getStringFromStream(inputStream);tv_code.setText(result);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}});}}編寫將流轉化為字符串的工具類
public class Utils {publicstatic String getStringFromStream(InputStream inputStream) {//TODO Auto-generated method stubByteArrayOutputStreambaos = new ByteArrayOutputStream();intlen = -1;byte[]buffer = new byte[1024];try{while((len = inputStream.read(buffer)) != -1) {baos.write(buffer,0, len);}inputStream.close();byte[]byteArray = baos.toByteArray();returnnew String(byteArray, "utf-8");}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();returnnull;}}}2.????????android4.0以上主線程聯網問題
聯網是一個比較耗時的操作。4.0后聯網必須要在子線程中,否則拋出android.os.NetworkOnMainThreadException。如果主線程被阻塞5秒以上,就會拋出Activity/Application? not?responding,ANR異常。如果多次拋出ANR異常,會降低產品的可靠度,導致被用戶拋棄。為了避免ANR,需要把耗時的操作放到子線程中,聯網就是一種耗時的操作。為了改善使用體驗,4.0后聯網必須要在子線程中實現。為了減少內存開銷,可以使用匿名內部類的方式,在主線程方法中開啟子線程聯網。
需要注意的是子線程不能修改UI,需要在主線程中修改,這是因為多線程中容易出現安全問題,為了避免多個線程修改同一個UI導致矛盾的UI,所以這樣規定,修改UI只能通過主線程,所以主線程又叫UI線程。由于數據是在子線程中獲取的,但是子線程不能修改UI,所以需要跨線程傳遞數據,通知主線程獲取數據并給主線程數據,需要使用Handler類。
public class MainActivity extends Activity {privateEditText et_url;privateButton btn_show;privateTextView tv_code;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {super.handleMessage(msg);tv_code.setText((String)msg.obj);};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//if (android.os.Build.VERSION.SDK_INT > 9) {//StrictMode.ThreadPolicy policy = new//StrictMode.ThreadPolicy.Builder()//.permitAll().build();//StrictMode.setThreadPolicy(policy);//}Stringname = Thread.currentThread().getName();Toast.makeText(this,name, Toast.LENGTH_SHORT).show();et_url= (EditText) findViewById(R.id.et_url);btn_show= (Button) findViewById(R.id.btn_show);tv_code= (TextView) findViewById(R.id.tv_code);btn_show.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {newThread() {publicvoid run() {StringurlStr = et_url.getText().toString().trim();if(urlStr == null) {return;}else {try{URLurl = new URL(urlStr);HttpURLConnectionurlConnection = (HttpURLConnection) url.openConnection();urlConnection.setRequestMethod("GET");urlConnection.setConnectTimeout(10000);intresCode = urlConnection.getResponseCode();if(resCode == 200) {InputStreaminputStream = urlConnection.getInputStream();Stringresult = Utils.getStringFromStream(inputStream);//子線程不能直接修改UI,通知主線程獲取數據,并且把數據給主線程//tv_code.setText(result);Messagemsg = new Message();msg.obj= result;handler.sendMessage(msg);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}}.start();//TODO Auto-generated method stub}});}}3.????????圖片查看器
使用消息機制獲取網絡資源圖片。
public class MainActivity extends Activityimplements OnClickListener {privateEditText et_url;privateButton btn_show;privateImageView iv_pic;finalprivate int GET_DATA_SUCCESS = 1;finalprivate int INET_ERROR = 2;finalprivate int SERVER_ERROR = 3;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {switch(msg.what) {caseGET_DATA_SUCCESS:Bitmapbitmap = (Bitmap) msg.obj;iv_pic.setImageBitmap(bitmap);break;caseINET_ERROR:Toast.makeText(MainActivity.this,"網絡異常",Toast.LENGTH_SHORT).show();break;caseSERVER_ERROR:Toast.makeText(MainActivity.this,"服務器返回異常",Toast.LENGTH_SHORT).show();break;default:break;}};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_url= (EditText) findViewById(R.id.et_url);btn_show= (Button) findViewById(R.id.btn_show);iv_pic= (ImageView) findViewById(R.id.iv_pic);btn_show.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubnewThread() {publicvoid run() {Stringpath = et_url.getText().toString().trim();try{URLurl = new URL(path);HttpURLConnection connection= (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setReadTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = connection.getInputStream();Bitmapbitmap = BitmapFactory.decodeStream(inputStream);Messagemsg = Message.obtain();msg.what= GET_DATA_SUCCESS;msg.obj= bitmap;handler.sendMessage(msg);}else {Messagemsg = Message.obtain();msg.what= SERVER_ERROR;handler.sendMessage(msg);}}catch (Exception e) {//TODO Auto-generated catch blockMessagemsg = Message.obtain();msg.what= INET_ERROR;handler.sendMessage(msg);}};}.start();}}4.????????給圖片查看器添加圖片緩存
在獲取圖片的輸入流之后,輸出到文件,保存在設備中。
public class MainActivity extends Activityimplements OnClickListener {privateEditText et_url;privateButton btn_show;privateImageView iv_pic;finalprivate int GET_DATA_SUCCESS = 1;finalprivate int INET_ERROR = 2;finalprivate int SERVER_ERROR = 3;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {switch(msg.what) {caseGET_DATA_SUCCESS:Bitmapbitmap = (Bitmap) msg.obj;iv_pic.setImageBitmap(bitmap);Toast.makeText(MainActivity.this,"從網絡獲取",Toast.LENGTH_SHORT).show();break;caseINET_ERROR:Toast.makeText(MainActivity.this,"網絡異常",Toast.LENGTH_SHORT).show();break;caseSERVER_ERROR:Toast.makeText(MainActivity.this,"服務器返回異常",Toast.LENGTH_SHORT).show();break;default:break;}};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_url= (EditText) findViewById(R.id.et_url);btn_show= (Button) findViewById(R.id.btn_show);iv_pic= (ImageView) findViewById(R.id.iv_pic);btn_show.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubfinalFile file = new File(getCacheDir(), "tomcat.png");if(file != null && file.length() > 0) {Bitmapbitmap = BitmapFactory.decodeFile(file.getAbsolutePath());iv_pic.setImageBitmap(bitmap);Toast.makeText(this,"使用緩存",Toast.LENGTH_SHORT).show();return;}newThread() {publicvoid run() {Stringpath = et_url.getText().toString().trim();try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setReadTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = connection.getInputStream();FileOutputStreamfos = new FileOutputStream(file);byte[]bts = new byte[1024];intlen = -1;while((len = inputStream.read(bts)) != -1) {fos.write(bts,0, len);}fos.close();//Bitmap bitmap =//BitmapFactory.decodeStream(inputStream);Bitmapbitmap = BitmapFactory.decodeFile(file.getAbsolutePath());Messagemsg = Message.obtain();msg.what= GET_DATA_SUCCESS;msg.obj= bitmap;handler.sendMessage(msg);}else {Messagemsg = Message.obtain();msg.what= SERVER_ERROR;handler.sendMessage(msg);}}catch (Exception e) {//TODO Auto-generated catch blockMessagemsg = Message.obtain();msg.what= INET_ERROR;handler.sendMessage(msg);}};}.start();}}5.????????Handler的第二個常用功能,在未來的某個時間執行一個消息
這個功能相當于延遲執行消息,可以用來做倒計時、定時發布等。
public class MainActivity extends Activity {privateTextView tv_text;privateint count = 60;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {countDown();};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_text= (TextView) findViewById(R.id.tv_text);Messagemsg = Message.obtain();handler.sendMessageDelayed(msg,1000);}publicvoid countDown() {count--;if(count == -1) {Toast.makeText(this,"時間到",Toast.LENGTH_SHORT).show();return;}tv_text.setText(Integer.toString(count));Messagemsg = Message.obtain();handler.sendMessageDelayed(msg,1000);}}可以使用sendEmptyMessageDelayed()來簡化操作。
public class MainActivity extends Activity {privateTextView tv_text;privateint count = 60;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {countDown();};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_text= (TextView) findViewById(R.id.tv_text);//Message msg = Message.obtain();//handler.sendMessageDelayed(msg, 1000);handler.sendEmptyMessageDelayed(1,1000);}publicvoid countDown() {count--;if(count < 0) {Toast.makeText(this,"時間到",Toast.LENGTH_SHORT).show();return;}else {tv_text.setText(Integer.toString(count));//Message msg = Message.obtain();//handler.sendMessageDelayed(msg, 1000);handler.sendEmptyMessageDelayed(1,1000);}}}6.????????runOnUiThread方法
Activity的一個方法,作用是可以讓其中的Runnable對象的方法運行在UI線程中。如果當前線程是主線程,則立即執行run方法;如果不是,就會把Runnable對象丟到消息隊列,最終在主線程中執行。
runOnUiThread(newRunnable() {@Overridepublicvoid run() {//TODO Auto-generated method stub//無論這個方法在那個線程,這里的代碼一定會執行在主線程里Toast.makeText(MainActivity.this,"網路連接失敗", Toast.LENGTH_SHORT).show();}});如果子線程也想更新UI,如果是比較簡單的業務邏輯,可以使用runOnUiThread()。
7.????????新聞客戶端
創建項目,設計UI,在主控件中添加一個ListView。準備偽服務端數據xml文件和圖片,放到tomcat的webapps的ROOT目錄下。
然后,創建條目模版。為了方便獲取圖片,使用了開源項目android-smart-image-view-1.0.0。
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content" ><com.loopj.android.image.SmartImageViewandroid:id="@+id/iv_icon"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher"/><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/iv_icon"android:text="標題"android:layout_marginLeft="5dp"android:textSize="16sp"/><TextViewandroid:id="@+id/tv_content"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_toRightOf="@id/iv_icon"android:layout_below="@id/tv_title"android:text="內容內容內容"android:layout_marginLeft="5dp"android:textSize="12sp"/><TextViewandroid:id="@+id/tv_comment"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/tv_content"android:layout_alignParentRight="true"android:text="評論"android:textSize="10sp"/></RelativeLayout>創建條目的javabean文件
public class NewsItem {publicString title;publicString description;publicString img;publicString type;publicString comment;@OverridepublicString toString() {return"NewsItem [title=" + title + ", description=" + description+", img=" + img + ", type=" + type + ", comment="+ comment+"]";}}編寫業務邏輯
public class MainActivity extends Activity {protectedstatic final int GET_DATA = 1;privateListView lv_list;privateString path = "http://192.168.0.100:8080/news.xml";privateArrayList<NewsItem> itemList = new ArrayList<NewsItem>();privateMyAdapter adapter;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {switch(msg.what) {case GET_DATA:lv_list.setAdapter(adapter);break;}};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv_list= (ListView) findViewById(R.id.lv_list);adapter= new MyAdapter();initData();}privatevoid initData() {//TODO Auto-generated method stubnewThread() {publicvoid run() {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = connection.getInputStream();XmlPullParserpullParser = Xml.newPullParser();pullParser.setInput(inputStream,"utf-8");inteventType = pullParser.getEventType();NewsItemitem = null;while(eventType != XmlPullParser.END_DOCUMENT) {switch(eventType) {caseXmlPullParser.START_TAG:if("item".equals(pullParser.getName())) {item= new NewsItem();}else if ("title".equals(pullParser.getName())) {item.title= pullParser.nextText();}else if ("description".equals(pullParser.getName())){item.description= pullParser.nextText();}else if ("image".equals(pullParser.getName())) {item.img= pullParser.nextText();}else if ("type".equals(pullParser.getName())) {item.type= pullParser.nextText();}else if ("comment".equals(pullParser.getName())){item.comment= pullParser.nextText();}break;caseXmlPullParser.END_TAG:if("item".equals(pullParser.getName())) {itemList.add(item);}break;default:break;}eventType= pullParser.next();}for(NewsItem news : itemList) {System.out.println(news);}handler.sendEmptyMessage(GET_DATA);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}};}.start();}privateclass MyAdapter extends BaseAdapter {@Overridepublicint getCount() {//TODO Auto-generated method stubreturnitemList.size();}@OverridepublicObject getItem(int position) {//TODO Auto-generated method stubreturnitemList.get(position);}@Overridepubliclong getItemId(int position) {//TODO Auto-generated method stubreturnposition;}@OverridepublicView getView(int position, View convertView, ViewGroup parent) {//TODO Auto-generated method stubViewview = null;if(convertView == null) {view= View.inflate(MainActivity.this, R.layout.item, null);}else {view= (View) convertView;}TextViewtv_title = (TextView) view.findViewById(R.id.tv_title);TextViewtv_content = (TextView) view.findViewById(R.id.tv_content);TextViewtv_comment = (TextView) view.findViewById(R.id.tv_comment);SmartImageViewiv_icon = (SmartImageView) view.findViewById(R.id.iv_icon);NewsItemitem = itemList.get(position);tv_title.setText(item.title);tv_content.setText(item.description);if("1".equals(item.type)) {tv_comment.setText(item.comment+ "條評論");tv_comment.setTextColor(Color.BLACK);}else if ("2".equals(item.type)) {tv_comment.setText("獨家");tv_comment.setTextColor(Color.RED);}else if ("3".equals(item.type)) {tv_comment.setText("專題");tv_comment.setTextColor(Color.BLUE);}else if ("4".equals(item.type)) {tv_comment.setText("專欄");tv_comment.setTextColor(Color.CYAN);}iv_icon.setImageUrl(item.img);returnview;}}}8.????????自定義實現SmartImageView的加載圖片功能
也是繼承ImageView,自定義設置圖片url的方法。
創建一個MySmartImageView類,設計使用自定義ImageView的UI。
<RelativeLayoutxmlns: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="com.example.mysmartimageview.MainActivity" ><com.example.mysmartimageview.MySmartImageViewandroid:id="@+id/siv_pic"android:layout_width="wrap_content"android:layout_height="wrap_content"/></RelativeLayout>編寫自定義類的方法
public class MySmartImageView extends ImageView{protectedstatic final int GET_PIC_SUCCESS = 1;protectedstatic final int GET_PIC_FAILED = -1;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {switch(msg.what) {caseGET_PIC_SUCCESS:Bitmapbm = (Bitmap) msg.obj;setImageBitmap(bm);break;caseGET_PIC_FAILED:setImageResource(msg.arg1);break;}};};publicMySmartImageView(Context context) {super(context);//TODO Auto-generated constructor stub}publicMySmartImageView(Context context, AttributeSet attrs) {super(context,attrs);//TODO Auto-generated constructor stub}publicMySmartImageView(Context context, AttributeSet attrs, int defStyle) {super(context,attrs, defStyle);//TODO Auto-generated constructor stub}publicvoid setImageUrl(final String path) {newThread() {publicvoid run() {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = connection.getInputStream();Bitmapbitmap = BitmapFactory.decodeStream(inputStream);Messagemsg = Message.obtain();msg.obj= bitmap;handler.sendMessage(msg);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}.start();}//設置默認圖方法publicvoid setImageUrl(final String path, final int resId) {newThread() {publicvoid run() {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = connection.getInputStream();Bitmapbitmap = BitmapFactory.decodeStream(inputStream);Messagemsg = Message.obtain();msg.what= GET_PIC_SUCCESS;msg.obj= bitmap;handler.sendMessage(msg);}else {//沒有成功獲取到圖片Messagemsg = Message.obtain();msg.what= GET_PIC_FAILED;msg.arg1= resId;handler.sendMessage(msg);}}catch (Exception e) {//TODO Auto-generated catch blockMessagemsg = Message.obtain();msg.what= GET_PIC_FAILED;msg.arg1= resId;handler.sendMessage(msg);}}}.start();}}在入口方法中測試
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MySmartImageViewsiv_pic = (MySmartImageView) findViewById(R.id.siv_pic);//siv_pic.setImageUrl("http://192.168.0.100:8080/img/c.jpg");siv_pic.setImageUrl("http://192.168.0.100:8080/img/c.jpg",R.drawable.ic_launcher);}}9.????????使用HttpURLConnection提交參數到服務端
創建一個項目,編寫一個用戶登陸的UI界面。
使用get方式提交參數。
編寫業務邏輯
public class MainActivity extends Activityimplements OnClickListener {privateString path = "http://192.168.0.100:8080/login/LoginServlet";privateEditText et_username;privateEditText et_password;privateButton btn_login;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_username= (EditText) findViewById(R.id.et_username);et_password= (EditText) findViewById(R.id.et_password);btn_login= (Button) findViewById(R.id.btn_login);btn_login.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubnewThread() {publicvoid run() {Stringusername = et_username.getText().toString().trim();Stringpassword = et_password.getText().toString().trim();if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {showToast("用戶名或密碼不能為空");return;}StringtempPath = path + "?username=" + username +"&password="+password;try{URLurl = new URL(tempPath);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = (InputStream) connection.getInputStream();Stringresult = Utils.getStringFromStream(inputStream);showToast(result);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}};}.start();}privatevoid showToast(final String str) {runOnUiThread(newRunnable() {@Overridepublicvoid run() {//TODO Auto-generated method stubToast.makeText(MainActivity.this,str, Toast.LENGTH_SHORT).show();}});}}解決上述業務中的get參數到服務端的中文亂碼問題
String tempPath = path + "?username="+ URLEncoder.encode(username, "utf-8") + "&password=" +?URLEncoder.encode(password,"utf-8");
使用post方式提交參數
在UI界面添加一個做post提交登陸的按鈕。
?? new Thread() {publicvoid run() {Stringusername = et_username.getText().toString().trim();Stringpassword = et_password.getText().toString().trim();if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)) {showToast("用戶名或密碼不能為空");return;}try{Stringparams = "username="+URLEncoder.encode(username, "utf-8")+"&password="+URLEncoder.encode(password, "utf-8");URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("POST");connection.setConnectTimeout(10000);//設置post請求相關的請求頭connection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");connection.setRequestProperty("Content-Length",Integer.toString(params.length()));connection.setDoOutput(true);connection.getOutputStream().write(params.getBytes());intcode = connection.getResponseCode();if(code == 200) {InputStreaminputStream = (InputStream) connection.getInputStream();Stringresult = Utils.getStringFromStream(inputStream);showToast(result);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}};}.start();注意由于使用url傳輸,需要使用UrlEncoder類編碼,以防止Content-Length出現異常。
10.?????HttpClient
HttpClient是封裝的http請求與響應操作的api,簡化了代碼。
創建項目,設計UI。
?編寫業務邏輯代碼。
public class MainActivity extends Activity {privateButton btn_loginPost;privateButton btn_login;privateEditText et_password;privateEditText et_username;privateString path = "http://192.168.0.100:8080/login/LoginServlet";@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_username= (EditText) findViewById(R.id.et_username);et_password= (EditText) findViewById(R.id.et_password);et_username.setText("abc哈哈");btn_login= (Button) findViewById(R.id.btn_login);btn_loginPost= (Button) findViewById(R.id.btn_loginPost);btn_login.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubnewThread() {publicvoid run() {Stringusername = et_username.getText().toString().trim();Stringpassword = et_password.getText().toString().trim();if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)) {showToast("用戶名或密碼不能為空");return;}try{DefaultHttpClienthttpClient = new DefaultHttpClient();Stringuri = path + "?username="+URLEncoder.encode(username, "utf-8")+"&password="+URLEncoder.encode(password, "utf-8");HttpGetrequest = new HttpGet(uri);HttpResponseresponse = httpClient.execute(request);intcode = response.getStatusLine().getStatusCode();if(code == 200) {InputStreaminputStream = response.getEntity().getContent();Stringresult = Utils.getStringFromStream(inputStream);showToast(result);}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}};}.start();}});btn_loginPost.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubnewThread() {publicvoid run() {Stringusername = et_username.getText().toString().trim();Stringpassword = et_password.getText().toString().trim();if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)) {showToast("用戶名或密碼不能為空");return;}try{DefaultHttpClienthttpClient = new DefaultHttpClient();HttpPostpost = new HttpPost(path);List<BasicNameValuePair>parameters = new ArrayList<BasicNameValuePair>();BasicNameValuePairusernamePair = new BasicNameValuePair("username",username);BasicNameValuePairpasswordPair = new BasicNameValuePair("password",password);parameters.add(usernamePair);parameters.add(passwordPair);HttpEntityentity = new UrlEncodedFormEntity(parameters,"utf-8");post.setEntity(entity);HttpResponseresponse = httpClient.execute(post);intcode = response.getStatusLine().getStatusCode();if(code == 200) {InputStreaminputStream = response.getEntity().getContent();Stringresult = Utils.getStringFromStream(inputStream);showToast(result);}}catch (Exception e) {e.printStackTrace();}};}.start();}});}publicvoid showToast(final String str) {runOnUiThread(newRunnable() {@Overridepublicvoid run() {//TODO Auto-generated method stubToast.makeText(MainActivity.this,str, Toast.LENGTH_SHORT).show();}});}}11.?????使用開源項目提交參數
使用android-async-http-1.4.8。1.4.9會報莫名其妙的錯誤。
業務邏輯代碼
public class MainActivity extends Activity {privateEditText et_username;privateEditText et_password;privateButton btn_login;privateButton btn_loginPost;privateString path = "http://192.168.0.100:8080/login/LoginServlet";@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_username= (EditText) findViewById(R.id.et_username);et_password= (EditText) findViewById(R.id.et_password);et_username.setText("abc哈哈");btn_login= (Button) findViewById(R.id.btn_login);btn_loginPost= (Button) findViewById(R.id.btn_loginPost);btn_login.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringusername = et_username.getText().toString().trim();Stringpassword = et_password.getText().toString().trim();if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {showToast("用戶名或密碼不能為空");return;}Stringurl;try{url= path + "?username="+URLEncoder.encode(username, "utf-8")+"&password="+URLEncoder.encode(password, "utf-8");AsyncHttpClientclient = new AsyncHttpClient();client.get(url,new AsyncHttpResponseHandler() {@Overridepublicvoid onSuccess(int arg0, Header[] arg1,byte[]response) {//TODO Auto-generated method stubtry{Stringresult = new String(response, "utf-8");showToast(result);}catch (UnsupportedEncodingException e) {//TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublicvoid onFailure(int arg0, Header[] arg1,byte[]arg2, Throwable arg3) {//TODO Auto-generated method stub}});}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}});btn_loginPost.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringusername = et_username.getText().toString().trim();Stringpassword = et_password.getText().toString().trim();if(TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {showToast("用戶名或密碼不能為空");return;}AsyncHttpClientclient = new AsyncHttpClient();RequestParamsparams = new RequestParams();params.put("username",username);params.put("password",password);client.post(path,params, new AsyncHttpResponseHandler() {@Overridepublicvoid onSuccess(int arg0, Header[] arg1,byte[]response) {//TODO Auto-generated method stubStringresult;try{result= new String(response, "utf-8");showToast(result);}catch (UnsupportedEncodingException e) {//TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublicvoid onFailure(int arg0, Header[] arg1, byte[] arg2,Throwablearg3) {//TODO Auto-generated method stub}});}});}publicvoid showToast(final String str) {runOnUiThread(newRunnable() {@Overridepublicvoid run() {//TODO Auto-generated method stubToast.makeText(MainActivity.this,str, Toast.LENGTH_SHORT).show();}});}privateclass MyHandler extends AsyncHttpResponseHandler {@Overridepublicvoid onFailure(int arg0, Header[] arg1, byte[] arg2,Throwablearg3) {//TODO Auto-generated method stub}@Overridepublicvoid onSuccess(int arg0, Header[] arg1, byte[] response) {//TODO Auto-generated method stubtry{Stringresult = new String(response, "utf-8");showToast(result);}catch (UnsupportedEncodingException e) {// TODO Auto-generated catchblocke.printStackTrace();}}}}12.?????多線程下載
使用多線程下載在帶寬限制內可以提高下載速度。使用多線程下載,要求服務端支持多線程讀,客戶端支持多線程寫,具體就是,服務端支持conn.setRequestProperty(“Range”,…);客戶端使用javaSE的RandomAccessFile對象,隨機讀寫文件的任意位置。
創建一個項目,編寫下載的java代碼。
public class MultiThreadDownload {privatestatic String path = "http://192.168.0.100:8080/xfplay9.9991.exe";privatestatic int threadCount = 3;publicstatic void main(String[] args) {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {intfileLength = connection.getContentLength();StringfileName = getFileName(path);RandomAccessFilefile = new RandomAccessFile(fileName, "rw");file.setLength(fileLength);intblockSize = fileLength / threadCount;for(int i = 0; i < threadCount; i++) {intstartIndex = i * blockSize;intendIndex = startIndex + blockSize - 1;if(i == threadCount - 1) {endIndex =fileLength - 1;}newDownloadThread(startIndex, endIndex, i).start();}}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}privatestatic class DownloadThread extends Thread {privateint startIndex;privateint endIndex;privateint threadID;publicDownloadThread(int startIndex, int endIndex, int threadID) {super();this.startIndex= startIndex;this.endIndex= endIndex;this.threadID= threadID;}publicvoid run() {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);connection.setRequestProperty("Range","bytes=" + startIndex+"-" + endIndex);if(connection.getResponseCode() == 206) {System.out.println("線程:" + threadID);InputStreaminputStream = connection.getInputStream();intlen = -1;byte[]bytes = new byte[1024];RandomAccessFilefile = new RandomAccessFile(getFileName(path),"rw");file.seek(startIndex);while((len = inputStream.read(bytes)) != -1) {file.write(bytes,0, len);}file.close();System.out.println("線程:" + threadID + "下載結束");}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}publicstatic String getFileName(String path) {String[]result = path.split("/");returnresult[result.length - 1];}}13.?????斷點續傳
從意外或非意外導致的中斷的位置,在下一次傳輸時繼續傳。比如某些下載軟件,下載一個大的文件,下載了一半后,先暫停,然后關閉了計算機,下次打開計算機,打開軟件,可以接著繼續下載,就是斷點續傳。或者,在下載過程中,意外關機了,再次開機后,接著下載也是斷點續傳。
實現斷點續傳的原理是通過一個日志文件記錄每個線程下載了多少數據,中斷后再次下載,讀取日志文件從記錄下的文件讀取數據作為開始寫入的文件。需要注意的是,日志文件的保存最好使用RandomAccessFile的rwd模式確保每次寫入都同步保存到磁盤而不是磁盤的緩存。
public class MultiThreadDownload2 {privatestatic String path = "http://192.168.0.100:8080/xfplay9.9991.exe";privatestatic int threadCount = 3;publicstatic void main(String[] args) {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {intfileLength = connection.getContentLength();StringfileName = getFileName(path);RandomAccessFilefile = new RandomAccessFile(fileName, "rw");file.setLength(fileLength);intblockSize = fileLength / threadCount;for(int i = 0; i < threadCount; i++) {intstartIndex = i * blockSize;intendIndex = startIndex + blockSize - 1;if(i == threadCount - 1) {endIndex= fileLength - 1;}newDownloadThread(startIndex, endIndex, i).start();}}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}privatestatic class DownloadThread extends Thread {privateint startIndex;privateint endIndex;privateint threadID;publicDownloadThread(int startIndex, int endIndex, int threadID) {super();this.startIndex= startIndex;this.endIndex= endIndex;this.threadID= threadID;}publicvoid run() {try{//讀出記錄下來的位置FilebreakPointFile = new File(getFileName(path) + threadID+".log");if(breakPointFile != null && breakPointFile.length() > 0) {FileInputStreamfis = new FileInputStream(breakPointFile);byte[]bts = new byte[1024];intlen = -1;StringBuildersb = new StringBuilder();while((len = fis.read(bts)) != -1) {sb.append(newString(bts, 0, len));}startIndex= Integer.parseInt(sb.toString());}System.out.println(startIndex);URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);connection.setRequestProperty("Range","bytes=" + startIndex+"-" + endIndex);if(connection.getResponseCode() == 206) {System.out.println("線程:" + threadID + "開始下載" + startIndex);InputStreaminputStream = connection.getInputStream();intlen = -1;byte[]bytes = new byte[1024];RandomAccessFilefile = new RandomAccessFile(getFileName(path),"rw");file.seek(startIndex);intcount = 0;while((len = inputStream.read(bytes)) != -1) {file.write(bytes,0, len);count+= len;intposition = count + startIndex;RandomAccessFiletemp = new RandomAccessFile(getFileName(path)+ threadID + ".log", "rwd");temp.write(String.valueOf(position).getBytes());}file.close();System.out.println("線程:" + threadID + "下載結束");}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}publicstatic String getFileName(String path) {String[]result = path.split("/");returnresult[result.length - 1];}}14.?????android實現多線程下載
創建項目,設計UI。
<LinearLayoutxmlns: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"android:orientation="vertical"tools:context="com.example.multithreaddownloadandroid.MainActivity"><EditTextandroid:id="@+id/et_url"android:layout_width="match_parent"android:layout_height="wrap_content"android:inputType="textUri"android:hint="請輸入地址"/><EditTextandroid:id="@+id/et_count"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="請輸入線程個數"/><Buttonandroid:id="@+id/btn_download"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下載" /><LinearLayoutandroid:id="@+id/ll_progress"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"></LinearLayout></LinearLayout>創建進度條文件
<?xml version="1.0"encoding="utf-8"?><ProgressBarxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp"style="@android:style/Widget.ProgressBar.Horizontal"></ProgressBar>編寫業務代碼
public class MainActivity extends Activityimplements OnClickListener {privateEditText et_url;privateEditText et_count;privateButton btn_download;privateLinearLayout ll_progress;privateString path;privateint threadCount;privateint blockSize;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_url= (EditText) findViewById(R.id.et_url);et_count= (EditText) findViewById(R.id.et_count);btn_download= (Button) findViewById(R.id.btn_download);ll_progress= (LinearLayout) findViewById(R.id.ll_progress);btn_download.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubpath= et_url.getText().toString().trim();ll_progress.removeAllViews();StringcountStr = et_count.getText().toString().trim();intcount = Integer.parseInt(countStr);threadCount= count;for(int i = 0; i < count; i++) {View.inflate(getApplicationContext(),R.layout.item, ll_progress);}newThread() {publicvoid run() {try{URLurl = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);intcode = connection.getResponseCode();if(code == 200) {intfileLength = connection.getContentLength();StringfileName = getFileName(path);RandomAccessFilefile = new RandomAccessFile(fileName,"rw");file.setLength(fileLength);blockSize= fileLength / threadCount;for(int i = 0; i < threadCount; i++) {intstartIndex = i * blockSize;intendIndex = startIndex + blockSize - 1;if(i == threadCount - 1) {endIndex= fileLength - 1;}ProgressBarpb = (ProgressBar) ll_progress.getChildAt(i);pb.setMax(endIndex- startIndex);newDownloadThread(startIndex, endIndex, i).start();}}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}.start();}privateclass DownloadThread extends Thread {privateint startIndex;privateint endIndex;privateint threadID;privateProgressBar pb;publicDownloadThread(int startIndex, int endIndex, int threadID) {super();this.startIndex= startIndex;this.endIndex= endIndex;this.threadID= threadID;this.pb= (ProgressBar) ll_progress.getChildAt(threadID);}publicvoid run() {try{//讀出記錄下來的位置FilebreakPointFile = new File(getFileName(path) + threadID+".log");if(breakPointFile != null && breakPointFile.length() > 0) {FileInputStreamfis = new FileInputStream(breakPointFile);byte[]bts = new byte[1024];intlen = -1;StringBuildersb = new StringBuilder();while((len = fis.read(bts)) != -1) {sb.append(newString(bts, 0, len));}startIndex= Integer.parseInt(sb.toString());}System.out.println(startIndex);URL url = new URL(path);HttpURLConnectionconnection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);connection.setRequestProperty("Range","bytes=" + startIndex+"-" + endIndex);if(connection.getResponseCode() == 206) {System.out.println("線程:" + threadID + "開始下載" + startIndex);InputStreaminputStream = connection.getInputStream();intlen = -1;byte[]bytes = new byte[1024 * 500];RandomAccessFilefile = new RandomAccessFile(getFileName(path),"rw");file.seek(startIndex);intcount = 0;RandomAccessFiletemp = new RandomAccessFile(getFileName(path)+ threadID + ".log", "rwd");while((len = inputStream.read(bytes)) != -1) {file.write(bytes,0, len);count+= len;intposition = count + startIndex;pb.setProgress(position- threadID * blockSize);temp.write(String.valueOf(position).getBytes());}file.close();System.out.println("線程:" + threadID + "下載結束");if(breakPointFile != null) {breakPointFile.delete();}}}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}privateString getFileName(String path) {String[]result = path.split("/");returngetCacheDir().getAbsolutePath() + "/"+result[result.length - 1];}}15.?????使用開源項目實現多線程下載
使用XUtils-master。
創建項目,導入源碼,設計UI。
編寫業務邏輯
public class MainActivity extends Activity {privateEditText et_url;privateButton btn_download;privateProgressBar pb_progress;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_url= (EditText) findViewById(R.id.et_url);btn_download= (Button) findViewById(R.id.btn_download);pb_progress= (ProgressBar) findViewById(R.id.pb_progress);btn_download.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringpath = et_url.getText().toString().trim();HttpUtilsutils = new HttpUtils();utils.download(path,getFileName(path), true,newRequestCallBack<File>() {@Overridepublicvoid onSuccess(ResponseInfo<File>responseInfo) {//TODO Auto-generated method stubToast.makeText(MainActivity.this,"下載完成",Toast.LENGTH_SHORT).show();}@Overridepublicvoid onFailure(HttpException error,Stringmsg) {//TODO Auto-generated method stub}@Overridepublicvoid onLoading(long total, long current,booleanisUploading) {//TODO Auto-generated method stubpb_progress.setMax((int)total);pb_progress.setProgress((int)current);}});}});}privateString getFileName(String path) {String[]result = path.split("/");returngetCacheDir().getAbsolutePath() + "/"+result[result.length - 1];}}16.?????上下文
Application對象表示當前應用。生命周期最長。使用這個對象的getApplicationContext獲得的上下文的生命周期最長。使用getApplicationContext獲得的上下文隨應用的存亡,不會發生內存泄漏,相比使用this方法獲得上下文可能發生內存泄漏。大部分情況下使用getApplicationContext是安全的,但是操作對話框的使用this是安全的。
五、? Activity頁面跳轉和數據傳遞
Activity,是四大組件之一。
1.????????創建一個Activity
當創建一個項目時,會自動生成一個主Activity繼承自Activity。自己創建一個Activity。繼承Activity,重寫onCreate方法。
創建一個layout文件。
在android清單文件中,聲明對應的activity節點。在activity節點下,可以聲明一個intent-filter,如果intent-filter配置為下述內容,則這個activity會最為啟動項并在桌名創建一個圖標。
<intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER"/></intent-filter>在activity節點下可以聲明label、icon項,如果這個activity是啟動activity,則icon和label會顯示在桌名上,如果沒有聲明這兩項,則默認使用應用的label和icon。
??? <applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name=".MainActivity"android:label="第一個activity"android:icon="@drawable/a"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><activityandroid:name="com.example.createnewactivity.SecondActivity"android:label="第二個activity"android:icon="@drawable/b"><!-- <intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER"/></intent-filter> --></activity></application>2.????????隱式意圖打開activity
通過設置要跳轉到的頁面的意圖過濾器,在主界面或者跳轉前頁面中,通過匹配目標頁面的意圖過濾器,打開目標頁面activity。這種方式稱為隱式意圖方式。
????? ??<activityandroid:name="com.example.createnewactivity.SecondActivity"android:label="第二個activity"android:icon="@drawable/b"><intent-filter><actionandroid:name="com.ten.second"/><categoryandroid:name="android.intent.category.DEFAULT" /><dataandroid:scheme="hello"/></intent-filter><intent-filter><actionandroid:name="com.ten.second2"/><categoryandroid:name="android.intent.category.DEFAULT" /><dataandroid:scheme="hello"android:mimeType="he/hehe"/></intent-filter></activity>可以設置多個意圖過濾器,通過匹配這些過濾器都可以打開activity
?? protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_open= (Button) findViewById(R.id.btn_open);btn_open.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubIntentintent = new Intent();intent.setAction("com.ten.second");intent.setData(Uri.parse("hello:world"));startActivity(intent);}});btn_open2= (Button) findViewById(R.id.btn_open2);btn_open2.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubIntentintent = new Intent();intent.setAction("com.ten.second2");//intent.setData(Uri.parse("hello:world"));//intent.setType("he/hehe");intent.setDataAndType(Uri.parse("hello:world"),"he/hehe");startActivity(intent);}});}3.????????顯式意圖打開activity
顯式意圖就是在創建意圖時或者創建意圖后,指定要打開的activity的類字節碼文件或者包名類名來打開。需要在清單文件中聲明要打開的activity。
創建一個activity及其xml文件,在清單文件中聲明這個activity。
<activityandroid:name="com.example.createnewactivity.ThirdActivity"></activity>
在打開前頁面設置按鈕,為按鈕添加顯示意圖。
???????? publicvoid onClick(View v) {//TODO Auto-generated method stubIntentintent = new Intent(getApplicationContext(), ThirdActivity.class);startActivity(intent);}publicvoid otherApp(View v) {Intentintent = new Intent();intent.setClassName("com.example.httpclientcommitparams","com.example.httpclientcommitparams.MainActivity");startActivity(intent);}一般,在應用中打開activity使用顯示意圖。如果需要其他應用打開本應用的activity使用隱式意圖,以便不隨意泄漏本應用的包名和類名信息,或者要開啟別的應用的activity使用隱式意圖。
4.????????隨機計算小程序
設計一個小程序,輸入姓名性別,然后將數據傳遞到另一個界面,給出一個隨機數。
創建項目,設計兩個activity的UI。
登陸界面的activity
public class MainActivity extends Activityimplements OnClickListener {privateButton btn_calc;privateRadioGroup gb_gender;privateEditText et_name;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_name= (EditText) findViewById(R.id.et_name);gb_gender= (RadioGroup) findViewById(R.id.rg_gender);btn_calc= (Button) findViewById(R.id.btn_calc);btn_calc.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringname = et_name.getText().toString().trim();intgender_id = gb_gender.getCheckedRadioButtonId();Stringsex = null;if(gender_id == R.id.rb_male) {sex= "男";}else if (gender_id == R.id.rb_female) {sex= "女";}Intentintent = new Intent(getApplicationContext(),ResultActivity.class);intent.putExtra("name",name);intent.putExtra("gender",sex);startActivity(intent);}}跳轉頁面的activity,注意在清單中添加這個activity的聲明。
public class ResultActivity extends Activity {privateTextView tv_info;privateTextView tv_result;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {//TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_result);Intentintent = getIntent();Stringname = intent.getStringExtra("name");Stringsex = intent.getStringExtra("gender");Stringinfo = "姓名:" + name +";性別:" + sex;tv_info= (TextView) findViewById(R.id.tv_info);tv_result= (TextView) findViewById(R.id.tv_result);tv_info.setText(info);intresult = (int) (Math.random() * 100) + 1;tv_result.setText(Integer.toString(result));}}5.????????短信大全小程序
使用條目的點擊事件。
創建項目,設計UI,編寫條目模版。
編寫業務邏輯。
public class MainActivity extends Activity {privateString[] msgs = { "彩旗飄飄風中舞,男女老少喜盈盈。","北風呼嘯不可畏,元旦到來春光近。","煩惱不順如云煙,立刻消散好運臨。", "氣象更新今日始,幸福快樂新年迎。祝元旦快樂!", "北風呼嘯不可畏,元旦到來春光近。","煩惱不順如云煙,立刻消散好運臨。", "氣象更新今日始,幸福快樂新年迎。祝元旦快樂!", "北風呼嘯不可畏,元旦到來春光近。","煩惱不順如云煙,立刻消散好運臨。", "氣象更新今日始,幸福快樂新年迎。祝元旦快樂!" };privateListView lv_list;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);lv_list= (ListView) findViewById(R.id.lv_sms);ArrayAdapter<String>adapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.item, msgs);lv_list.setAdapter(adapter);lv_list.setOnItemClickListener(newOnItemClickListener() {@Overridepublicvoid onItemClick(AdapterView<?> parent, View view,intposition, long id) {//TODO Auto-generated method stubStringmsg = msgs[position];System.out.println(msg);Intentintent = new Intent();intent.setAction("android.intent.action.SEND");intent.setType("text/plain");intent.putExtra("sms_body",msg);startActivity(intent);}});}}6.????????短信發送器小程序
通過按鈕添加聯系人,通過快速回復按鈕添加快速回復的短信內容,可以直接發送短信的應用。
創建項目,設計主界面UI,添加聯系人界面UI和快速回復界面UI。
<RelativeLayoutxmlns: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="com.example.msgsender2.MainActivity" ><Buttonandroid:id="@+id/btn_add"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:text="+" /><EditTextandroid:id="@+id/et_tel"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_toLeftOf="@id/btn_add"android:inputType="numberSigned"android:hint="請輸入號碼" /><EditTextandroid:id="@+id/et_msgcontent"android:layout_width="match_parent"android:layout_height="200dp"android:layout_below="@id/btn_add"android:layout_marginTop="10dp"android:gravity="top"android:hint="請輸入短信內容"/><Buttonandroid:id="@+id/btn_reply"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/et_msgcontent"android:text="快速回復" /><Buttonandroid:id="@+id/btn_send"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/btn_reply"android:text="發送" /></RelativeLayout>快速回復界面和添加聯系人界面都是一個ListView。
創建兩個界面的item模版。
編寫業務邏輯
主控件
public class MainActivity extends Activityimplements OnClickListener {privateEditText et_tel;privateEditText et_msgcontent;privateButton btn_send;privateButton btn_reply;privateButton btn_add;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_tel= (EditText) findViewById(R.id.et_tel);et_msgcontent= (EditText) findViewById(R.id.et_msgcontent);btn_add = (Button)findViewById(R.id.btn_add);btn_reply= (Button) findViewById(R.id.btn_reply);btn_send= (Button) findViewById(R.id.btn_send);btn_add.setOnClickListener(this);btn_reply.setOnClickListener(this);btn_send.setOnClickListener(this);}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubintid = v.getId();switch(id) {caseR.id.btn_add:Intentintent = new Intent(getApplicationContext(),ContractActivity.class);//startActivity(intent);startActivityForResult(intent,1);break;caseR.id.btn_reply:Intentintent2 = new Intent(getApplicationContext(),ReplyActivity.class);startActivityForResult(intent2,2);break;caseR.id.btn_send:SmsManagermanager = SmsManager.getDefault();StringdestinationAddress = et_tel.getText().toString().trim();Stringtext = et_msgcontent.getText().toString().trim();manager.sendTextMessage(destinationAddress,null, text, null, null);break;}}@Overrideprotectedvoid onActivityResult(int requestCode, int resultCode, Intent data) {//TODO Auto-generated method stubsuper.onActivityResult(requestCode,resultCode, data);System.out.println("onactivityresult");if(data == null) {return;}switch(requestCode) {case1:Stringtel = data.getStringExtra("tel");et_tel.setText(tel);break;case2:Stringmsg_content = data.getStringExtra("msgContent");et_msgcontent.setText(msg_content);break;}}}添加聯系人號碼控件
public class ContractActivity extends Activity{privateListView lv_contract;privateArrayList<Contract> conList = new ArrayList<Contract>();@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {//TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_contract);lv_contract= (ListView) findViewById(R.id.lv_contract);for(int i = 0; i < 20; i++) {Contractcon = new Contract();con.name= "abc" + i;con.tel= "1351234" + i;conList.add(con);}MyAdapteradapter = new MyAdapter();lv_contract.setAdapter(adapter);lv_contract.setOnItemClickListener(newOnItemClickListener() {@Overridepublicvoid onItemClick(AdapterView<?> parent, View view,intposition, long id) {//TODO Auto-generated method stubContractcontract = conList.get(position);Stringname = contract.name;Stringtel = contract.tel;Intentintent = new Intent();intent.putExtra("name",name);intent.putExtra("tel",tel);setResult(1,intent);finish();}});}privateclass MyAdapter extends BaseAdapter {@Overridepublicint getCount() {//TODO Auto-generated method stubreturnconList.size();}@OverridepublicObject getItem(int position) {//TODO Auto-generated method stubreturnconList.get(position);}@Overridepubliclong getItemId(int position) {//TODO Auto-generated method stubreturnposition;}@OverridepublicView getView(int position, View convertView, ViewGroup parent) {//TODO Auto-generated method stubViewview = null;if(convertView == null) {view= View.inflate(getApplicationContext(),R.layout.item_contract,null);}else {view= convertView;}TextViewcontract_name = (TextView) view.findViewById(R.id.contract_name);TextViewcontract_tel = (TextView) view.findViewById(R.id.contract_tel);contract_name.setText(conList.get(position).name);contract_tel.setText(conList.get(position).tel);returnview;}}}快速回復控件
public class ReplyActivity extends Activity {privateString[] msgs = { "春回大地鶯梳柳,","福到農家燕銜泥。", "小康入戶春風暖;", "福字進門日子紅。","三春巧畫新時代", "四海高歌大浪潮","雞犬相聞鄰里睦;", "燕鶯清唱畫中歡。", "淘到春風歸作寶","裹成福氣寄回家","梅花一路追新夢", "竹葉兩行入畫圖" };privateListView lv_reply;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {//TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_reply);lv_reply= (ListView) findViewById(R.id.lv_reply);ArrayAdapter<String>adapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.item_reply, msgs);lv_reply.setAdapter(adapter);lv_reply.setOnItemClickListener(newOnItemClickListener() {@Overridepublicvoid onItemClick(AdapterView<?> parent, View view,intposition, long id) {//TODO Auto-generated method stubStringmsgContent = msgs[position];Intentintent = new Intent();intent.putExtra("msgContent",msgContent);setResult(2,intent);finish();}});}}將兩個控件加入到清單。測試。
7.????????Activity的生命周期
Activity的四個狀態。處于前臺的activity,是可見的,并且可以跟用戶進行交互;處于暫停狀態,可見,但不能被操作,當內存資源及其緊張時被殺死;處于停止狀態,不可見,不可被操作;銷毀狀態,activity被系統殺死或者調用finish方法主動退出。
這四種狀態就是Activity的生命周期。
創建一個項目,調用各個生命周期的方法。
onCreate當activity創建的時候執行這個方法。
onStart走完這個方法activity就被用戶端看到。
onResume走這個方法使activity處于前臺的狀態,可見可被操作。
onPause這個方法使activity處于暫停狀態,可見但不可被操作。
onStop這個方法使activity處于停止狀態,不可見不可被操作。
onDestroy這個方法使activity被銷毀,回收內存。
onRestart這個方法使activity從停止狀態回到前臺。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);System.out.println("oncreate");}publicvoid open(View v) {Intentintent = new Intent(getApplicationContext(),SecondActivity.class);startActivity(intent);}@Overrideprotectedvoid onStart() {//TODO Auto-generated method stubsuper.onStart();System.out.println("onStart");}@Overrideprotectedvoid onResume() {//TODO Auto-generated method stubsuper.onResume();System.out.println("onResume");}@Overrideprotectedvoid onPause() {//TODO Auto-generated method stubsuper.onPause();System.out.println("onPause");}@Overrideprotectedvoid onStop() {//TODO Auto-generated method stubsuper.onStop();System.out.println("onStop");}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}@Overrideprotectedvoid onRestart() {//TODO Auto-generated method stubsuper.onRestart();System.out.println("onRestart");}}在UI界面添加一個按鈕,跳轉到另一個界面,測試從停止狀態回到前臺。
創建一個透明應用,打開這個應用,并覆蓋已經打開的測試應用,可以看到被測試應用處于暫停狀態。
創建透明應用,需要在清單文件的application標簽下添加:
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
生命周期方法的應用很普遍,比如在使用一個應用的過程中,來電話了,這個時候可以在應用的onStop或者onPause方法中做一些操作。比如操作數據庫時,對于頻繁使用數據庫的應用,可以在打開數據庫后,不立即close,而是在onDestroy的方法中關閉,減少頻繁打開、關閉數據庫,節省內存資源。比如一個聊天應用,當壓到后臺后,再次調回前臺時,可以在onResume方法中,獲取最新的聊天記錄,在界面顯示。
onResume加載數據、恢復播放的狀態。
onStop,可以在這個方法中停止所有關于刷新界面的操作。
onDestroy,釋放資源的操作在這個方法中執行。
對于屏幕旋轉時,activity的生命周期,當屏幕旋轉后,先銷毀再新創建。對于多數應用,在使用過程中,如果銷毀了activity,再創建可能產生意外的結果。解決這個問題的方式是,第一,禁止屏幕旋轉,在清單文件中給對應的activity配置android:screenOrientation="portrait"。第二中方式,可以隨屏幕旋轉,但是不執行生命周期方法,在activity中配置android:configChanges="orientation|screenSize"。
8.????????Activity的任務棧
創建一個activity就會放在任務棧中。android使用棧結構保存activity的實例。在清單文件中可以配置activity的啟動模式。
standard,標準模式,默認使用這種模式。
singleTop,在任務棧的棧頂只有一個實例。如果棧頂有一個activity,則在創建這個activity的對象不會成功。比如使用二維碼掃描使用singleTop。
singleTask,在任務棧中只有一個實例。如果在棧中已經存在一個singleTask的activity的對象,那么再次開啟這個activity不會創建一個新的對象而是把這個activity上的對象都彈出棧,而使用這個activity。較常用,比如應用的主界面可以使用singleTask。
singleInstance,在當前任務棧中只有一個實例,并且這個實例會創建一個單獨的任務棧,這個棧中只有這一個實例。調用瀏覽器,就可以使用singleInstance。
六、? BroadcastReceiver
1.????????廣播接受者介紹
廣播接受者,接受意圖發布的廣播。現實中廣播的特點是,數據傳遞方向是單向的,需要調到固定的頻率,一對多。android的廣播的特點是,作用范圍有限,僅限于當前的手機,系統把一些重要的操作,通過廣播的形式通知給所有的應用。
2.????????ip撥號器
通過撥號器,自動給撥打的號碼添加前綴,比如添加17951等。
創建項目,設計UI,一個號碼輸入框和提交保存的按鈕。
編寫保存用戶輸入的前綴的業務。
public class MainActivity extends Activity {privateButton btn_save;privateEditText et_prefix;privateSharedPreferences sp;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_prefix= (EditText) findViewById(R.id.et_prefix);btn_save= (Button) findViewById(R.id.btn_save);sp= getSharedPreferences("info", MODE_PRIVATE);btn_save.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubStringprefix = et_prefix.getText().toString().trim();if(TextUtils.isEmpty(prefix)) {Toast.makeText(MainActivity.this,"前綴不可以為空",Toast.LENGTH_SHORT);}else {sp.edit().putString("prefix",prefix).commit();}}});}}創建一個廣播接受對象,并在清單中聲明之,給它添加打電話的意圖過濾。
?? ?????<receiverandroid:name="com.example.ipdailer.DailReceiver"><intent-filter ><actionandroid:name="android.intent.action.NEW_OUTGOING_CALL"/></intent-filter></receiver>編寫廣播接受對象的業務邏輯
public class DailReceiver extendsBroadcastReceiver {privateSharedPreferences sp;@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubsp= context.getSharedPreferences("info", context.MODE_PRIVATE);Stringprefix = sp.getString("prefix", "12530");System.out.println("打電話進行中");Stringresult = getResultData();System.out.println(result);setResultData(prefix+ result);}}3.????????sd卡狀態監聽
創建項目,創建一個sd卡的廣播接收者,并將這個接受者聲明在清單文件,給其添加意圖過濾。
???? ???<receiverandroid:name="com.example.sdstatuslistener.SDCardStatusReceiver"><intent-filter ><actionandroid:name="android.intent.action.MEDIA_MOUNTED"/><actionandroid:name="android.intent.action.MEDIA_UNMOUNTED"/><data android:scheme="file"/></intent-filter></receiver>編寫接收業務
public class SDCardStatusReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubSystem.out.println("sd卡狀態發生變化");Stringaction = intent.getAction();if("android.intent.action.MEDIA_MOUNTED".equals(action)) {System.out.println("sd卡被掛載");}else if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {System.out.println("sd卡被卸載");}}}4.????????短信監聽
創建項目,創建短信廣播接受者,將短信接受者添加到清單。
?????? ?????? <receiverandroid:name="com.example.smslistener.SmsReceiver"><intent-filter ><actionandroid:name="android.provider.Telephony.SMS_RECEIVED" /></intent-filter></receiver>編寫業務邏輯
public class SmsReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubSystem.out.println("收到短信了");Object[]obj = (Object[]) intent.getExtras().get("pdus");for(Object o : obj) {SmsMessagesmsMessage = SmsMessage.createFromPdu((byte[]) o);Stringfrom = smsMessage.getOriginatingAddress();Stringsms = smsMessage.getMessageBody();System.out.println("from:"+ from + ";body:" + sms);}}}5.????????應用的卸載和安裝的廣播
針對應用的安裝和卸載的廣播接收,常用來做競品分析。
創建項目,創建應用安裝卸載的廣播接收,添加到清單。
??? ????<receiverandroid:name="com.example.appinstalluninstall.AppInstallUninstall"><intent-filter ><action android:name="android.intent.action.PACKAGE_ADDED"/><actionandroid:name="android.intent.action.PACKAGE_INSTALL"/><actionandroid:name="android.intent.action.PACKAGE_REMOVED"/><data android:scheme="package"/></intent-filter></receiver>編寫業務邏輯
public class AppInstallUninstall extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringaction = intent.getAction();Uriuri = intent.getData();if("android.intent.action.PACKAGE_ADDED".equals(action)) {System.out.println("應用被添加" + uri);}else if ("android.intent.action.PACKAGE_INSTALL".equals(action)) {System.out.println("應用被安裝");}else if ("android.intent.action.PACKAGE_REMOVED".equals(action)) {System.out.println("應用被卸載" + uri);}}}6.????????開機啟動廣播接收
創建項目,創建一個開機啟動的廣播接收,在清單文件中添加這個接受者。
?????? ?<receiverandroid:name="com.example.bootreceiver.BootReceiver"><intent-filter ><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver>編寫接收廣播的業務
public class BootReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubSystem.out.println("開機");Intentintent2 = new Intent(context, MainActivity.class);intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(intent2);}}7.????????發送無序廣播
指定action可以發送無序廣播。
創建一個發送廣播的項目,設計UI,添加一個發送廣播的按鈕。
編寫這個按鈕的發送業務邏輯,可以攜帶鍵值對內容。
???????? publicvoid sendbroadcast(View v) {//TODO Auto-generated method stubIntentintent = new Intent();intent.setAction("com.ten.broadcast");intent.putExtra("hello","world");sendBroadcast(intent);}再創建一個項目,接收廣播,創建廣播接收者,在清單中添加接收者,指定action為發送源的action。
編寫接收的業務
public class CustomReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubSystem.out.println("收到無序廣播");Stringv = intent.getStringExtra("hello");System.out.println(v);}}8.????????發送有序廣播
有序廣播可以指定接收的順序。
創建一個發送有序廣播的項目,設計UI,添加一個按鈕,發送廣播。
編寫發送的業務邏輯
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid send(View v) {Intentintent = new Intent();intent.setAction("com.ten.sendmoney");StringreceiverPermission = null;BroadcastReceiverresultReceiver = new FinalReceiver();Handlerscheduler = null;intinitialCode = Activity.RESULT_OK;StringinitialData = "廣播初始值100";BundleinitialExtras = null;sendOrderedBroadcast(intent,receiverPermission, resultReceiver,scheduler,initialCode, initialData, initialExtras);}}創建一個最后的接收者,由于由系統維護,所以不需要在清單文件中聲明之。
public class FinalReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringresult = getResultData();System.out.println(result);Toast.makeText(context,"final:" + result, Toast.LENGTH_SHORT).show();}}創建一個接收有序廣播的項目,創建多個廣播接收者。
public class ProReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringdata = getResultData();Toast.makeText(context,data, Toast.LENGTH_SHORT).show();setResultData("經過pro后80");}}public class CityReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringdata = getResultData();Toast.makeText(context,data, Toast.LENGTH_SHORT).show();setResultData("經過ci后60");}}public class CountyReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringdata = getResultData();Toast.makeText(context,data, Toast.LENGTH_SHORT).show();setResultData("經過cy后40");}}public class CountryReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringdata = getResultData();Toast.makeText(context,data, Toast.LENGTH_SHORT).show();}}在清單文件中,聲明這些接收者,并配置優先級。
??? ????<receiverandroid:name="com.example.receiveorderbroadcast.ProReceiver"><intent-filter android:priority="100" ><action android:name="com.ten.sendmoney"/></intent-filter></receiver><receiverandroid:name="com.example.receiveorderbroadcast.CityReceiver"><intent-filter android:priority="80" ><action android:name="com.ten.sendmoney"/></intent-filter></receiver><receiverandroid:name="com.example.receiveorderbroadcast.CountyReceiver"><intent-filter android:priority="60" ><action android:name="com.ten.sendmoney"/></intent-filter></receiver><receiverandroid:name="com.example.receiveorderbroadcast.CountryReceiver"><intent-filter android:priority="40" ><action android:name="com.ten.sendmoney"/></intent-filter></receiver>比較無序廣播和有序廣播。有序廣播,可以在接收者中通過優先級設置廣播接收順序;無序廣播是一起收到。有序廣播可以在接收中,abortBroadcast();中斷廣播;無序廣播不可以,否則報錯。有序廣播可以在接收過程中,修改廣播內容;無序廣播不可以。
9.????????特殊廣播接收者
四大組件中,只有廣播接收者可以不在清單文件中注冊。在清單文件中,通過聲明一個receiver,指定一個intent-filter的方法是靜態注冊。對于某些頻繁執行的操作,比如屏幕的點亮、滅和手機的鎖定、解鎖等,如果使用靜態注冊的方法接收這些操作的廣播,那么,這些操作就會變得卡頓。對于這類操作,需要使用動態注冊廣播接收者。也就是在代碼中注冊廣播接收者。
創建一個項目,創建一個關于屏幕點亮、關滅的廣播接收者。
public class ScreenLightReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringaction = intent.getAction();if("android.intent.action.SCREEN_OFF".equals(action)) {System.out.println("滅");}else if ("android.intent.action.SCREEN_ON".equals(action)) {System.out.println("點亮");}}}在入口方法中編寫注冊廣播接收者的代碼并在銷毀方法中注銷之。
public class MainActivity extends Activity {privateBroadcastReceiver receiver;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);receiver= new ScreenLightReceiver();IntentFilterfilter = new IntentFilter();filter.addAction("android.intent.action.SCREEN_ON");filter.addAction("android.intent.action.SCREEN_OFF");registerReceiver(receiver,filter);}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unregisterReceiver(receiver);}}10.?????自動填寫短信驗證碼
通過短信監聽的廣播接收者,獲得短信源的號碼,然后發起一個廣播,將驗證碼廣播出去,在主activity中,創建一個接收驗證碼廣播的內部類,動態注冊這個廣播接收者,并在廣播接收者的方法中,將驗證碼賦值給EditText控件。
創建短信監聽的廣播接收者,并在清單中注冊。
public class SmsReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubSystem.out.println("收到短信了");Object[]obj = (Object[]) intent.getExtras().get("pdus");for(Object o : obj) {SmsMessagesmsMessage = SmsMessage.createFromPdu((byte[]) o);Stringfrom = smsMessage.getOriginatingAddress();Stringsms = smsMessage.getMessageBody();System.out.println("from:"+ from + ";body:" + sms);if("15555215556".equals(from)) {Intentintent2 = new Intent();intent2.setAction("com.ten.smscode");intent2.putExtra("code",sms);context.sendBroadcast(intent2);}}}}在主activity中編寫業務邏輯
public class MainActivity extends Activity {privateEditText et_code;privateBroadcastReceiver receiver;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_code= (EditText) findViewById(R.id.et_code);receiver= new DynamicSmsReceiver();IntentFilterfilter = new IntentFilter();filter.addAction("com.ten.smscode");registerReceiver(receiver,filter);}privateclass DynamicSmsReceiver extends BroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubStringcode = intent.getStringExtra("code");et_code.setText(code);System.out.println(code);}}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unregisterReceiver(receiver);}}七、? 樣式與主題
1.????????樣式
使用values>styles.xml文件配置一個style,可以給多個樣式相同的控件使用這個style,如果這多個控件需要修改樣式,只需要修改這個style配置文件,即可,減少工作量。比如:
配置了一個style
??? <stylename="myTextView"><itemname="android:layout_width">wrap_content</item><itemname="android:layout_height">wrap_content</item><itemname="android:textSize">20sp</item><itemname="android:textColor">#ffff00</item><itemname="android:background">#770000</item></style>在使用style的UI中
? ??<TextViewstyle="@style/myTextView"android:text="@string/hello_world" /><TextViewstyle="@style/myTextView"android:text="@string/hello_world" /><TextViewstyle="@style/myTextView"android:text="@string/hello_world" /><TextViewstyle="@style/myTextView"android:text="@string/hello_world" />2.????????主題
主題實際上也是一種樣式,區別是,主題是作用在整個app上的。
比如,配置一個主題:
? ??<stylename="myAppTheme"><item name="android:background">#770000</item></style>在清單文件中,給application設置主題為myAppTheme。
android:theme="@style/myAppTheme">
八、? 國際化
Internationalization i18n,國際化。主要是應用的語言的國際化,就是支持隨著系統語言的變化而改變為相應的語言展示的。通過創建values-zh等文件夾,修改strings.xml等文件的內容,同時在應用中使用到文字等的地方采用@string/app_name的形式表示內容。關于語言的縮寫,通過查看pc端網頁瀏覽器中的相關設置可以找到。
九、? 對話框
常用的對話框有普通對話框、單選對話框、對選對話框和進度條對話框。創建對話框的時候,需要使用上下文,這個上下文必須是activity。因為對話框需要顯示到當前的activity中,是activity的一部分,創建對象的時候需要通知系統當前對話框顯示到哪個activity。對于進度條對話框,可以在子線程中修改主線程activity的界面。
創建一個項目,設計UI,添加四個對話框的按鈕。
? ??<Button?android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="normal"android:text="普通對話框"/><Button?android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="singleChoice"android:text="單選對話框"/><Button?android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="multiChoice"android:text="多選對話框"/><Button?android:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="progress"android:text="進度對話框"/><TextViewandroid:id="@+id/tv_hobby"?android:layout_width="match_parent"android:layout_height="wrap_content"/>編寫業務邏輯
public class MainActivity extends Activity {privateLinearLayout ll_docker;privateTextView tv_hobby;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ll_docker= (LinearLayout) findViewById(R.id.ll_docker);tv_hobby= (TextView) findViewById(R.id.tv_hobby);}publicvoid normal(View v) {AlertDialog.Builderbuilder = new Builder(this);builder.setTitle("普通對話框");builder.setMessage("要顯示的內容");builder.setPositiveButton("確定", new OnClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which) {//TODO Auto-generated method stubToast.makeText(MainActivity.this,"去頂了",Toast.LENGTH_SHORT).show();}});builder.setNegativeButton("取消", new OnClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which) {//TODO Auto-generated method stubToast.makeText(MainActivity.this,"取消了",Toast.LENGTH_SHORT).show();}});builder.show();}publicvoid singleChoice(View v) {AlertDialog.Builderbuilder = new Builder(this);builder.setTitle("請選擇背景顏色");finalString[] items = { "紅色", "藍色", "黑色", "白色", "綠色" };finalMap<String, String> colorMap = new HashMap<String, String>();colorMap.put("紅色", "#ff0000");colorMap.put("藍色", "#ffff00");colorMap.put("黑色", "#ffffff");colorMap.put("白色", "#000000");colorMap.put("綠色", "#00ff00");builder.setSingleChoiceItems(items,4, new OnClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which) {//TODO Auto-generated method stubll_docker.setBackgroundColor(Color.parseColor(colorMap.get(items[which])));dialog.dismiss();}});builder.show();}publicvoid multiChoice(View v) {AlertDialog.Builderbuilder = new Builder(this);builder.setTitle("請選擇愛好");finalString[] items = { "籃球", "足球", "排球", "乒乓球", "地球" };finalSet<Integer> choice = new HashSet<Integer>();builder.setMultiChoiceItems(items,null,newOnMultiChoiceClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which,booleanisChecked) {//TODO Auto-generated method stubif(isChecked) {choice.add(which);}else {if(choice.contains(which)) {choice.remove(which);}}StringBuildersb = new StringBuilder("愛好:");for(Integer i : choice) {sb.append(items[i]+ "、");}Stringresult = sb.substring(0,sb.length()- "、".length());tv_hobby.setText(result);}});builder.setPositiveButton("確定", new OnClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which) {//TODO Auto-generated method stubdialog.dismiss();}});builder.setNegativeButton("取消", new OnClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which) {//TODO Auto-generated method stubtv_hobby.setText("");}});builder.show();}publicvoid progress(View v) {finalProgressDialog dialog = new ProgressDialog(this);dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);dialog.setTitle("下載中");dialog.setMax(100);dialog.show();newThread() {publicvoid run() {for(int i = 0; i <= 100; i++) {dialog.setProgress(i);SystemClock.sleep(10);}dialog.dismiss();runOnUiThread(newRunnable() {@Overridepublicvoid run() {//TODO Auto-generated method stubToast.makeText(MainActivity.this,"下載完成",Toast.LENGTH_SHORT).show();}});}}.start();}}十、? service服務
1.????????進程
關于android中的進程和線程。當應用運行之后,系統就會創建一個linux進程,大部分情況下一個應用對應一個進程。每個進程開始有一個線程,默認下,所有的組件都運行在同一個進程和同一個線程中。四大組件都運行在主線程中。android系統會盡量保證每一個開啟的進程盡量長的運行在系統上。
前臺進程,當前用戶正在操作的進程是前臺進程。包括,當前進程中有activity處于可見可操作的狀態,activity執行了onResume之后并且留在這個狀態正在被用戶操作;service執行生命周期方法以及廣播接收者執行onReceive方法。前臺進程幾乎不會被殺死。
可視進程,有activity處于onPause狀態,可見不可操作。比如有透明應用蓋在一個應用上,或者有對話框蓋在activity上。只有當前臺進程內存不夠時才會殺死可視進程。
服務進程,用startService開啟的服務,并且運行在后臺。
后臺進程,activity處于onStop狀態,但是沒有被銷毀。通常會有大量應用處于后臺進程狀態,哪個應用的進程被銷毀取決于其LRU,最近最少使用。
空進程,沒有任何組件在運行,保存這個空進程的目的,是為了緩存當前的進程,加快下次運行時間。
2.????????開啟服務
使用startService方法開啟服務。執行的生命周期方法onCreate()->onStartCommand()->onStop()。結束服務使用stopService方法。
創建一個項目,UI中設計兩個按鈕,開啟和關閉,編寫一個服務,調用生命周期方法。
public class MyService extends Service {@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubSystem.out.println("onBind");returnnull;}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();System.out.println("onCreate");}@Overridepublicint onStartCommand(Intent intent, int flags, int startId) {//TODO Auto-generated method stubSystem.out.println("onStartCommand");returnsuper.onStartCommand(intent, flags, startId);}@Overridepublicvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}}在清單文件中注冊這個服務。
?? ?????<serviceandroid:name="com.example.startservice.MyService"></service>編寫業務
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid startservice(View v) {Intentservice = new Intent(this, MyService.class);startService(service);}publicvoid stopservice(View v) {Intentname = new Intent(this, MyService.class);stopService(name);}}3.????????電話錄音機
利用服務,偵聽接聽的電話,進行錄音。通過廣播,開機,開啟錄音服務。
創建項目,創建一個偵聽接電話的服務。在清單中注冊這個服務。
public class RecordService extends Service {privateMediaRecorder recorder;@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubreturnnull;}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();TelephonyManagermanager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);MyPhoneStateListenerlistener = new MyPhoneStateListener();manager.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);}privateclass MyPhoneStateListener extends PhoneStateListener {@Overridepublicvoid onCallStateChanged(int state, String incomingNumber) {switch(state) {caseTelephonyManager.CALL_STATE_IDLE:System.out.println("空閑");if(recorder != null) {try{recorder.stop();recorder.reset();recorder.release();}catch (Exception e) {e.printStackTrace();}}break;caseTelephonyManager.CALL_STATE_RINGING:System.out.println("響鈴" + incomingNumber);recorder= new MediaRecorder();recorder.setAudioSource(MediaRecorder.AudioSource.MIC);recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);recorder.setOutputFile(getCacheDir()+"/"+incomingNumber+"-Date"+new SimpleDateFormat("yyyyMMddHHmmss").format(newDate(System.currentTimeMillis()))+".3gp");try{recorder.prepare();}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}break;caseTelephonyManager.CALL_STATE_OFFHOOK:System.out.println("接聽" + incomingNumber);recorder.start();break;}}}}創建一個接收開機完畢的廣播,完成開啟服務的業務,注冊這個廣播。
public class BootReceiver extendsBroadcastReceiver {@Overridepublicvoid onReceive(Context context, Intent intent) {//TODO Auto-generated method stubIntentintent2 = new Intent(context, RecordService.class);context.startService(intent2);}}測試。
4.????????bindService開啟服務
bindService開啟的服務與當前的activity是綁定的,生命周期隨當前acitivity。
創建一個項目,創建一個服務,并在清單中注冊之。
public class BindService extends Service {@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubSystem.out.println("onbind");returnnew MyBinder();}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();System.out.println("oncreate");}@Overridepublicint onStartCommand(Intent intent, int flags, int startId) {//TODO Auto-generated method stubSystem.out.println("onStartCommand");returnsuper.onStartCommand(intent, flags, startId);}@Overridepublicvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}privateclass MyBinder extends Binder {}}編寫開啟服務和結束服務的邏輯。
public class MainActivity extends Activity {privateMyConnection conn;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid start(View v) {Intentservice = new Intent(this, BindService.class);conn= new MyConnection();bindService(service,conn, BIND_AUTO_CREATE);}privateclass MyConnection implements ServiceConnection {@Overridepublicvoid onServiceConnected(ComponentName name, IBinder service) {//TODO Auto-generated method stubSystem.out.println("onServiceConnected");}@Overridepublicvoid onServiceDisconnected(ComponentName name) {//TODO Auto-generated method stubSystem.out.println("onServiceDisconnected");}}publicvoid stop(View v) {unbindService(conn);}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unbindService(conn);}}比較startService和bindService
bindService的生命周期,是onCreate->onBind,onBind只會執行一次。開啟的服務會綁定到當前的activity,隨著activity的退出而需要結束服務。結束的時候,調用unbindService方法,只能調用一次,否則報錯。
startService的生命周期,是onCreate->onStartCommand,onStartCommand會執行多次。開啟的服務與activity沒有綁定關系。結束的時候,調用stopService方法,可以調用多次,只有第一次有效。
5.????????bindService通過activity調用服務中的方法
使用service的onBind方法的返回值,在service中創建一個內部類繼承Binder類,通過這個內部類將service類中的方法傳遞給activity。然后,在activity創建的實現ServiceConnection接口的類中,獲取到service傳遞過來的內部類。使用這個獲得的內部類調用相關方法。
public class BindService extends Service {@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubSystem.out.println("onbind");returnnew MyBinder();}publicvoid showToast(String str) {Toast.makeText(getApplicationContext(),str, Toast.LENGTH_SHORT).show();}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();System.out.println("oncreate");}@Overridepublicint onStartCommand(Intent intent, int flags, int startId) {//TODO Auto-generated method stubSystem.out.println("onStartCommand");returnsuper.onStartCommand(intent, flags, startId);}@Overridepublicvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}publicclass MyBinder extends Binder {publicvoid callShowToast(String s) {showToast(s);}}}編寫調用方法的業務邏輯
public class MainActivity extends Activity {privateMyConnection conn;privateMyBinder mybinder;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid start(View v) {Intentservice = new Intent(this, BindService.class);conn= new MyConnection();bindService(service,conn, BIND_AUTO_CREATE);}privateclass MyConnection implements ServiceConnection {@Overridepublicvoid onServiceConnected(ComponentName name, IBinder service) {//TODO Auto-generated method stubSystem.out.println("onServiceConnected");mybinder= (MyBinder) service;//mybinder.callShowToast("haha");}@Overridepublicvoid onServiceDisconnected(ComponentName name) {//TODO Auto-generated method stubSystem.out.println("onServiceDisconnected");}}publicvoid stop(View v) {unbindService(conn);}publicvoid callServiceMethod(View v) {//BindService service = new BindService();mybinder.callShowToast("haha");}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unbindService(conn);}}6.????????音樂播放器
創建項目,設計UI,編寫播放控制服務,并注冊。
public class MusicPlayerService extends Service{@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubreturnnew MyBinder();}publicclass MyBinder extends Binder {publicvoid callNext() {next();}publicvoid callPrev() {prev();}publicvoid callPlay() {play();}publicvoid callPause() {pause();}}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();System.out.println("準備一個音樂播放器");}publicvoid next() {Toast.makeText(getApplicationContext(),"播放下一首",Toast.LENGTH_SHORT).show();}publicvoid play() {Toast.makeText(getApplicationContext(),"播放開始",Toast.LENGTH_SHORT).show();}publicvoid prev() {Toast.makeText(getApplicationContext(),"播放上一首",Toast.LENGTH_SHORT).show();}publicvoid pause() {Toast.makeText(getApplicationContext(),"暫停",Toast.LENGTH_SHORT).show();}}編寫播放控制的業務
public class MainActivity extends Activity {privateMyBinder binder;privateMyConnection conn;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intentservice = new Intent(this, MusicPlayerService.class);conn= new MyConnection();bindService(service,conn, BIND_AUTO_CREATE);}publicvoid nextOne(View v) {binder.callNext();}publicvoid preOne(View v) {binder.callPrev();}publicvoid play(View v) {binder.callPlay();}publicvoid pause(View v) {binder.callPause();}privateclass MyConnection implements ServiceConnection {@Overridepublicvoid onServiceConnected(ComponentName name, IBinder service) {binder= (MyBinder) service;}@Overridepublicvoid onServiceDisconnected(ComponentName name) {//TODO Auto-generated method stub}}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unbindService(conn);}}使用bindService打開服務,問題是,播放功能隨著退出應用而結束。
7.????????混合方式開啟服務
混合使用startService和bindService方法,既可以使得activity和service溝通,也可以使得service的生命不止于activity結束而結束。開啟服務需要兩種方式的開啟都執行,順序不分前后;結束服務需要兩種方式的結束都執行,順序不分前后。
創建一個項目,設計UI,為兩種方式分別設計開始和結束的按鈕,創建服務,并注冊。
public class MixStartService extends Service {@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubSystem.out.println("onbind");returnnew MyBinder();}publicclass MyBinder extends Binder {publicvoid start() {Toast.makeText(getApplicationContext(),"開始",Toast.LENGTH_SHORT).show();}publicvoid stop() {Toast.makeText(getApplicationContext(),"停止",Toast.LENGTH_SHORT).show();}}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();System.out.println("onCreate");}@Overridepublicint onStartCommand(Intent intent, int flags, int startId) {//TODO Auto-generated method stubSystem.out.println("onStartCommand");returnsuper.onStartCommand(intent, flags, startId);}@Overridepublicvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}}編寫業務邏輯
public class MainActivity extends Activity {privateMyBinder binder;privateMyConnection conn;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid start(View v) {Intentintent = new Intent(this, MixStartService.class);startService(intent);if(binder != null) {binder.start();}}publicvoid stop(View v) {Intentintent = new Intent(this, MixStartService.class);stopService(intent);if(binder != null) {binder.stop();}}publicvoid bind(View v) {Intentintent = new Intent(this, MixStartService.class);conn= new MyConnection();bindService(intent,conn, BIND_AUTO_CREATE);//binder.start();}publicvoid unbind(View v) {if(binder != null && conn != null) {binder.stop();unbindService(conn);conn= null;}}privateclass MyConnection implements ServiceConnection {@Overridepublicvoid onServiceConnected(ComponentName name, IBinder service) {binder= (MyBinder) service;System.out.println("onServiceConnected");}@Overridepublicvoid onServiceDisconnected(ComponentName name) {//TODO Auto-generated method stub}}}8.????????AIDL
android?interface? definition? language,android接口定義語言,讓其他應用可以調用當前應用service中的方法。 為了讓其他應用可以訪問本應用程序提供的服務,android采用遠程過程調用remote? procedure?call,rpc來實現。rpc是屬于ipc,inter? process? communication進程間通信的表現形式。每個androud應用間的通信都是ipc,四大組件中的三個acitivity、broadcastreceiver、provider都可以獨立實現ipc。跨進程間訪問的服務使用aidl實現rpc。
通過提供遠程服務實現跨進程調用服務方法。
創建一個提供遠程服務的項目,編寫服務類,并注冊。
public class RemoteService extends Service {@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubreturnnew MyBinder();}publicclass MyBinder extends Stub {publicvoid callRemoteMethod() {remoteMethod();}}publicvoid remoteMethod() {System.out.println("remoteMethod");}}編寫一個接口,暴露要被調用的方法。
interface IService {void callRemoteMethod();}將這個接口文件的后綴改為aidl,注意aidl文件不支持public關鍵字。修改后在gen目錄下會自動創建一個對應的java文件,這個文件里面的抽象類Stub繼承了Binder類實現了自定義的接口。然后,將服務類中自定義的Binder類繼承這個Stub類。
創建調用遠程服務方法的項目,建立一個被調用項目的aidl文件的包同名的包,并將aidl文件復制到這個包下。設計UI,添加一個調用方法的按鈕。編寫業務邏輯。
public class MainActivity extends Activity {privateIService iservice;privateMyConnection conn;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intentservice = new Intent();service.setAction("com.ten.remoteservice");conn= new MyConnection();bindService(service,conn, BIND_AUTO_CREATE);}publicvoid callremote(View v) {try{iservice.callRemoteMethod();}catch (RemoteException e) {//TODO Auto-generated catch blocke.printStackTrace();}}privateclass MyConnection implements ServiceConnection {@Overridepublicvoid onServiceConnected(ComponentName name, IBinder service) {iservice= Stub.asInterface(service);}@Overridepublicvoid onServiceDisconnected(ComponentName name) {//TODO Auto-generated method stub}}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unbindService(conn);}}測試。
十一、?????????內容相關組件
1.????????內容提供者
內容提供者的主要作用,將自己的數據提供給其他應用使用。如果不使用內容提供者將本應用的數據提供出去,將是不安全的,比如。
創建一個項目,創建數據庫表并插入數據。
public class MyOpenHelper extendsSQLiteOpenHelper {publicMyOpenHelper(Context context) {super(context,"ten.db", null, 1);//TODO Auto-generated constructor stub}@Overridepublicvoid onCreate(SQLiteDatabase db) {//TODO Auto-generated method stubdb.execSQL("createtable info(_id integer primary key autoincrement,name varchar(20),phonevarchar(20))");db.execSQL("altertable info add age integer");}@Overridepublicvoid onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//TODO Auto-generated method stub}}編寫初始化數據表和插入數據的業務邏輯。
public class MainActivity extends Activity {privateSQLiteDatabase database;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyOpenHelperopenHelper = new MyOpenHelper(this);database= openHelper.getReadableDatabase();}publicvoid insert(View v) {database.execSQL("insertinto info (name,phone) values ('張四','13567899876')");database.execSQL("insertinto info (name,phone) values ('王武','13545699876')");database.execSQL("insertinto info (name,phone) values ('馬流','1567899876')");database.execSQL("insertinto info (name,phone) values ('沼氣','1678765676')");}publicvoid query(View v) {Cursorresult = database.rawQuery("select * from info", null);while(result.moveToNext()) {Stringname = result.getString(result.getColumnIndex("name"));Stringphone = result.getString(result.getColumnIndex("phone"));System.out.println(name+ "--" + phone);}}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();database.close();}}為了能夠是其他應用可以訪問被應用的數據,將數據庫文件權限修改為777,并刪除對應的日志文件。
創建其他應用訪問本應用的數據表。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid access(View v) {Stringpath = "/data/data/com.example.opendatabase/databases/ten.db";SQLiteDatabasedatabase = SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READWRITE);Cursorresult = database.rawQuery("select * from info", null);while(result.moveToNext()) {Stringname = result.getString(result.getColumnIndex("name"));Stringphone = result.getString(result.getColumnIndex("phone"));System.out.println(name+ "--" + phone);}}}顯然,這種方式是不安全的。
內容提供者,專門向其他應用提供內容訪問的類,并且具有一定的安全控制性。
使用內容提供者的例子。
創建一個項目初始化數據表。
public class MyOpenHelper extendsSQLiteOpenHelper {publicMyOpenHelper(Context context) {super(context,"ten.db", null, 1);//TODO Auto-generated constructor stub}@Overridepublicvoid onCreate(SQLiteDatabase db) {//TODO Auto-generated method stubdb.execSQL("createtable info(_id integer primary key autoincrement,name varchar(20),phonevarchar(20))");db.execSQL("insertinto info (name,phone) values ('張四','13567899876')");db.execSQL("insertinto info (name,phone) values ('王武','13545699876')");db.execSQL("insertinto info (name,phone) values ('馬流','1567899876')");db.execSQL("insertinto info (name,phone) values ('沼氣','1678765676')");}@Overridepublicvoid onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//TODO Auto-generated method stub}}public class MainActivity extends Activity {privateSQLiteDatabase db;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyOpenHelperhelper = new MyOpenHelper(this);db= helper.getReadableDatabase();}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();db.close();}}創建內容提供者類,并注冊之。
public class MyProvider extends ContentProvider{privateMyOpenHelper helper;privatestatic final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);privatestatic final int QUERY_SUCESS = 0;privatestatic final int INSERT_MATCHED = 1;privatestatic final int DELETE_MATCHED = 2;privatestatic final int UPDATE_MATCHED = 3;static{sUriMatcher.addURI("com.ten.provider","query", QUERY_SUCESS);sUriMatcher.addURI("com.ten.provider","insert", INSERT_MATCHED);sUriMatcher.addURI("com.ten.provider","delete", DELETE_MATCHED);sUriMatcher.addURI("com.ten.provider","update", UPDATE_MATCHED);}@Overridepublicboolean onCreate() {helper= new MyOpenHelper(getContext());returnfalse;}@OverridepublicCursor query(Uri uri, String[] projection, String selection,String[]selectionArgs, String sortOrder) {//TODO Auto-generated method stubintresult = sUriMatcher.match(uri);if(result == QUERY_SUCESS) {SQLiteDatabasedb = helper.getReadableDatabase();Cursorquery = db.query("info", projection, selection,selectionArgs,null, null, sortOrder);returnquery;}else {thrownew IllegalStateException("口令不符");}}@OverridepublicString getType(Uri uri) {//TODO Auto-generated method stubreturnnull;}@OverridepublicUri insert(Uri uri, ContentValues values) {//TODO Auto-generated method stubintresult = sUriMatcher.match(uri);if(result == INSERT_MATCHED) {SQLiteDatabasedb = helper.getReadableDatabase();longinsert = db.insert("info", null, values);db.close();returnUri.parse(String.valueOf(insert));}else {returnnull;}}@Overridepublicint delete(Uri uri, String selection, String[] selectionArgs) {//TODO Auto-generated method stubintresult = sUriMatcher.match(uri);if(result == DELETE_MATCHED) {SQLiteDatabasedb = helper.getReadableDatabase();intdelete = db.delete("info", selection, selectionArgs);db.close();returndelete;}else {return-1;}}@Overridepublicint update(Uri uri, ContentValues values, String selection,String[]selectionArgs) {intresult = sUriMatcher.match(uri);if(result == UPDATE_MATCHED) {SQLiteDatabasedb = helper.getReadableDatabase();intupdate = db.update("info", values, selection, selectionArgs);db.close();returnupdate;}else {return-1;}}} ??? ????<providerandroid:name="com.example.contentprovider.MyProvider"android:authorities="com.ten.provider"android:exported="true"></provider>創建另一個項目,編寫業務邏輯,使用內容解析者獲取其他項目內容提供者提供的數據。
???????? publicclass MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid access(View v) {Stringpath = "/data/data/com.example.opendatabase/databases/ten.db";SQLiteDatabasedatabase = SQLiteDatabase.openDatabase(path, null,SQLiteDatabase.OPEN_READWRITE);Cursorresult = database.rawQuery("select * from info", null);while(result.moveToNext()) {Stringname = result.getString(result.getColumnIndex("name"));Stringphone = result.getString(result.getColumnIndex("phone"));System.out.println(name+ "--" + phone);}}publicvoid accessProvider(View v) {ContentResolvercontentResolver = getContentResolver();Uriuri = Uri.parse("content://com.ten.provider/query");Cursorresult = contentResolver.query(uri, null, null, null, null);while(result.moveToNext()) {Stringname = result.getString(result.getColumnIndex("name"));Stringphone = result.getString(result.getColumnIndex("phone"));System.out.println(name+ "--" + phone);}}publicvoid insert(View v) {ContentResolverresolver = getContentResolver();Uriurl = Uri.parse("content://com.ten.provider/insert");ContentValuesvalues = new ContentValues();values.put("name","禮拜");values.put("phone","135665456");Uriinsert = resolver.insert(url, values);System.out.println(insert);}publicvoid update(View v) {ContentResolverresolver = getContentResolver();Uriuri = Uri.parse("content://com.ten.provider/update");ContentValuesvalues = new ContentValues();values.put("phone","11111111");Stringwhere = "name = ?";String[]selectionArgs = { "沼氣" };intupdate = resolver.update(uri, values, where, selectionArgs);Toast.makeText(getApplicationContext(),update + "", Toast.LENGTH_SHORT).show();}publicvoid delete(View v) {ContentResolverresolver = getContentResolver();Uriurl = Uri.parse("content://com.ten.provider/delete");Stringwhere = "name=?";String[]selectionArgs = { "馬流" };intdelete = resolver.delete(url, where, selectionArgs);Toast.makeText(getApplicationContext(),delete + "", Toast.LENGTH_SHORT).show();}}2.????????通過內容提供者訪問短信數據庫
創建一個項目,設計UI,添加3個按鈕。
編寫一個短信的javabean。
public class Sms {publicString date;publicString address;publicString body;@OverridepublicString toString() {return"Sms [date=" + date + ", address=" + address + ",body=" + body+"]";}}在清單文件,添加讀寫短信的權限。
編寫業務邏輯。
public class MainActivity extends Activity {privateArrayList<Sms> smslist = new ArrayList<Sms>();@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid query(View v) {ContentResolverresolver = getContentResolver();Uriuri = Uri.parse("content://sms");String[]projection = { "address", "date", "body" };Cursorresult = resolver.query(uri, projection, null, null, null);while(result.moveToNext()) {Smssms = new Sms();Stringaddress = result.getString(result.getColumnIndex("address"));StringdateStr = result.getString(result.getColumnIndex("date"));Datedate = new Date(Long.parseLong(dateStr));StringdateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);Stringbody = result.getString(result.getColumnIndex("body"));sms.address= address;sms.body= body;sms.date= dateFormat;smslist.add(sms);System.out.println("address:"+ address + "||date:" + dateFormat+"||body:" + body);}for(Sms sms : smslist) {System.out.println(sms);}result.close();}publicvoid backup(View v) {XmlSerializerserializer = Xml.newSerializer();try{serializer.setOutput(openFileOutput("sms.xml",MODE_PRIVATE),"utf-8");serializer.startDocument("utf-8",null);serializer.startTag(null,"SmsList");for(Sms sms : smslist) {serializer.startTag(null,"sms");serializer.startTag(null,"address");serializer.text(sms.address);serializer.endTag(null,"address");serializer.startTag(null,"date");serializer.text(sms.date);serializer.endTag(null,"date");serializer.startTag(null,"body");serializer.text(sms.body);serializer.endTag(null,"body");serializer.endTag(null,"sms");}serializer.endTag(null,"SmsList");serializer.endDocument();}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}publicvoid insert(View v) {ContentResolverresolver = getContentResolver();Uriurl = Uri.parse("content://sms");ContentValuesvalues = new ContentValues();values.put("address","123456");values.put("date",String.valueOf(System.currentTimeMillis()));values.put("body","測試插入短信");Uriresult = resolver.insert(url, values);Toast.makeText(getApplicationContext(),result.toString(),Toast.LENGTH_SHORT).show();}}3.????????聯系人
使用聯系人的內容提供者可以實現查詢聯系人和保存聯系人的功能。
創建一個項目,設計UI,添加查詢按鈕,輸入框和保存按鈕。在清單文件,添加讀寫聯系人的權限。
創建一個聯系人的javabean。
public class Contact {publicString name;publicString address;publicString phone;publicString email;@OverridepublicString toString() {return"Contact [name=" + name + ", address=" + address + ",phone="+phone + ", email=" + email + "]";}}編寫業務邏輯。
public class MainActivity extends Activity {ArrayList<Contact>contList = new ArrayList<Contact>();privateEditText et_name;privateEditText et_phone;privateEditText et_address;privateEditText et_email;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_name= (EditText) findViewById(R.id.et_name);et_phone= (EditText) findViewById(R.id.et_phone);et_address= (EditText) findViewById(R.id.et_address);et_email= (EditText) findViewById(R.id.et_email);}publicvoid queryContract(View v) {ContentResolverresolver = getContentResolver();Uriraw_contacts_uri = Uri.parse("content://com.android.contacts/raw_contacts");Uridata_uri = Uri.parse("content://com.android.contacts/data");String[]projection = { "contact_id" };Cursorcontact_id = resolver.query(raw_contacts_uri, projection, null,null,null);while(contact_id.moveToNext()) {Stringid = contact_id.getString(contact_id.getColumnIndex("contact_id"));System.out.println(id);String[]projection2 = { "data1", "mimetype" };Cursordatas = resolver.query(data_uri, projection2,"raw_contact_id=?",new String[] { id }, null);Contactcont = new Contact();while(datas.moveToNext()) {Stringdata1 = datas.getString(datas.getColumnIndex("data1"));Stringmimetype = datas.getString(datas.getColumnIndex("mimetype"));System.out.println(data1+ "--" + mimetype);//String[] names = datas.getColumnNames();//for (String name : names) {//System.out.println(name);//}if("vnd.android.cursor.item/phone_v2".equals(mimetype)) {cont.phone= data1;}else if ("vnd.android.cursor.item/postal-address_v2".equals(mimetype)){cont.address= data1;}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {cont.email= data1;}else if ("vnd.android.cursor.item/name".equals(mimetype)) {cont.name= data1;}}contList.add(cont);}contact_id.close();for(Contact cont : contList) {System.out.println(cont);}}publicvoid save(View v) {Stringname = et_name.getText().toString().trim();Stringphone = et_phone.getText().toString().trim();Stringaddress = et_address.getText().toString().trim();Stringemail = et_email.getText().toString().trim();ContentResolverresolver = getContentResolver();Uriraw_contact_uri = Uri.parse("content://com.android.contacts/raw_contacts");Cursordata_ids = resolver.query(raw_contact_uri,newString[] { "contact_id" }, null, null, null);intcount = data_ids.getCount();data_ids.close();System.out.println("count:"+ count);intid = count + 1;ContentValuesraw_values = new ContentValues();raw_values.put("contact_id",id);resolver.insert(raw_contact_uri,raw_values);HashMap<String,String> datas = new HashMap<String, String>();datas.put("vnd.android.cursor.item/name",name);datas.put("vnd.android.cursor.item/phone_v2",phone);datas.put("vnd.android.cursor.item/postal-address_v2",address);datas.put("vnd.android.cursor.item/email_v2",email);Uridata_uri = Uri.parse("content://com.android.contacts/data");Set<String>keys = datas.keySet();for(String key : keys) {ContentValuesvalues = new ContentValues();values.put("raw_contact_id",id);values.put("mimetype",key);values.put("data1",datas.get(key));resolver.insert(data_uri,values);}}}4.????????內容觀察者
當數據發生改變的時候,內容解析者發出一個通知ContentResolver.notifyChange,通過內容解析者可以注冊一個內容解析者。常用于數據庫內容發生變化后,通知界面做相應變化。
在某個應用的內容提供者類中通過內容解析者發出一個通知變化
?? public Uri insert(Uri uri, ContentValues values) {//TODO Auto-generated method stubintresult = sUriMatcher.match(uri);if(result == INSERT_MATCHED) {SQLiteDatabasedb = helper.getReadableDatabase();longinsert = db.insert("info", null, values);db.close();getContext().getContentResolver().notifyChange(uri,null);returnUri.parse(String.valueOf(insert));}else {returnnull;}}創建一個內容觀察者的項目
編寫觀察的業務邏輯
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ContentResolverresolver = getContentResolver();Uriuri = Uri.parse("content://com.ten.provider/insert");MyObserverobserver = new MyObserver(new Handler());resolver.registerContentObserver(uri,false, observer);}privateclass MyObserver extends ContentObserver {publicMyObserver(Handler handler) {super(handler);//TODO Auto-generated constructor stub}@Overridepublicvoid onChange(boolean selfChange, Uri uri) {//TODO Auto-generated method stubSystem.out.println(uri);}}}十二、?????????多媒體
關于圖片、音頻是視頻相關的。
1.????????計算機表示圖片的方式
BMP,質量最高,用于計算機。
PNG,質量高,用于計算機、網絡,android中的圖片資源一般使用這種格式。
jpeg,較高質量,用于計算機、網絡、電子右鍵。
gif,質量最差,用于計算機、網絡、電子郵件、動圖。
單色位圖,一個像素用一位2進制數表示。比如,100*100像素的圖片,大小為10000/8= 1250byte。
16色位圖,一個像素16種顏色,也就是4位2進制數,100*100像素的圖片,大小為10000*4/8 = 5000byte。
256色位圖,一個像素256種顏色,也就是8位2進制數,也就是1byte,100*100像素的圖片,大小為10000*8/8=10000byte。
24位位圖,一個像素用24位2進制數表示,也就是3個字節,100*100像素的圖片,大小為10000*24/8=30000byte。
anroid中的圖片使用的argb8888,一個像素就是32位2進制數表示,也就是4個字節,100*100像素的圖片,大小為10000*4= 40000byte。
2.????????加載大圖
可能會發生內存溢出的異常,因為手機出廠時,應用的對內存的大小已經固定,所以,只能通過壓縮圖片的方式來加載大圖。
創建一個項目,設計UI,一個按鈕一個圖片控件。
編寫業務邏輯。
public class MainActivity extends Activity {privateImageView iv_pic;privateString path = "mnt/sdcard/11.jpg";privateint width;privateint height;privatePoint p;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_pic= (ImageView) findViewById(R.id.iv_pic);height= getWindowManager().getDefaultDisplay().getHeight();width= getWindowManager().getDefaultDisplay().getWidth();System.out.println(width+ ":" + height);p= new Point();getWindowManager().getDefaultDisplay().getSize(p);System.out.println(p.x+ ":" + p.y);}publicvoid loadpic(View v) {//Bitmap bm = BitmapFactory.decodeFile(path);//iv_pic.setImageBitmap(bm);loadpic3();}publicvoid loadpic1() {BitmapFactory.Optionsoptions = new Options();options.inSampleSize= 2;Bitmapbm = BitmapFactory.decodeFile(path, options);iv_pic.setImageBitmap(bm);}publicvoid loadpic2() {BitmapFactory.Optionsopts = new Options();opts.inJustDecodeBounds= true;Bitmapbm = BitmapFactory.decodeFile(path, opts);intpicW = opts.outWidth;intpicH = opts.outHeight;if(bm == null) {System.out.println("圖片的寬度:" + picW + ";圖片的高度:" +picH);}if(picW > width || picH > height) {intwidthIndex = Math.round((float) picW / (float) width);intheightIndex = Math.round((float) picH / (float) height);opts.inSampleSize= Math.max(widthIndex, heightIndex);}opts.inJustDecodeBounds= false;bm= BitmapFactory.decodeFile(path, opts);iv_pic.setImageBitmap(bm);}publicvoid loadpic3() {BitmapFactory.Optionsopts = new Options();opts.inSampleSize= 1;Bitmapbm = null;inti = 1;for(;;) {try{opts.inSampleSize= i;bm= BitmapFactory.decodeFile(path, opts);break;}catch (Error e) {i*= 2;System.out.println("i="+ i);}}iv_pic.setImageBitmap(bm);}}3.????????創建圖片副本
創建圖片副本,使用到Canvas類。創建一個項目,設計UI一個圖片顯示控件,編寫業務邏輯。
public class MainActivity extends Activity {privateImageView iv_image;privateString path;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_image= (ImageView) findViewById(R.id.iv_image);//iv_image.setImageResource(R.drawable.c);Bitmapbm = BitmapFactory.decodeResource(getResources(), R.drawable.c);//iv_image.setImageBitmap(bm);//bm.setPixel(40, 40, Color.RED);//iv_image.setImageBitmap(bm);Bitmapcopybm = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),bm.getConfig());Canvascanvas = new Canvas(copybm);Matrixmatrix = new Matrix();Paintpaint = new Paint();canvas.drawBitmap(bm,matrix, paint);for(int i = 0; i < 20; i++) {copybm.setPixel(40+ i, 40 + i, Color.RED);}iv_image.setImageBitmap(copybm);}}4.????????處理圖片
使用Matrix類的方法處理圖片。
創建一個項目,設計UI,添加兩個圖片顯示控件,編寫業務邏輯。
public class MainActivity extends Activity {privateImageView iv_dest;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_dest= (ImageView) findViewById(R.id.iv_dest);Bitmapbm = BitmapFactory.decodeResource(getResources(), R.drawable.b);intpicW = bm.getWidth();intpicH = bm.getHeight();Bitmapcopybm = Bitmap.createBitmap(picW, picH, bm.getConfig());Canvascanvas = new Canvas(copybm);Matrixmatrix = new Matrix();//matrix.setRotate(60, picW / 2, picH / 2);//matrix.setTranslate(30, 20);//matrix.setScale(0.5F, 0.5F);//matrix.setScale(-1f, 1f);//matrix.postTranslate(copybm.getWidth(), 0);matrix.setScale(1F,-1F);matrix.postTranslate(0,copybm.getHeight());Paintpaint = new Paint();canvas.drawBitmap(bm,matrix, paint);iv_dest.setImageBitmap(copybm);}}5.????????畫畫板
簡單的畫畫的功能,創建一個項目,設計UI,添加變化顏色和線條的按鈕以及保存的按鈕。
編寫業務邏輯
public class MainActivity extends Activity {privateImageView iv_image;privateCanvas canvas;privatePaint paint;privateBitmap copybm;privateBitmap bm;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_image= (ImageView) findViewById(R.id.iv_image);bm= BitmapFactory.decodeResource(getResources(), R.drawable.bj);copybm= Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),bm.getConfig());canvas= new Canvas(copybm);Matrixmatrix = new Matrix();paint= new Paint();canvas.drawBitmap(bm,matrix, paint);iv_image.setImageBitmap(copybm);iv_image.setOnTouchListener(newOnTouchListener() {privatefloat startX;privatefloat startY;@Overridepublic boolean onTouch(Viewview, MotionEvent event) {//TODO Auto-generated method stubintaction = event.getAction();switch(action) {caseMotionEvent.ACTION_DOWN:System.out.println("按下");startX= event.getX();startY= event.getY();break;caseMotionEvent.ACTION_MOVE:System.out.println("移動");floatx = event.getX();floaty = event.getY();System.out.println(x+ ":" + y);canvas.drawLine(startX,startY, x, y, paint);startX= x;startY= y;iv_image.setImageBitmap(copybm);break;caseMotionEvent.ACTION_UP:System.out.println("抬起");break;default:break;}returntrue;}});}publicvoid changeColor(View v) {paint.setColor(Color.RED);}publicvoid changeBold(View v) {paint.setStrokeWidth(5f);}publicvoid save(View v) {Filefile = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+ ".png");FileOutputStreamfos = null;try{fos= new FileOutputStream(file);copybm.compress(CompressFormat.PNG,100, fos);Intentintent = new Intent();intent.setAction(Intent.ACTION_MEDIA_MOUNTED);intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));sendBroadcast(intent);}catch (FileNotFoundException e) {//TODO Auto-generated catch blocke.printStackTrace();}finally {if(fos != null) {try{fos.close();}catch (IOException e) {//TODO Auto-generated catch blocke.printStackTrace();}}}}}6.????????撕衣服應用
利用兩種內容大致相同的圖片,一張覆蓋另一張,使用觸摸事件修改上圖的透明度,看起來像撕衣服的效果。
創建項目,設計UI,編寫業務邏輯。
public class MainActivity extends Activity {privateImageView iv_front;privateMatrix matrix;privatePaint paint;privateBitmap copybm;privateBitmap bm;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_front= (ImageView) findViewById(R.id.iv_front);bm= BitmapFactory.decodeResource(getResources(), R.drawable.s1);copybm= Bitmap.createBitmap(bm.getWidth(), bm.getHeight(),bm.getConfig());Canvascanvas = new Canvas(copybm);matrix= new Matrix();paint= new Paint();canvas.drawBitmap(bm,matrix, paint);iv_front.setImageBitmap(copybm);iv_front.setOnTouchListener(newOnTouchListener() {privatefloat startX;privatefloat startY;@Overridepublicboolean onTouch(View v, MotionEvent event) {//TODO Auto-generated method stubintaction = event.getAction();switch(action) {caseMotionEvent.ACTION_DOWN:break;caseMotionEvent.ACTION_MOVE:floatx = event.getX();floaty = event.getY();try{for(int i = -6; i < 7; i++) {for(int j = -6; j < 7; j++) {if(Math.sqrt(i * i + j * j) <= 6) {copybm.setPixel((int)x + i, (int) y + j,Color.TRANSPARENT);}}}}catch (Exception e) {}iv_front.setImageBitmap(copybm);break;caseMotionEvent.ACTION_UP:break;}returntrue;}});}}7.????????音樂播放器
使用MediaPlayer類實現一個音樂播放器,需要使用混合服務。
創建一個項目,設計UI,一個控制按鈕和一個進度條。創建音樂控制的服務。
public class MusicPlayerService extends Service{privateString path = "mnt/sdcard/gbqq.mp3";privateMediaPlayer player;@OverridepublicIBinder onBind(Intent intent) {//TODO Auto-generated method stubreturnnew MyBinder();}publicclass MyBinder extends Binder {publicvoid playPause() {if(player.isPlaying()) {player.pause();}else {player.start();}}publicboolean isPlaying() {returnplayer.isPlaying();}publicint getDuration() {returnplayer.getDuration();}publicint getCurrentPosition() {returnplayer.getCurrentPosition();}publicvoid seekTo(int msec) {player.seekTo(msec);}}@Overridepublicvoid onCreate() {//TODO Auto-generated method stubsuper.onCreate();player= new MediaPlayer();try{player.setDataSource(path);player.prepare();}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}}編寫業務邏輯
public class MainActivity extends Activity {privatestatic final int UPDATE_PROGRESS = 0;privateString path = "mnt/sdcard/gbqq.mp3";privateMyConnection conn;privateIntent service;privateMyBinder playerController;privateImageButton ib_controller;privateSeekBar sb_progress;privateHandler handler = new Handler() {publicvoid handleMessage(android.os.Message msg) {switch(msg.what) {caseUPDATE_PROGRESS:updateProgress();break;default:break;}};};@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ib_controller= (ImageButton) findViewById(R.id.ib_controller);sb_progress= (SeekBar) findViewById(R.id.sb_progress);sb_progress.setOnSeekBarChangeListener(newOnSeekBarChangeListener() {@Overridepublicvoid onStopTrackingTouch(SeekBar seekBar) {//TODO Auto-generated method stub}@Overridepublicvoid onStartTrackingTouch(SeekBar seekBar) {//TODO Auto-generated method stub}@Overridepublicvoid onProgressChanged(SeekBar seekBar, int progress,booleanfromUser) {//TODO Auto-generated method stubif(fromUser) {playerController.seekTo(progress);}}});service= new Intent(this, MusicPlayerService.class);startService(service);conn= new MyConnection();bindService(service,conn, BIND_AUTO_CREATE);}publicvoid play(View v) {//MediaPlayer player = new MediaPlayer();//try {//player.setDataSource(path);//player.prepare();//player.start();//} catch (Exception e) {TODO Auto-generated catch block//e.printStackTrace();//}playerController.playPause();updatePlayIcon();}publicclass MyConnection implements ServiceConnection {@Overridepublicvoid onServiceConnected(ComponentName name, IBinder service) {playerController= (MyBinder) service;updatePlayIcon();sb_progress.setMax(playerController.getDuration());sb_progress.setProgress(playerController.getCurrentPosition());}@Overridepublicvoid onServiceDisconnected(ComponentName name) {//TODO Auto-generated method stub}}@Overrideprotectedvoid onResume() {//TODO Auto-generated method stubsuper.onResume();if(playerController != null) {handler.sendEmptyMessage(UPDATE_PROGRESS);}}@Overrideprotectedvoid onStop() {//TODO Auto-generated method stubsuper.onStop();handler.removeCallbacksAndMessages(null);}@Overrideprotectedvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();unbindService(conn);}publicvoid updatePlayIcon() {if(playerController.isPlaying()) {ib_controller.setImageResource(R.drawable.pause);handler.sendEmptyMessage(UPDATE_PROGRESS);}else {ib_controller.setImageResource(R.drawable.play);handler.removeMessages(UPDATE_PROGRESS);}}publicvoid updateProgress() {System.out.println("updateProgress");intcurrentPosition = playerController.getCurrentPosition();sb_progress.setProgress(currentPosition);handler.sendEmptyMessageDelayed(UPDATE_PROGRESS,500);}}8.????????MediaPlayer播放網絡音樂
創建一個項目,設計UI,一個按鈕。
編寫業務邏輯。
public class MainActivity extends Activity {privateMediaPlayer player;privateString path = "http://192.168.0.101:8080/gbqq.mp3";privateButton btn_controller;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_controller= (Button) findViewById(R.id.btn_controller);}publicvoid play(View v) {if(player == null) {player= new MediaPlayer();btn_controller.setText("暫停");try{player.setDataSource(path);player.prepareAsync();player.setOnPreparedListener(newOnPreparedListener() {@Overridepublicvoid onPrepared(MediaPlayer mp) {//TODO Auto-generated method stubmp.start();}});}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}else {if(player.isPlaying()) {btn_controller.setText("播放");player.pause();}else {btn_controller.setText("暫停");player.start();}}}}9.????????MediaPlayer播放網絡視頻
創建一個項目,設計UI,添加兩個按鈕和一個SuifaceView。編寫業務邏輯。
public class MainActivity extends Activity {privateSurfaceView sv_video;privateString path = "http://192.168.0.101:8080/v1.mp4";privateSurfaceHolder sh;privateMediaPlayer player;privateButton btn_play;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btn_play= (Button) findViewById(R.id.btn_play);sv_video= (SurfaceView) findViewById(R.id.sv_video);sh= sv_video.getHolder();}publicvoid prepare(View v) {player= new MediaPlayer();try{player.setDataSource(path);player.prepareAsync();player.setDisplay(sh);player.setOnPreparedListener(newOnPreparedListener() {@Overridepublicvoid onPrepared(MediaPlayer mp) {//TODO Auto-generated method stubmp.start();btn_play.setText("暫停");}});}catch (Exception e) {//TODO Auto-generated catch blocke.printStackTrace();}}publicvoid play(View v) {if(player != null) {if(player.isPlaying()) {player.pause();btn_play.setText("播放");}else {player.start();btn_play.setText("暫停");}}}}SurfaceView是重量級的控件,加載需要一些時間。
10.?????VideoView
VideoView是對MediaPlayer和SurfaceView的封裝。
創建一個項目,設計UI,編寫業務邏輯。
public class MainActivity extends Activity {privateVideoView vv_video;privateString path = "http://192.168.0.101:8080/v1.mp4";@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);vv_video= (VideoView) findViewById(R.id.vv_video);}publicvoid prepare(View v) {vv_video.setVideoPath(path);vv_video.setOnPreparedListener(newOnPreparedListener() {@Overridepublicvoid onPrepared(MediaPlayer mp) {//TODO Auto-generated method stubvv_video.start();}});vv_video.setMediaController(newMediaController(this));}publicvoid play(View v) {}}VidwoView能夠支持的視頻格式有限的。
11.?????Vitamio
Vitamio是一個支持android/IOS的多媒體開發框架,支持眾多常見的音視頻格式。
下載vitamio的源碼包,導入到eclipse,導入時將項目拷貝到工作臺,右鍵源碼項目>properties>Android>勾選isLibrary。
創建一個項目,右鍵項目>properties>Android>Add>添加vitamio的庫。將vitamio的初始化activity聲明到清單文件。
<activity android:name="io.vov.vitamio.activity.InitActivity"></activity>
在UI中,使用vitamio的VideoView,編寫業務邏輯
public class MainActivity extends Activity {privateVideoView vv_video;privateString path = "http://192.168.0.101:8080/v1.mp4";@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if(!Vitamio.isInitialized(this)) {return;}setContentView(R.layout.activity_main);vv_video= (VideoView) findViewById(R.id.vv_video);}publicvoid prepare(View v) {vv_video.setVideoPath(path);vv_video.setOnPreparedListener(newOnPreparedListener() {@Overridepublicvoid onPrepared(MediaPlayer mp) {//TODO Auto-generated method stubvv_video.start();}});vv_video.setMediaController(newMediaController(this));}publicvoid play(View v) {}}類似的框架還有VLC。
十三、?????????Fragment
1.????????簡介
Fragment是Android3.0后引入的一個API,起初是為了適應大屏幕的平板電腦,現在也被應用于平板。后來,智能手機也使用了Fragment,字面意思是碎片、片段,可以理解為是Activity片段。使用Fragment可以把屏幕劃分為幾塊,然后進行分組,便于實現模塊化的管理。Fragment不能單獨使用,需要嵌套在Activity中使用。
2.????????靜態加載Fragment
創建一個項目,創建fragment的布局文件。
<RelativeLayoutxmlns: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="com.example.fragmentindoor.MainActivity" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="第一個Fragment"/></RelativeLayout><RelativeLayoutxmlns: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="com.example.fragmentindoor.MainActivity" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="20sp"android:textColor="#00ff00"android:text="第二個Fragment"/></RelativeLayout>編寫兩個Fragment類。
public class FirstFragment extends Fragment {@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_first, null);returnview;}}public class SecondFragment extends Fragment {@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_second, null);returnview;}}在主布局文件中,聲明fragment節點,注意f小寫并且聲明id。
<LinearLayoutxmlns: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"android:orientation="horizontal"tools:context="com.example.fragmentindoor.MainActivity" ><fragmentandroid:name="com.example.fragmentindoor.FirstFragment"android:id="@+id/first"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"/><fragmentandroid:name="com.example.fragmentindoor.SecondFragment"android:id="@+id/second"android:layout_weight="2"android:layout_width="0dp"android:layout_height="match_parent"/></LinearLayout>3.????????動態替換fragment
創建一個項目,設計UI,為動態替換的fragment添加一個容器。
<RelativeLayoutxmlns: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="com.example.replacefragmentdynamically.MainActivity"><TextViewandroid:id="@+id/text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world" /><LinearLayoutandroid:id="@+id/fragemnt_container"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_below="@id/text"android:orientation="vertical"></LinearLayout></RelativeLayout>創建兩個fragment布局文件。
創建兩個Fragment類。
public class FirstFragment extends Fragment {@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_first, null);returnview;}}public class SecondFragment extends Fragment {@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_second, null);returnview;}}動態替換
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);intwidth = getWindowManager().getDefaultDisplay().getWidth();intheight = getWindowManager().getDefaultDisplay().getHeight();FragmentManagermanager = getFragmentManager();FragmentTransactiontransaction = manager.beginTransaction();if(width > height) {transaction.replace(R.id.fragemnt_container,new SecondFragment());}else {transaction.replace(R.id.fragemnt_container,new FirstFragment());}transaction.commit();}}4.????????使用動態fragment制作選項卡的例子
創建一個項目,設計主布局UI,最下4個圖片按鈕,上面一個fragment容器。
<RelativeLayoutxmlns: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="com.example.wechatview.MainActivity"><LinearLayoutandroid:id="@+id/ll_button"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:orientation="horizontal"android:background="@drawable/bg"android:gravity="center_vertical"><ImageButtonandroid:id="@+id/ib_chat"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@null"android:src="@drawable/wechat"/><ImageButtonandroid:id="@+id/ib_contact"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@null"android:src="@drawable/contacts"/><ImageButtonandroid:id="@+id/ib_find"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@null"android:src="@drawable/find"/><ImageButtonandroid:id="@+id/ib_me"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:background="@null"android:src="@drawable/me"/></LinearLayout><LinearLayoutandroid:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@id/ll_button"android:orientation="vertical"></LinearLayout></RelativeLayout>創建4個fragment布局
創建4個fragment類。
在主布局類中編寫選項卡邏輯。
public class MainActivity extends Activityimplementsandroid.view.View.OnClickListener{privateImageButton ib_chat;privateImageButton ib_contact;privateImageButton ib_find;privateImageButton ib_me;privateChatFragment chatFragment;privateContactsFragment contactsFragment;privateFindFragment findFragment;privateMeFragment meFragment;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ib_chat= (ImageButton) findViewById(R.id.ib_chat);ib_contact= (ImageButton) findViewById(R.id.ib_contact);ib_find= (ImageButton) findViewById(R.id.ib_find);ib_me= (ImageButton) findViewById(R.id.ib_me);ib_chat.setOnClickListener(this);ib_contact.setOnClickListener(this);ib_find.setOnClickListener(this);ib_me.setOnClickListener(this);ib_chat.performClick();}@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stubclearIcon();FragmentManagermanager = getFragmentManager();FragmentTransactiontransaction = manager.beginTransaction();switch(v.getId()) {caseR.id.ib_chat:if(chatFragment == null) {chatFragment= new ChatFragment();}transaction.replace(R.id.fragment_container,chatFragment);ib_chat.setImageResource(R.drawable.wechat2);break;caseR.id.ib_contact:if(contactsFragment == null) {contactsFragment= new ContactsFragment();}transaction.replace(R.id.fragment_container,contactsFragment);ib_contact.setImageResource(R.drawable.contacts2);break;caseR.id.ib_find:if(findFragment == null) {findFragment= new FindFragment();}transaction.replace(R.id.fragment_container,findFragment);ib_find.setImageResource(R.drawable.find2);break;caseR.id.ib_me:if(meFragment == null) {meFragment= new MeFragment();}transaction.replace(R.id.fragment_container,meFragment);ib_me.setImageResource(R.drawable.me2);break;}transaction.commit();}privatevoid clearIcon() {ib_chat.setImageResource(R.drawable.wechat);ib_contact.setImageResource(R.drawable.contacts);ib_find.setImageResource(R.drawable.find);ib_me.setImageResource(R.drawable.me);}}5.????????兼容低版本的fragment方法
跟fragment相關的api都要調用android.support.v4.app包的。
創建一個項目,在主UI中添加一個LinearLaytou作為fragment容器。
編寫一個fragment布局,創建這個布局的類。
public class LowerFragment extends Fragment {@OverridepublicView onCreateView(LayoutInflater inflater,@NullableViewGroup container, @Nullable Bundle savedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_lower, null);returnnull;}}動態替換,主activity要繼承自FragmentActivity。
public class MainActivity extendsFragmentActivity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//FragmentManager manager = getFragmentManager();FragmentManagermanager = getSupportFragmentManager();FragmentTransactiontransaction = manager.beginTransaction();transaction.replace(R.id.fragment_container,new LowerFragment());transaction.commit();}}6.????????關于fragment中的點擊事件
fragment中點擊事件一般不采用第四種寫法,即在xml中聲明onclick屬性的寫法。而是在對應的Fragment類中使用setOnClickListener()的方法。
7.????????fragment的生命周期
創建一個項目,在主UI中添加一個fragment容器,創建一個fragment布局,創建fragment類。
public class FirstFragment extends Fragment {@Overridepublicvoid onAttach(Activity activity) {//TODO Auto-generated method stubsuper.onAttach(activity);System.out.println("onAttach");}@Overridepublicvoid onCreate(Bundle savedInstanceState) {//TODO Auto-generated method stubsuper.onCreate(savedInstanceState);System.out.println("onCreate");}@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_first, null);System.out.println("onCreateView");returnview;}@Overridepublicvoid onActivityCreated(Bundle savedInstanceState) {//TODO Auto-generated method stubsuper.onActivityCreated(savedInstanceState);System.out.println("onActivityCreated");}@Overridepublicvoid onStart() {//TODO Auto-generated method stubsuper.onStart();System.out.println("onStart");}@Overridepublicvoid onResume() {//TODO Auto-generated method stubsuper.onResume();System.out.println("onResume");}@Overridepublicvoid onPause() {//TODO Auto-generated method stubsuper.onPause();System.out.println("onPause");}@Overridepublicvoid onStop() {//TODO Auto-generated method stubsuper.onStop();System.out.println("onStop");}@Overridepublicvoid onDestroyView() {//TODO Auto-generated method stubsuper.onDestroyView();System.out.println("onDestroyView");}@Overridepublicvoid onDestroy() {//TODO Auto-generated method stubsuper.onDestroy();System.out.println("onDestroy");}@Overridepublicvoid onDetach() {//TODO Auto-generated method stubsuper.onDetach();System.out.println("onDetach");}}動態替換之
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);FragmentManagermanager = getFragmentManager();FragmentTransactiontransaction = manager.beginTransaction();transaction.replace(R.id.fragment_container,new FirstFragment());transaction.commit();}}8.????????fragment之間的通信
創建一個項目,設計UI,添加兩個fragment的容器,創建兩個fragment布局,其中一個添加一個按鈕。
創建兩個fragment類。
public class FirstFragment extends Fragment {@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_first, null);Buttonbtn = (Button) view.findViewById(R.id.btn);btn.setOnClickListener(newOnClickListener() {@Overridepublicvoid onClick(View v) {//TODO Auto-generated method stub//SecondFragment second = new SecondFragment();SecondFragmentsecond = (SecondFragment) getActivity().getFragmentManager().findFragmentByTag("right");second.changeStr("測試修改");}});returnview;}}public class SecondFragment extends Fragment {privateTextView tv_text;@OverridepublicView onCreateView(LayoutInflater inflater, ViewGroup container,BundlesavedInstanceState) {//TODO Auto-generated method stubViewview = inflater.inflate(R.layout.fragment_second, null);tv_text= (TextView) view.findViewById(R.id.tv_text);returnview;}publicvoid changeStr(String str) {tv_text.setText(str);}}動態替換
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);FragmentManagermanager = getFragmentManager();FragmentTransactiontransaction = manager.beginTransaction();transaction.replace(R.id.ll_left,new FirstFragment(), "left");transaction.replace(R.id.ll_right,new SecondFragment(), "right");transaction.commit();}}十四、?????????menu菜單
menu菜單在app中也會被使用到。
創建一個項目,在menu目錄的main.xml文件中添加兩個菜單選項。
<menuxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"tools:context="com.example.menu.MainActivity" ><itemandroid:id="@+id/action_settings"android:orderInCategory="100"android:showAsAction="never"android:title="@string/action_settings"/><itemandroid:id="@+id/action_settings1"android:orderInCategory="80"android:showAsAction="never"android:title="菜單項1"/><itemandroid:id="@+id/action_settings2"android:orderInCategory="60"android:showAsAction="never"android:title="菜單項2"/></menu>編寫業務邏輯。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublicboolean onCreateOptionsMenu(Menu menu) {//Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main,menu);returntrue;}@Overridepublicboolean onOptionsItemSelected(MenuItem item) {//Handle action bar item clicks here. The action bar will//automatically handle clicks on the Home/Up button, so long//as you specify a parent activity in AndroidManifest.xml.intid = item.getItemId();switch(id) {caseR.id.action_settings:Toast.makeText(getApplicationContext(),"主菜單",Toast.LENGTH_SHORT).show();break;caseR.id.action_settings1:Toast.makeText(getApplicationContext(),"菜單1",Toast.LENGTH_SHORT).show();break;caseR.id.action_settings2:Toast.makeText(getApplicationContext(),"菜單2",Toast.LENGTH_SHORT).show();break;}returnsuper.onOptionsItemSelected(item);}@Overridepublicboolean onMenuOpened(int featureId, Menu menu) {//TODO Auto-generated method stubAlertDialog.Builderbuilder = new Builder(this);builder.setTitle("菜單選項卡");builder.setMessage("請選擇");builder.setPositiveButton("確定", new OnClickListener() {@Overridepublicvoid onClick(DialogInterface dialog, int which) {//TODO Auto-generated method stubToast.makeText(getApplicationContext(),"菜單確定",Toast.LENGTH_SHORT).show();}});builder.show();returnfalse;}}十五、?????????自動補全TextView
在用戶輸入時,提供補全下拉列表。
創建一個項目,設計UI,添加一個AutoCompleteTextView。
<RelativeLayoutxmlns: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="com.example.autocompletetextview.MainActivity"><AutoCompleteTextViewandroid:id="@+id/actv_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:completionThreshold="1"android:hint="請輸入內容"/></RelativeLayout>創建一個下拉列表item。
編寫業務邏輯。
public class MainActivity extends Activity {privateAutoCompleteTextView actv_text;privateString[] strings = { "哈哈","heh", "l了" };@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);actv_text= (AutoCompleteTextView) findViewById(R.id.actv_text);ArrayAdapter<String>adapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.item, strings);actv_text.setAdapter(adapter);}}十六、?????????動畫
動畫會在app中被使用到。
1.????????幀動畫
創建一個項目,在res目錄下創建一個drawable文件夾,放入幀素材圖片,并創建一個幀動畫的xml文件。
<?xml version="1.0"encoding="utf-8"?><animation-listxmlns:android="http://schemas.android.com/apk/res/android" ><item android:drawable="@drawable/a1" android:duration="200"/><item android:drawable="@drawable/a2"android:duration="200" /><itemandroid:drawable="@drawable/a3" android:duration="200"/><itemandroid:drawable="@drawable/a4" android:duration="200"/><itemandroid:drawable="@drawable/a5" android:duration="200"/><itemandroid:drawable="@drawable/a6" android:duration="200"/><itemandroid:drawable="@drawable/a7" android:duration="200"/><itemandroid:drawable="@drawable/a8" android:duration="200"/></animation-list>設計UI,添加一個圖片view控件,來放幀素材,設置background為幀素材文件夾的animation。
???<ImageViewandroid:id="@+id/iv_image"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/animation"android:layout_centerInParent="true"/>編寫幀動畫業務邏輯
public class MainActivity extends Activity {privateImageView iv_image;privateAnimationDrawable background;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_image= (ImageView) findViewById(R.id.iv_image);background= (AnimationDrawable) iv_image.getBackground();iv_image.setOnTouchListener(newOnTouchListener() {@Overridepublicboolean onTouch(View v, MotionEvent event) {//TODO Auto-generated method stubif(background.isRunning()) {background.stop();}else {background.start();}returnfalse;}});}}2.????????補間動畫
創建一個項目,設計UI,添加幾個動畫的按鈕,添加一個ImageView,操作這個圖片。
編寫業務邏輯
public class MainActivity extends Activity {privateImageView iv_image;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_image= (ImageView) findViewById(R.id.iv_image);}publicvoid alpha(View view) {AlphaAnimationalpha = new AlphaAnimation(1.0f, 0.5f);alpha.setDuration(5000);alpha.setRepeatMode(Animation.RESTART);alpha.setRepeatCount(2);alpha.setFillAfter(true);iv_image.setAnimation(alpha);alpha.start();}publicvoid rotate(View view) {iv_image.getX();RotateAnimationrotate = new RotateAnimation(0, 360);intpivotXType = Animation.RELATIVE_TO_SELF;floatpivotXValue = 0.5f;intpivotYType = Animation.RELATIVE_TO_SELF;floatpivotYValue = 0.5f;rotate= new RotateAnimation(0, 360, pivotXType, pivotXValue,pivotYType,pivotYValue);rotate.setDuration(2000);rotate.setRepeatMode(Animation.RESTART);rotate.setRepeatCount(2);rotate.setFillAfter(true);iv_image.setAnimation(rotate);rotate.start();}publicvoid scale(View view) {ScaleAnimationanimation = new ScaleAnimation(1, 2, 1, 2);intpivotXType = Animation.RELATIVE_TO_SELF;floatpivotXValue = 0.5f;intpivotYType = Animation.RELATIVE_TO_SELF;floatpivotYValue = 0.5f;animation= new ScaleAnimation(1, 2, 1, 2, pivotXType, pivotXValue,pivotYType= Animation.RELATIVE_TO_SELF, pivotYValue);animation.setDuration(2000);animation.setRepeatMode(Animation.RESTART);animation.setRepeatCount(2);animation.setFillAfter(true);iv_image.setAnimation(animation);}publicvoid translate(View view) {TranslateAnimationanimation = new TranslateAnimation(10, 100, 10, 100);intfromXType = Animation.RELATIVE_TO_PARENT;floatfromXValue = -0.5f;inttoXType = Animation.RELATIVE_TO_PARENT;floattoXValue = 0.5f;intfromYType = Animation.RELATIVE_TO_PARENT;floatfromYValue = -0.5f;inttoYType = Animation.RELATIVE_TO_PARENT;floattoYValue = 0.5f;animation= new TranslateAnimation(fromXType, fromXValue, toXType,toXValue,fromYType, fromYValue, toYType, toYValue);animation.setDuration(1000);animation.setRepeatCount(2);animation.setRepeatMode(Animation.RESTART);animation.setFillAfter(true);animation.setInterpolator(newAccelerateDecelerateInterpolator());iv_image.setAnimation(animation);animation.start();}publicvoid set(View view) {AnimationSetset = new AnimationSet(false);AlphaAnimationalpha = new AlphaAnimation(1.0f, 0.5f);alpha.setDuration(5000);alpha.setRepeatMode(Animation.RESTART);alpha.setRepeatCount(2);alpha.setFillAfter(true);set.addAnimation(alpha);RotateAnimationrotate = new RotateAnimation(0, 360);intpivotXType = Animation.RELATIVE_TO_SELF;floatpivotXValue = 0.5f;intpivotYType = Animation.RELATIVE_TO_SELF;floatpivotYValue = 0.5f;rotate= new RotateAnimation(0, 360, pivotXType, pivotXValue,pivotYType,pivotYValue);rotate.setDuration(2000);rotate.setRepeatMode(Animation.RESTART);rotate.setRepeatCount(2);rotate.setFillAfter(true);set.addAnimation(rotate);ScaleAnimationscale = new ScaleAnimation(1, 2, 1, 2);scale= new ScaleAnimation(1, 2, 1, 2, pivotXType, pivotXValue,pivotYType= Animation.RELATIVE_TO_SELF, pivotYValue);scale.setDuration(2000);scale.setRepeatMode(Animation.RESTART);scale.setRepeatCount(2);scale.setFillAfter(true);set.addAnimation(scale);TranslateAnimationtranslate = new TranslateAnimation(10, 100, 10, 100);intfromXType = Animation.RELATIVE_TO_PARENT;floatfromXValue = -0.5f;inttoXType = Animation.RELATIVE_TO_PARENT;floattoXValue = 0.5f;intfromYType = Animation.RELATIVE_TO_PARENT;floatfromYValue = -0.5f;inttoYType = Animation.RELATIVE_TO_PARENT;floattoYValue = 0.5f;translate= new TranslateAnimation(fromXType, fromXValue, toXType,toXValue,fromYType, fromYValue, toYType, toYValue);translate.setDuration(1000);translate.setRepeatCount(2);translate.setRepeatMode(Animation.RESTART);translate.setFillAfter(true);translate.setInterpolator(newAccelerateDecelerateInterpolator());set.addAnimation(translate);iv_image.setAnimation(set);set.start();}}3.????????使用xml文件實現補間動畫
一般使用xml文件實現動畫,這樣使得代碼看起來簡潔,也有利于解耦合。
創建一個項目,添加動畫按鈕和一個imageview。
在res目錄下創建anim目錄,并且創建每個動畫的xml文件。
<?xml version="1.0"encoding="utf-8"?><alphaxmlns:android="http://schemas.android.com/apk/res/android"android:fromAlpha="1.0"android:toAlpha="0.5"android:duration="1000"android:repeatCount="2"android:repeatMode="restart"></alpha><?xml version="1.0"encoding="utf-8"?><rotatexmlns:android="http://schemas.android.com/apk/res/android"android:fromDegrees="0"android:toDegrees="245"android:pivotX="50%"android:pivotY="50%"android:duration="1000"android:repeatCount="2"android:repeatMode="restart"android:fillAfter="true"><?xml version="1.0"encoding="utf-8"?><scalexmlns:android="http://schemas.android.com/apk/res/android"android:fromXScale="1"android:toXScale="2"android:fromYScale="1"android:toYScale="2"android:pivotX="50%"android:pivotY="50%"android:duration="1000"android:repeatCount="2"android:repeatMode="reverse"android:fillAfter="true"></scale><?xml version="1.0"encoding="utf-8"?><translatexmlns:android="http://schemas.android.com/apk/res/android"android:fromXDelta="10"android:toXDelta="100"android:fromYDelta="10"android:toYDelta="100"android:duration="1000"android:repeatCount="2"android:interpolator="@android:anim/cycle_interpolator"android:repeatMode="reverse"android:fillAfter="true"></translate><?xml version="1.0"encoding="utf-8"?><setxmlns:android="http://schemas.android.com/apk/res/android"android:shareInterpolator="false"><translateandroid:fromXDelta="0"android:fromYDelta="0"android:toXDelta="200%"android:toYDelta="0" /><setandroid:interpolator="@android:anim/accelerate_interpolator"><scaleandroid:fromXScale="1.0"android:fromYScale="1.0"android:pivotX="0%"android:pivotY="100%"android:toXScale="1.5"android:toYScale="1.5" /><rotatexmlns:android="http://schemas.android.com/apk/res/android"android:fromDegrees="0"android:toDegrees="245"android:pivotX="50%"android:pivotY="50%"android:duration="1000"android:repeatCount="2"android:repeatMode="restart"android:fillAfter="true"/></set></set>在主activity類中實現業務邏輯
public class MainActivity extends Activity {privateImageView iv_image;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_image= (ImageView) findViewById(R.id.iv_image);}publicvoid alphaX(View view) {Animationanimation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.alpha);iv_image.setAnimation(animation);animation.start();}publicvoid rotateX(View view) {Animationanimation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.rotate);iv_image.setAnimation(animation);animation.start();}publicvoid scaleX(View view) {Animationanimation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.scale);iv_image.setAnimation(animation);animation.start();}publicvoid translateX(View view) {Animationanimation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.translate);iv_image.setAnimation(animation);animation.start();}publicvoid setX(View view) {Animationanimation = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.set);iv_image.setAnimation(animation);animation.start();}}4.????????屬性動畫
使用ObjectAnimator類的ofFloat方法實現動畫。
創建一個項目,設計UI,添加動畫按鈕和一個ImageView。
如果使用xml文件實現,需要在res目錄下創建一個animator目錄,并創建animator的xml文件。
<?xml version="1.0"encoding="utf-8"?><animator xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimatorandroid:propertyName="rotation"android:duration="2000"android:valueFrom="0"android:valueTo="240"android:repeatCount="2"android:repeatMode="restart"></objectAnimator></animator>編寫業務邏輯
public class MainActivity extends Activity {privateImageView iv_image;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv_image= (ImageView) findViewById(R.id.iv_image);}publicvoid alpha(View v) {ObjectAnimatoroa = ObjectAnimator.ofFloat(iv_image, "alpha", 1.0f,0.5f,0.9f, 0.1f, 0.6f);oa.setDuration(2000);oa.start();}publicvoid rotate(View v) {ObjectAnimatoroa = ObjectAnimator.ofFloat(iv_image, "rotation", 0, 20,180,90, 360);oa.setDuration(3000);oa.start();}publicvoid scale(View v) {ObjectAnimatoroa = ObjectAnimator.ofFloat(iv_image, "scaleX", 0.2f, 2,1,3);oa.setDuration(3000);oa.start();}publicvoid translate(View v) {ObjectAnimatoroa = ObjectAnimator.ofFloat(iv_image, "translationX",10,30, 50);oa.setDuration(3000);oa.start();}publicvoid set(View v) {AnimatorSetas = new AnimatorSet();ObjectAnimatoroa1 = ObjectAnimator.ofFloat(iv_image, "alpha", 1.0f,0.5f,0.9f, 0.1f, 0.6f);ObjectAnimatoroa2 = ObjectAnimator.ofFloat(iv_image, "scaleX", 0.2f,2,1, 3);ObjectAnimatoroa3 = ObjectAnimator.ofFloat(iv_image, "rotation", 0,20,180, 90, 360);ObjectAnimatoroa4 = ObjectAnimator.ofFloat(iv_image, "translationX",10,30, 50);//as.playSequentially(oa1, oa2, oa3, oa4);as.playTogether(oa1,oa2, oa3, oa4);as.setDuration(3000);as.setTarget(iv_image);as.start();}publicvoid xmlAnimator(View view) {Animatoranimator = AnimatorInflater.loadAnimator(getApplicationContext(),R.animator.oanimator);animator.setTarget(iv_image);animator.start();}}屬性動畫和補間動畫的區別,view動畫不會改變view的屬性,屬性動畫會改變view的屬性。屬性動畫是3.0之后才有的api。
十七、?????????通知欄
通知欄在app中使用較多,比如音樂播放器、購物app、短信等。
創建一個項目,在UI中添加一個按鈕,編寫業務邏輯。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid send(View view) {Notification.Builderbuilder = new Builder(this);builder.setTicker("來通知了");builder.setAutoCancel(true);builder.setContentText("sldjf螺絲釘解放螺絲釘解放看見的路口附近的離開解放擴大");builder.setSmallIcon(R.drawable.ic_launcher);//builder.setOngoing(true);Intentintent2 = new Intent(this, MainActivity.class);PendingIntentintent = PendingIntent.getActivity(getApplicationContext(),1, intent2,PendingIntent.FLAG_UPDATE_CURRENT);builder.setContentIntent(intent);Notificationnotification = builder.build();NotificationManagermanager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);manager.notify(1,notification);}}十八、?????????JNI
java?native? interface,java本地接口。本地表示,本地語言,也就是操作系統的語言,比如windows的本地語言是c/c++,android系統是linux系統,也是c/c++。JNI,就是java和本地語言之間相互調用的接口。使用JNI可以使java間接的操作硬件;c/c++的運行效率更高,使用JNI可以提高運行效率;c語言存在時間久,開源項目豐富,使用JNI可以訪問優秀的開源項目;java的反編譯相比c的反匯編更容易泄漏源碼,使用JNI更具安全性。
c語言快速入門見https://blog.csdn.net/xingzhishen/article/details/79340449。
1.????????ndk
使用JNI,需要編譯本地語言,此時,需要進行交叉編譯。交叉編譯就是在一個平臺上編譯出在另外一個平臺上可以運行的本地代碼。NDK是一個交叉編譯工具,native? develop?kit。下載NDK。
NDK的目錄結構。
build,處理命令。
docs,幫助文檔。
platforms,平臺資源。
samples,樣例。
sources,源碼。
toolchains,工具鏈。
ndk-build.cmd,ndk編譯命令。
在eclipse的preferences>Android>NDK>選擇NDK解壓的路徑。如果沒有NDK選項,需要下載NDK插件。
2.????????一個JNI程序
創建一個項目,設計UI,添加一個調用c的按鈕。
在主activity中編寫調用邏輯。
public class MainActivity extends Activity {@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid jniHello(View view) {System.loadLibrary("hello");Toast.makeText(getApplicationContext(),helloC(), Toast.LENGTH_SHORT).show();}publicnative String helloC();}在項目路徑下創建一個jni目錄,
創建c代碼文件
#include<stdio.h>#include<stdlib.h>#include<jni.h>jstringJava_com_example_chello_MainActivity_helloC(JNIEnv* env,jobject this){char*str = "helloc";return(*env)->NewStringUTF(env,str);}創建一個Android.mk文件
LOCAL_PATH := $(call my-dir)
#清除上一次編譯的信息
include $(CLEAR_VARS)
#指定最終生成的文件的名字
LOCAL_MODULE := hello
#要編譯的c代碼的名字
LOCAL_SRC_FILES :=hello.c
#要生成的一個動態連接庫
include $(BUILD_SHARED_LIBRARY)
然后,在cmd命令中進入項目目錄,使用ndk-build命令編譯c文件。
然后,測試。
3.????????JNI開發中常見錯誤
1)????????本地方法沒有找到,比如,在java中創建的本地方法名中使用了_。
public native String hello_C();
那么在,c代碼中
jstringJava_com_example_chello_MainActivity_hello_C(JNIEnv* env,jobject this){char*str = "helloc";return(*env)->NewStringUTF(env,str);}由于包名、類名、方法名都是使用_分割的,那么方法名中_就會造成與類名的混淆,為了區分,使用1將一個整體的名字合起來,比如:
jstringJava_com_example_chello_MainActivity_hello_1C(JNIEnv* env,jobject this){char*str = "helloc";return(*env)->NewStringUTF(env,str);}對于一些很奇怪的方法名,比如h___e_____l__l__o_C(),可以使用jdk的javah工具生成JNI樣式的標頭文件。進入cmd,如果是jdk1.7及以上,進入項目的src目錄,使用javah? 類的全路徑,比如javah? com.example.chello.MainActivity。如果是jdk1.6及以下,到項目的bin/classes目錄下,運行javah。在src目錄下會生成一個.h文件。
JNIEXPORT jstring JNICALLJava_com_example_chello_MainActivity_h_1_1_1e_1_1_1_1_1l_1_1l_1_1o_1C
? (JNIEnv*, jobject);
拷貝后,刪掉生產成的.h文件。
如果沒有寫System.loadLibrary("hello");也會導致出現找不到方法名的異常。
實際上,加載庫的動作是在一類加載時就執行的,可以卸載一個靜態代碼塊中。
2)????????找庫返回空
在加載庫文件時,名字寫錯會出現這個異常。一般生成的.so文件會自動添加lib前綴,加載的文件名不需要寫lib前綴和.so擴展名。
一般,沒有特別操作,使用ndk-build生成的是armeabi的.so文件,也就是支持arm的cpu架構的編譯文件,如果在x86架構的設備上就不能運行。這就需要生成相關架構的.so文件。
解決方法是在項目的jni目下創建一個Application.mk文件,在這個文件中說明需要生成支持那些平臺的編譯文件。比如:
APP_ABI := armeabi ?x86
不同的平臺使用空格隔開。如果需要支持所有的平臺,可以簡寫為:APP_ABI := all
4.????????JNI開發簡便流程
創建一個項目,設計UI,添加一個調用c的按鈕。
在主activity中編寫本地方法,并在按鈕方法中調用之。
public class MainActivity extends Activity {static{System.loadLibrary("hello");}@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid callc(View view) {Toast.makeText(this,helloC(), Toast.LENGTH_SHORT).show();}publicnative String helloC();}添加本地支持,前提是在properties>Android>NDK中添加了NDK文件的路徑,右鍵項目>Android? Tools>add?native? support>填寫lib? name,然后在項目目錄下生成一個jni目錄,下面有cpp源碼文件和一個Android.mk文件,系統生成的是cpp文件,需要將cpp文件擴展名改為c,同時在Android.mk文件中也做相應的修改。
通過cmd,javah? 類的全路徑生成標頭文件。復制標頭文件方法。
給CDT插件,指定編譯c文件時include的目錄,右鍵項目>properties>c/c++?general>paths? and? symbols>includes>add>file? system>選擇NDK文件中的platforms,選擇一個版本,選擇include目錄>ok>ok。
編寫c源碼。
#include <jni.h>#include<stdio.h>#include<stdlib.h>JNIEXPORT jstring JNICALLJava_com_example_jnisimpleprocess_MainActivity_helloC(JNIEnv* env, jobject thiz){return(*env)->NewStringUTF(env,"hellocccc");}點擊c/c++視圖下的小錘子可以編譯c源碼,如果對c源碼確認無誤,可以不編譯,當項目部署到設備上時也會編譯的。
在主activity類中加載c庫文件
???????? static{System.loadLibrary("hello");}5.????????java傳遞數據給c
創建一個項目,設計UI,三個按鈕。
創建一個JNI方法的類,順便在這個類中加載c的lib庫。
public class JNI {static{System.loadLibrary("passparam");}publicnative int add(int x, int y);publicnative String hellc(String s);publicnative int[] arrElementsIncrease(int[] intArray);}編寫業務邏輯
public class MainActivity extends Activity {privateJNI jni;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);jni= new JNI();}publicvoid passInt(View view) {Toast.makeText(this,"result:" + jni.add(4, 5), Toast.LENGTH_SHORT).show();}publicvoid passString(View view) {Toast.makeText(this,"result:" + jni.hellc("abc"), Toast.LENGTH_SHORT).show();}publicvoid passArray(View view) {int[]arr = { 1, 2, 3, 4 };int[]result = jni.arrElementsIncrease(arr);for(int i : result) {System.out.println(i);}}}添加jni支持,右鍵項目>android? tools>add? native?support>庫名添加在JNI類中加載的庫名。
為了在c源碼文件中調用android的logcat,需要在自動生成的Android.mk文件中添加
#加載liblog.so,LDLIBS表示loadlibs
LOCAL_LDLIBS += -llog
設置C/C++的includes目錄路徑。
在cmd中使用javah生成標頭文件,復制方法名到c源碼文件,編寫c源碼文件。
#include <jni.h>#include<stdlib.h>#include<android/log.h>#define LOG_TAG "System.out"#define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)#define LOGI(...)__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)char* jstringTostring(JNIEnv* env, jstringjstr){char*rtn = NULL;jclassclsstring = (*env)->FindClass(env,"java/lang/String");jstringstrencode = (*env)->NewStringUTF(env,"utf-8");jmethodIDmid = (*env)->GetMethodID(env, clsstring, "getBytes","(Ljava/lang/String;)[B");jbyteArraybarr= (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode);jsizealen = (*env)->GetArrayLength(env, barr);jbyte*ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);if(alen > 0){rtn= (char*)malloc(alen + 1);memcpy(rtn,ba, alen);rtn[alen]= 0;}(*env)->ReleaseByteArrayElements(env,barr, ba, 0);returnrtn;}JNIEXPORT jint JNICALLJava_com_example_javatransformdatatoc_JNI_add(JNIEnv* env, jobject thiz, jint a, jint b){returna+b;}JNIEXPORT jstring JNICALLJava_com_example_javatransformdatatoc_JNI_hellc(JNIEnv* env, jobject thiz, jstring str){char*cstr = jstringTostring(env, str);intlength = strlen(cstr);inti;for(i= 0;i < length;i++){*(cstr+ i)? += 1;}return(*env)->NewStringUTF(env, cstr);}JNIEXPORT jintArray JNICALLJava_com_example_javatransformdatatoc_JNI_arrElementsIncrease(JNIEnv* env, jobject thiz, jintArray arr){intlength = (*env)->GetArrayLength(env,arr);LOGD("length=%d",length);jbooleanisCopy;int*p = (*env)->GetIntArrayElements(env,arr,NULL);inti;for(i= 0;i < length;i++){*(p+ i) += 10;}returnarr;}測試。
6.????????c反射調用java
創建一個項目,設計UI,添加4個按鈕。
編寫一個JNI類,創建jni方法,順便將clib加載進去。
public class JNI {static{System.loadLibrary("calljava");}publicvoid hello() {System.out.println("hellojava");}publicint add(int x, int y) {return x + y;}publicvoid printString(String str) {System.out.println(str);}publicnative void callvoid();publicnative int callint();publicnative void callstring();}在主activity中編寫按鈕業務邏輯,對于彈吐司的方法由于需要用到上下文,如果在c反射方法中創建4大組件,得到的上下文就是空,由兩種解決方法,一種是在組件中創建彈吐司的jni方法,另一種是在JNI類中傳遞一個上下文。
public class MainActivity extends Activity {privateJNI jni;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);jni= new JNI();}publicvoid callvoid(View view) {jni.callvoid();}publicvoid callint(View view) {jni.callint();}publicvoid callstring(View view) {jni.callstring();}publicvoid calltoast(View view) {callToast();}publicnative void callToast();publicvoid showToast(String s) {Toast.makeText(this,s, Toast.LENGTH_SHORT).show();}}添加jni支持,右鍵項目>android? tools>add? native?support>填寫JNI類中加載的庫名。修改c源碼文件名。
順便設置c/c++的includes目錄路徑。
編寫c源碼
#include <jni.h>#include<stdlib.h>#include<android/log.h>#define LOG_TAG "System.out"#define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)#define LOGI(...)__android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)JNIEXPORT void JNICALL Java_com_example_ccalljava_JNI_callvoid(JNIEnv* env, jobject thiz){jclassclazz = (*env)->FindClass(env,"com/example/ccalljava/JNI");jmethodIDmid = (*env)->GetMethodID(env,clazz,"hello","()V");(*env)->CallVoidMethod(env,thiz,mid);}JNIEXPORT jint JNICALL Java_com_example_ccalljava_JNI_callint(JNIEnv* env, jobject thiz){jclassclazz = (*env)->FindClass(env,"com/example/ccalljava/JNI");jmethodIDmid = (*env)->GetMethodID(env,clazz,"add","(II)I");intresult = (*env)->CallIntMethod(env,thiz,mid,3,5);LOGD("%d",result);}JNIEXPORT void JNICALLJava_com_example_ccalljava_JNI_callstring(JNIEnv* env, jobject thiz){jclassclazz = (*env)->FindClass(env,"com/example/ccalljava/JNI");jmethodIDmid =(*env)->GetMethodID(env,clazz,"printString","(Ljava/lang/String;)V");jstringstr = (*env)->NewStringUTF(env,"printjavajava");(*env)->CallVoidMethod(env,thiz,mid,str);}JNIEXPORT void JNICALLJava_com_example_ccalljava_MainActivity_callToast(JNIEnv* env, jobject thiz){jclassclazz = (*env)->FindClass(env,"com/example/ccalljava/MainActivity");jmethodIDmid =(*env)->GetMethodID(env,clazz,"showToast","(Ljava/lang/String;)V");//jobjectmain = (*env)->AllocObject(env,thiz);jstringstr = (*env)->NewStringUTF(env,"hellohello");(*env)->CallVoidMethod(env,thiz,mid,str);}測試。
7.????????鍋爐壓力測試app
android的app也會被應用到工業硬件設備上。
創建一個項目,設計UI,兩個控制的按鈕和一個ProgressBar。
在主activity中編寫業務邏輯,順便加載庫文件。
public class MainActivity extends Activity {static{System.loadLibrary("pressure");}privateProgressBar pb_progress;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);pb_progress= (ProgressBar) findViewById(R.id.pb_progress);pb_progress.setMax(100);}publicvoid start(View v) {newThread() {publicvoid run() {startMoniter();};}.start();}publicvoid stop(View v) {stopMoniter();}publicvoid setPressure(int pressure) {pb_progress.setProgress(pressure);}publicnative void startMoniter();publicnative void stopMoniter();}添加本地支持,修改c源碼文件名。給項目設置includes路徑。
使用javah生成標頭文件名。
編寫c源碼
#include <jni.h>#include<stdlib.h>int getPressure(){returnrand()%101;}int flag = 1;JNIEXPORT void JNICALLJava_com_example_pressurediagram_MainActivity_startMoniter(JNIEnv* env, jobject thiz){jclassclazz =(*env)->FindClass(env,"com/example/pressurediagram/MainActivity");jmethodIDmid =(*env)->GetMethodID(env,clazz,"setPressure","(I)V");flag= 1;while(flag){(*env)->CallVoidMethod(env,thiz,mid,getPressure());sleep(1);}}JNIEXPORT void JNICALLJava_com_example_pressurediagram_MainActivity_stopMoniter(JNIEnv* env, jobject thiz){flag= 0;}測試。
加入自定義控件的鍋爐壓力app
在UI中添加一個按鈕。
編寫一個自定義的控件
public class MyPressureView extends View {privateint pressure = 50;publicMyPressureView(Context context) {super(context);//TODO Auto-generated constructor stub}publicMyPressureView(Context context, AttributeSet attrs, int defStyle) {super(context,attrs, defStyle);//TODO Auto-generated constructor stub}publicMyPressureView(Context context, AttributeSet attrs) {super(context,attrs);//TODO Auto-generated constructor stub}@Overrideprotectedvoid onDraw(Canvas canvas) {//TODO Auto-generated method stubPaintpaint = new Paint();paint.setTextSize(20);if(pressure > 80) {paint.setColor(Color.RED);}else if (pressure < 40) {paint.setColor(Color.GREEN);}else {paint.setColor(Color.YELLOW);}canvas.drawText("壓力值:" + pressure, 30, 30, paint);canvas.drawRect(30,200 - pressure, 50, 200, paint);}publicvoid setPressure(int pressure) {this.pressure= pressure;postInvalidate();}}在UI中添加自定義的控件。
在主activity中添加使用自定義控件的代碼
public class MainActivity extends Activity {static{System.loadLibrary("pressure");}privateProgressBar pb_progress;publicMyPressureView pressure_view;@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);pb_progress= (ProgressBar) findViewById(R.id.pb_progress);pb_progress.setMax(100);pressure_view= (MyPressureView) findViewById(R.id.pressure);}publicvoid start(View v) {newThread() {publicvoid run() {startMoniter();};}.start();}publicvoid stop(View v) {stopMoniter();}publicvoid setPressure(int pressure) {pb_progress.setProgress(pressure);pressure_view.setPressure(pressure);}publicnative void startMoniter();publicnative void stopMoniter();}8.????????c++開發JNI
在c++下,JNIEnv不是結構體的一級指針,而是JNIEnv的別名。env就是JNIEnv的一級指針,就是結構體。訪問結構體成員,不需要(*env)->而是直接env->。c++的結構體中可以有函數,c的結構體中只能有函數指針,不能定義函數。c++的函數在使用時需要聲明,可以使用生成的標頭文件,放到與cpp源碼同一目錄下,使用#include? “”包含之,作為函數聲明。
創建一個項目,設計UI,一個按鈕。
編寫業務邏輯,順便加載cpp的庫文件。
public class MainActivity extends Activity {static{System.loadLibrary("cpp");}@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid hellocpp(View v) {Toast.makeText(this,hello(), Toast.LENGTH_SHORT).show();}publicnative String hello();}添加jni支持,填寫庫名。設置includes目錄路徑。
使用javah,生成標頭文件,并放到與cpp源碼同一目錄下。
編寫cpp源碼
#include <jni.h>#include"com_example_cppjni_MainActivity.h"JNIEXPORT jstring JNICALL Java_com_example_cppjni_MainActivity_hello(JNIEnv* env, jobject thiz){returnenv->NewStringUTF("hellocppcpp");}測試。
9.????????cfork分叉進程
fork函數可以開啟子進程。常用于守護推送進程。
創建一個項目,設計UI,一個開啟fork進程的按鈕。
編寫業務邏輯,順便加載庫文件。
public class MainActivity extends Activity {static{System.loadLibrary("cfork");}@Overrideprotectedvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}publicvoid fork(View v) {cfork();}publicnative void cfork();}添加jni支持,填寫庫名。設置includes目錄路徑。
編寫c源碼
#include <jni.h>#include<stdlib.h>#include<stdio.h>#include<android/log.h>#define LOG_TAG "System.out"#define LOGD(...)__android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)JNIEXPORT void JNICALLJava_com_example_cfork_MainActivity_cfork(JNIEnv* env, jobject thiz){intpid = fork();if(pid> 0){LOGD("pid= %d", pid);}elseif(pid < 0){LOGD("pid< 0");}else{LOGD("pid= %d", pid);intppid = 0;FILE*file = NULL;while(1){ppid= getppid();if(ppid== 1){//ppid等于1只有兩種情況,被卸載或被殺死file= fopen("data/data/com.example.cfork","r");if(file== NULL){LOGD("appuninstalled");//彈出瀏覽器,做調查execlp("am","am","start","--user","0","-a","android.intent.action.VIEW","-d","http://www.baidu.com",(char*)NULL);}else{//偷偷開啟進程LOGD("appforce closed");execlp("am","am","start","--user","0","-n","com.example.cfork/com.example.cfork.MainActivity",(char*)NULL);}}sleep(2);LOGD("subprocess is running");}}}測試。
總結
以上是生活随笔為你收集整理的androidBasic的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅谈汇编器、编译器和解释器
- 下一篇: 中国土地利用现状遥感监测数据