日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

androidBasic

發布時間:2024/3/12 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

黄色a在线观看 | 国产精品毛片一区视频播不卡 | 久久色视频 | 亚洲91在线 | 99热这里精品 | 永久免费精品视频网站 | 999久久国产精品免费观看网站 | 99热这里只有精品国产首页 | 91九色视频网站 | 91福利免费 | 国产精品a久久久久 | 一级黄色大片在线观看 | 一区二区三区四区五区六区 | www日韩精品 | 精品一区二三区 | 最近中文字幕免费观看 | 日韩av电影中文字幕在线观看 | 久久艹艹 | 久久久久久久久久久久电影 | 国产.精品.日韩.另类.中文.在线.播放 | 久久国产精品视频免费看 | 久久人人97超碰com | 欧美日韩一级在线 | 亚洲精品字幕在线观看 | 亚洲精品乱码久久久久久久久久 | 午夜精品婷婷 | 国产黄网站在线观看 | 婷婷丁香六月天 | 少妇bbw搡bbbb搡bbbb | 日本 在线 视频 中文 有码 | 国产免码va在线观看免费 | 日韩久久久久久久久久久久 | 免费在线观看av电影 | 亚洲日韩欧美一区二区在线 | 九色91视频| 国产中文字幕久久 | 免费看一及片 | 国产精品女教师 | 国产精品久久99综合免费观看尤物 | 777视频在线观看 | 国产精品久久伊人 | 久久久久国产精品免费免费搜索 | 欧美日韩综合在线 | 亚洲另类视频在线观看 | 最新国产精品拍自在线播放 | 日本狠狠色 | 91免费观看视频在线 | 天天夜操 | 色av网站| 99精品乱码国产在线观看 | 国产护士在线 | 免费亚洲黄色 | 免费看片网页 | 国产精品一区二区精品视频免费看 | 久久99这里只有精品 | 91av视频播放 | 夜夜操天天干, | 美女啪啪图片 | 国产精品女视频 | 伊人影院得得 | 中文字幕资源站 | 超碰在线成人 | 黄色一级免费网站 | 亚洲黄色片在线 | 911国产精品 | 成人av免费网站 | 国产精品久久久久久久久久久久冷 | 亚洲精品在线免费观看视频 | 人人玩人人爽 | 国产精品久久久久永久免费看 | 欧美日韩在线视频一区二区 | 日韩精品五月天 | 97超碰总站 | 久久久精品 一区二区三区 国产99视频在线观看 | 日韩电影在线观看一区二区三区 | 日韩,精品电影 | 天天草综合 | 成人片在线播放 | 欧美福利网址 | 蜜臀久久99精品久久久无需会员 | 亚洲区另类春色综合小说校园片 | 黄色a一级片 | 中文字幕在线第一页 | 欧美日韩国产综合一区二区 | 久久精精品| 国产人成在线观看 | 久久99最新地址 | 久久五月天综合 | 亚a在线 | 天天操天天干天天爱 | 亚洲黄色免费电影 | 亚洲精品动漫在线 | 91桃色在线播放 | 国产精品视屏 | 91精品国产综合久久婷婷香蕉 | 欧美一区二区在线免费看 | 蜜臀av性久久久久蜜臀aⅴ流畅 | 国产资源在线视频 | www.午夜色.com| 国产精品美女 | 91激情视频在线观看 | av在线电影网站 | 欧美性生交大片免网 | 香蕉精品视频在线观看 | 午夜精品一区二区三区视频免费看 | 国产一级黄色av | 黄色国产在线观看 | 黄色www在线观看 | 高清美女视频 | 中文字幕av免费在线观看 | 最近字幕在线观看第一季 | 99精品热视频只有精品10 | 日韩大片在线观看 | 久久成视频 | 国产亚洲欧美一区 | 日韩免费一区二区 | 国产精品1区2区在线观看 | 日韩高清一二区 | 亚洲午夜精品在线观看 | 国产区高清在线 | 97在线影院| av在线播放一区二区三区 | 免费国产ww| 欧洲亚洲女同hd | 91精品视频免费 | 婷婷社区五月天 | 91 在线视频播放 | 美女视频黄免费网站 | 国产一区久久久 | 美女网站在线观看 | 久久av在线播放 | 久99久中文字幕在线 | 国产精品一区二区62 | 精品福利网| 91亚·色 | 一区二区三区四区五区六区 | 国产日韩欧美在线影视 | 五月天精品视频 | 夜夜爽88888免费视频4848 | 久99久中文字幕在线 | 国产亚洲va综合人人澡精品 | 国产一区二区不卡在线 | 国产91九色蝌蚪 | 欧美va在线观看 | 91九色国产在线 | 久久精品一区二区三区国产主播 | 日批在线看 | 中文在线8新资源库 | 中文不卡视频在线 | 97视频久久久 | 国产成人三级在线 | 狠狠色丁香久久婷婷综合_中 | 欧美视频在线二区 | 97日日碰人人模人人澡分享吧 | 色在线视频 | 国产精品免费久久久 | 国产一在线精品一区在线观看 | 免费日韩高清 | 国产蜜臀av | 91资源在线观看 | 国产无区一区二区三麻豆 | 99国产在线视频 | 激情视频免费观看 | 在线观看视频黄 | av在观看| 91福利视频免费 | 日日夜夜中文字幕 | avav片| 最近日本字幕mv免费观看在线 | 日韩久久影院 | 欧美99久久 | 国产欧美综合在线观看 | 国产成人性色生活片 | www.少妇| 国产一区视频在线播放 | 久久视频精品在线 | 在线观看日韩精品视频 | 91精品婷婷国产综合久久蝌蚪 | 日韩精品一区二区三区不卡 | 日本精品视频在线观看 | 成年人免费在线观看网站 | 国产视频2021| 日本精品一二区 | 91精品啪在线观看国产 | 在线看免费 | 国产视频精品免费 | 亚洲va在线va天堂 | 美女精品在线 | 日本久久中文 | 911精品视频 | 操操操日日 | 国内丰满少妇猛烈精品播 | 国产精品色 | 亚洲精品xxxx | 69久久久久久久 | 亚洲美女视频在线 | 国产精品24小时在线观看 | 日韩av不卡在线播放 | 亚洲综合狠狠干 | 久久综合色8888 | 中文字幕国产精品一区二区 | av888.com| 免费a级观看 | 久久综合久久综合久久综合 | 成人黄色在线播放 | 中文字幕在线中文 | 在线观看日本高清mv视频 | 欧美日韩视频免费 | 97精品一区| 天天干天天操av | 麻豆国产露脸在线观看 | 一区二区三区观看 | 黄色大片中国 | 欧美日韩亚洲国产一区 | 美女一级毛片视频 | 中文字幕精品一区二区精品 | 精品福利在线观看 | 国产精品免费在线视频 | 视频成人 | 日韩精品一区二区三区电影 | 免费精品国产va自在自线 | 国产高清一 | 欧美日韩一二三四区 | 五月婷av | 天天草天天 | 成 人 黄 色 片 在线播放 | 欧美成天堂网地址 | 日日久视频 | 99re8这里有精品热视频免费 | 中文在线字幕免 | 欧美日韩精品在线视频 | 国产成人久久精品 | 中文字幕一区二区三区四区视频 | 国产女人18毛片水真多18精品 | 日日添夜夜添 | 在线免费观看亚洲视频 | 免费视频久久久久久久 | 国产成人一区二区三区 | 欧美午夜一区二区福利视频 | 免费精品在线 | 天堂av网址 | 天天干天天摸 | 国产视频 亚洲视频 | 97在线免费视频 | 久久优| www五月| 9在线观看免费高清完整 | 免费观看性生交 | 亚洲成a人片在线观看中文 中文字幕在线视频第一页 狠狠色丁香婷婷综合 | a级国产乱理论片在线观看 伊人宗合网 | 中文字幕人成乱码在线观看 | 黄色tv视频 | 亚洲精品视频在线观看网站 | 国产中文视 | 一级黄色大片在线观看 | 久色网| 成人免费在线观看入口 | 三级免费黄色 | ww视频在线观看 | 欧美一区二区三区在线观看 | 91麻豆高清视频 | 亚洲精品免费在线播放 | 免费观看黄 | 色综合五月天 | 99久久婷婷国产一区二区三区 | 免费看黄色91 | 欧美另类重口 | 婷婷久久五月天 | 久久伊人精品一区二区三区 | 久久色网站 | 国产在线看一区 | 一级成人免费视频 | 看片黄网站 | 精品亚洲免a | 中文字幕一区二区三区四区 | 视频国产一区二区三区 | 中日韩在线 | 91天天操| 国产精品久久久久久久午夜 | 96av在线视频| 日韩激情小视频 | 91九色视频在线播放 | 久久国产香蕉视频 | 人人插人人做 | 欧美激情在线看 | 97色在线观看免费视频 | 麻豆91在线 | 操操操操网| 日本中文字幕在线视频 | 91麻豆免费视频 | 在线看日韩 | 亚洲一二三在线 | 亚洲美女精品区人人人人 | 中文字幕亚洲在线观看 | 青春草免费视频 | 久草爱| 午夜美女av | 精品一区二区精品 | 在线国产一区二区三区 | 中文av在线免费观看 | 国外调教视频网站 | 精品久久久久国产 | 国产精品一区免费在线观看 | 免费看国产a | 国产不卡视频在线播放 | 天天射天天舔天天干 | 久久久久久久久艹 | 亚洲成人av片在线观看 | 国产在线观看免 | 国产精品一区欧美 | 亚洲国产精品500在线观看 | 在线观看理论 | 国产精品剧情 | 亚洲精品久久久久久久不卡四虎 | 色噜噜日韩精品欧美一区二区 | 在线观看免费 | 日韩精品久久久 | 911av视频| 日韩精品一区二区免费视频 | 中文字幕在线观看第三页 | 午夜精品影院 | 超碰在线最新 | 9在线观看免费高清完整 | 日韩视频免费在线观看 | 欧美人人 | 日韩激情视频在线观看 | 日韩不卡高清 | 欧美日韩国产欧美 | 一区二区三区在线免费观看 | 亚洲成av人片在线观看www | 国产在线一区二区三区播放 | 在线免费观看羞羞视频 | 国产字幕在线看 | 国产精品99久久久久久武松影视 | 国产精品一区二区麻豆 | 国产91精品看黄网站在线观看动漫 | 涩涩资源网 | 日韩视频中文字幕在线观看 | 国产自偷自拍 | 日韩三级免费 | 亚洲 欧洲 国产 日本 综合 | 超碰日韩 | 丁香婷五月 | 久久色网站 | 人人干干人人 | 亚洲视频免费在线 | 黄色免费电影网站 | 国产免费又粗又猛又爽 | 欧美a级片网站 | 亚洲妇女av| 三级黄色理论片 | 国产黄色一级大片 | 久久精彩 | 久久人人精品 | 亚洲综合成人婷婷小说 | 日韩午夜小视频 | 韩日色视频 | 久草在线视频中文 | 狠狠躁18三区二区一区ai明星 | 天天艹天天操 | 在线导航av | 99热这里只有精品国产首页 | 天天天干天天射天天天操 | 国产精久久久久久妇女av | 99草在线视频 | 成人av在线影视 | 激情大尺度视频 | 欧美做受xxx | 在线韩国电影免费观影完整版 | 国产在线污 | 免费十分钟 | 国产精品久久久久影视 | 99性视频| 日日草视频 | 五月婷亚洲| 在线播放亚洲激情 | av免费在线网站 | 在线视频日韩 | 日韩久久精品一区二区 | 国产一区二区在线免费播放 | 国产精品免费麻豆入口 | 国产色在线 | 又黄又爽的视频在线观看网站 | 69视频在线 | 日韩黄色在线观看 | 日韩黄色免费在线观看 | 深夜国产在线 | 国产成人专区 | 日本狠狠色 | 久久久久亚洲国产 | 亚洲午夜久久久影院 | 久久久久久黄色 | 欧美精品乱码久久久久 | 国产精品久久久久久久电影 | 国产精品视频最多的网站 | 亚洲影视九九影院在线观看 | 99 国产精品| 深爱五月激情五月 | 99久久婷婷国产 | 国产高清久久久久 | 九草在线视频 | 久久超 | 欧美一区二区在线看 | 成人aaa毛片 | 2024国产精品视频 | av高清一区二区三区 | www.久久婷婷 | 亚洲第二色 | 国产免费又爽又刺激在线观看 | 成人av直播 | 国产亚洲精品久久久久秋 | 久久成人精品视频 | 日日夜夜免费精品 | 免费又黄又爽的视频 | 久久伦理 | 国产乱视频| 国产精品免费久久久久久久久久中文 | 五月宗合网 | 精品日本视频 | 久久人91精品久久久久久不卡 | 天天干,夜夜爽 | 九九精品无码 | 天天操天天色综合 | 国产91精品看黄网站 | 中文字幕乱码日本亚洲一区二区 | 国产精品原创 | 午夜色大片在线观看 | 亚洲乱码国产乱码精品天美传媒 | 91成人黄色| 97超碰人| 国产专区在线视频 | 婷婷免费在线视频 | 一级免费黄色 | 91在线观看欧美日韩 | 五月亚洲综合 | 欧美成人性战久久 | 日韩视频专区 | 亚洲激情综合 | 日韩av一区二区三区 | 天天超碰 | 国产精品12 | 精品国产乱码一区二 | 国产91影视 | 国产精品丝袜 | 欧美一级电影片 | 国产又粗又猛又爽 | www.久久婷婷| 992tv在线成人免费观看 | 岛国精品一区二区 | 欧美天天干 | 97人人人 | 成人av在线资源 | 99免费精品 | 久草视频视频在线播放 | 久久精品999| 久草精品国产 | 久草久草在线 | 丰满少妇在线观看资源站 | 一区二区三区日韩在线观看 | 蜜臀av一区二区 | 视频在线在亚洲 | 亚洲欧美视频在线播放 | 蜜臀久久99精品久久久无需会员 | 午夜久久福利视频 | 国产成人精品综合久久久 | 亚洲精品一区二区在线观看 | 久久久久久美女 | 婷婷丁香狠狠爱 | 二区三区在线视频 | 日躁夜躁狠狠躁2001 | 久久综合影音 | 999久久久免费精品国产 | 蜜臀av夜夜澡人人爽人人桃色 | 久久av中文字幕片 | 99久久99热这里只有精品 | 91福利小视频 | 91社区国产高清 | 国产精品国产三级在线专区 | 特级西西人体444是什么意思 | 成人va在线观看 | 色插综合 | 9色在线视频 | 午夜精品电影一区二区在线 | 久久字幕网 | 久久伊99综合婷婷久久伊 | 日韩欧美一区二区三区黑寡妇 | 五月综合婷 | 亚洲精品视频在线观看免费视频 | 一二三久久久 | 欧美日韩亚洲在线 | 在线你懂的视频 | 日韩高清一区在线 | 国产91精品在线观看 | 在线观看mv的中文字幕网站 | 日韩高清免费无专码区 | 91c网站色版视频 | 成人午夜剧场在线观看 | 三级黄色片子 | 国产xvideos免费视频播放 | 久久精品一区二区三区中文字幕 | av网站在线观看播放 | 久久久五月天 | 99免费在线视频观看 | 西西4444www大胆无视频 | 久香蕉 | 一区二区三区四区五区在线视频 | 久久女同性恋中文字幕 | 欧美综合色 | 成人午夜电影在线播放 | 在线观看国产成人av片 | 久久中文字幕在线视频 | 免费在线观看日韩 | 91av网址 | 999男人的天堂 | 一级理论片在线观看 | 日日夜夜狠狠操 | 蜜臀精品久久久久久蜜臀 | 成人动漫精品一区二区 | 亚洲国产欧美在线人成大黄瓜 | 日韩欧美极品 | 久久99国产精品久久99 | 99色视频| 97在线精品| 91中文字幕视频 | 69性欧美 | 中文字幕在线看视频国产 | 欧美国产日韩一区二区 | 激情丁香综合 | 国产精品久久久久久久久久直播 | 99久久精品免费看国产免费软件 | 免费日韩三级 | 国产中文在线播放 | av在线一| www.99在线观看| av黄色大片 | 久久精品网站视频 | 麻豆视频www | 国产成人精品免费在线观看 | 97精品超碰一区二区三区 | 五月天婷婷在线播放 | 黄色成人在线网站 | aⅴ视频在线 | 国产一级片视频 | 日韩视频1 | 高清av免费看 | 免费看高清毛片 | 五月天激情视频在线观看 | 国产一级免费在线 | 97看片网| 在线看中文字幕 | 婷婷在线色| 五月天久久综合 | 国产成人一区二区三区影院在线 | 激情五月综合 | 精品91视频 | 亚洲黄色在线观看 | 欧美一区视频 | 亚洲天堂社区 | 亚洲天堂va| 国产99中文字幕 | 在线免费看黄色 | 国产亚洲精品久久久久久电影 | 青青草国产精品视频 | 深夜免费福利 | 国产91学生粉嫩喷水 | 中文字幕亚洲在线观看 | 亚洲日韩中文字幕在线播放 | 天天综合亚洲 | 日本中文字幕在线观看 | 97香蕉久久国产在线观看 | 日韩理论在线观看 | 成人少妇影院yyyy | 精品免费视频123区 午夜久久成人 | 中文在线8资源库 | 久草在线免费资源 | 久久久久久国产精品999 | 一本一本久久aa综合精品 | 精品av网站 | 日日夜夜av | 国产在线一区二区 | 丁香婷婷激情啪啪 | 成片免费观看视频 | 久久高清国产 | 日本系列中文字幕 | 色综合久久久久久久久五月 | 精品国产一区二区三区不卡 | 久久中文字幕视频 | 国产三级精品三级在线观看 | 国产免费观看久久 | 韩国视频一区二区三区 | 国产视频九色蝌蚪 | 伊人黄色网 | 亚洲日日夜夜 | 日本高清免费中文字幕 | 一区二区精品在线视频 | 91热| 亚洲高清国产视频 | 韩日精品在线 | 天天操天天射天天舔 | 国产第一福利 | 中文在线字幕观看电影 | 久草久| 国内精品在线观看视频 | 国产免费片 | 国产网站色 | 欧美一区二区精品在线 | 亚洲国产精彩中文乱码av | 欧美日韩在线观看一区二区 | 国产精品三级视频 | 中文字幕av在线免费 | 欧美日韩免费一区 | 在线观看网站黄 | 一区二区中文字幕在线播放 | 亚洲精品自在在线观看 | 久久一区精品 | 五月婷婷在线观看视频 | 91亚·色| 日韩69av | 国产精品久久久久婷婷 | 久久99热精品这里久久精品 | 国产在线黄色 | 国产成人av | 成年人免费电影在线观看 | 日本久久久久久久久久久 | 伊人狠狠干 | www.久久久| av丝袜天堂| 日韩激情一二三区 | 香蕉视频在线观看免费 | 欧美精品久久久久a | 91免费看黄色 | 亚洲综合视频网 | 久久免费视频6 | 免费观看国产成人 | 日韩免费三区 | 亚洲午夜精品福利 | 黄色小说在线免费观看 | 国内成人精品视频 | 国产在线观看免费观看 | 国产99一区二区 | 精品久久网| 国产一区二区三区免费在线观看 | 欧美福利视频一区 | 涩涩爱夜夜爱 | 日韩中文幕 | 亚洲天天综合 | 在线观看国产日韩欧美 | 午夜美女福利直播 | 91精品啪在线观看国产81旧版 | 天天操网站 | 国产三级在线播放 | 美女精品在线观看 | 欧美一区二区三区特黄 | 天天综合网久久综合网 | 久久y | 一级黄视频| 黄色精品免费 | h视频日本 | 男女拍拍免费视频 | 国产精品美女www爽爽爽视频 | 国产 亚洲 欧美 在线 | 亚洲毛片久久 | 国产女v资源在线观看 | 亚洲精品乱码久久久久久按摩 | 欧美中文字幕久久 | 九九色视频 | 亚洲综合国产精品 | 久久中文字幕视频 | japanesexxx乱女另类 | 亚洲精品国产精品国自 | 91亚色在线观看 | 国产在线观看二区 | 亚洲黄色一级电影 | 欧美日韩69 | 日韩色综合 | 午夜视频免费 | 亚洲免费av在线播放 | 亚洲在线视频网站 | 久久人91精品久久久久久不卡 | 91视频免费看片 | 欧美另类网站 | 在线观看黄色大片 | 97超碰人人澡人人 | 国产精品毛片久久 | 久久久91精品国产一区二区精品 | 久久综合色天天久久综合图片 | 免费视频久久久久久久 | 亚洲永久字幕 | 国内精品久久久久久久97牛牛 | 激情丁香 | 在线观看中文字幕一区 | 精品美女久久久久久免费 | 最新日韩视频 | 91漂亮少妇露脸在线播放 | 一区二区三区在线观看免费视频 | 日韩中文字幕免费看 | 亚洲午夜精品久久久久久久久 | 亚洲精品视频在线免费播放 | 国产精品久久久久一区二区 | 2018亚洲男人天堂 | 99热高清| 天天操网址 | 精品伊人久久久 | 九色91在线 | 婷婷综合成人 | 麻豆传媒视频在线播放 | 久在线观看视频 | 精品在线观 | 国产精品毛片一区二区在线看 | 狠狠精品 | 国产精久久 | 中文字幕中文字幕在线中文字幕三区 | 2022国产精品视频 | 国产福利在线免费观看 | 在线观看国产v片 | 在线 日韩 av| 狠狠色丁香 | 久久久久www | 免费能看的av | 成人三级网站在线观看 | 亚洲理论在线观看 | a'aaa级片在线观看 | 国内精品美女在线观看 | 免费在线观看午夜视频 | 久久精品直播 | 成人国产综合 | 9999在线视频| 337p日本大胆噜噜噜噜 | 亚洲a在线观看 | 亚洲一区 影院 | 伊色综合久久之综合久久 | 亚一亚二国产专区 | 亚洲天天干 | 日日躁天天躁 | 亚洲女欲精品久久久久久久18 | 99久久婷婷国产精品综合 | 91成年人网站 | 91丨九色丨高潮丰满 | 久久久国产一区二区三区四区小说 | 色插综合 | 香蕉视频在线网站 | 亚洲三级国产 | 国产日韩欧美在线播放 | 久草免费福利在线观看 | 精品在线一区二区 | 中文字幕一区二区三区四区 | 最新久久免费视频 | 久久久久久久久久久免费av | 久久久久国产精品一区二区 | 国产美女精品久久久 | 久久精品国产99国产 | 久久这里只有精品1 | 亚洲人成精品久久久久 | 亚洲精品乱码久久久久久 | 中文一区二区三区在线观看 | 婷婷四房综合激情五月 | 激情久久伊人 | 久久精品专区 | 亚洲国产电影在线观看 | 在线观看一区二区精品 | 国产无限资源在线观看 | 国产亚洲午夜高清国产拍精品 | 亚洲精品久久激情国产片 | 天天综合网 天天 | 亚洲精品国产视频 | 国产又粗又猛又黄又爽 | 欧美在线视频免费 | 一区二区三区精品在线视频 | 国产黄色大片 | 免费三级黄 | 一本一本久久a久久精品综合小说 | 色多多在线观看 | 在线观看免费观看在线91 | 亚洲精品9 | 国产97免费 | 日本精品一区二区三区在线观看 | 涩涩资源网 | 999电影免费在线观看2020 | 日本中文字幕免费观看 | 日韩午夜视频在线观看 | 国产精品成人a免费观看 | 色五月激情五月 | 婷婷色五| 69视频国产 | 亚洲国产精品成人综合 | 久久国产精品久久w女人spa | av成人免费在线观看 | 狠狠伊人 | 亚洲黄色免费 | 色婷婷欧美 | 婷婷综合网| 中文字幕乱在线伦视频中文字幕乱码在线 | 欧美日韩一区二区三区不卡 | 亚洲视频中文 | 国产成人一区二 | 97色国产| 国产精品久久久久久久久久白浆 | av一级片网站 | 国产精品九九九 | 国产成人精品久久久 | 久久社区视频 | 99热99热| 国产91av视频在线观看 | 日韩r级电影在线观看 | 91九色蝌蚪国产 | 精品国产一区二区三区蜜臀 | 最近中文字幕在线中文高清版 | 久久久国产精品一区二区中文 | 欧美最爽乱淫视频播放 | 国产一区高清在线观看 | 狠狠干成人综合网 | 色先锋资源网 | 欧美国产日韩中文 | 成人激情开心网 | 黄色亚洲免费 | 国产亚洲免费的视频看 | 色综合人人 | 日本黄色免费播放 | 国产欧美在线一区二区三区 | 久久精品在线免费观看 | 日韩欧美高清在线 | 99热九九这里只有精品10 | 中文字幕影片免费在线观看 | 欧美成年黄网站色视频 | 中文字幕观看在线 | 精品国自产在线观看 | 欧美成年人在线视频 | 久久网页 | 亚洲一级片在线看 | 精品国偷自产国产一区 | 国产精品欧美久久 | 久久国产精品网站 | 丁香婷婷自拍 | 91av小视频 | 久久婷婷色综合 | 麻豆 free xxxx movies hd| 欧美一二三区在线观看 | 这里有精品在线视频 | 国产精品高潮呻吟久久久久 | 97理论片| 亚洲久草在线视频 | 中文亚洲欧美日韩 | 亚洲天堂免费视频 | 欧美黑人性爽 | 成人在线视频免费 | 国产精品久久伊人 | 久久久久99精品国产片 | 97网在线观看 | 国产日产精品久久久久快鸭 | 欧美老少交 | 色中色综合 | 久草在线视频在线 | 天天射天| 91精品啪在线观看国产 | 激情网五月天 | 丁香花在线观看免费完整版视频 | 国产亚洲在线视频 | 国产黄色大片 | 四虎成人精品永久免费av九九 | 99精品系列 | 9色在线视频 | 国产裸体视频网站 | 亚洲高清av在线 | 久久av免费| 免费日韩 精品中文字幕视频在线 | 国产97视频 | 国产香蕉97碰碰碰视频在线观看 | 欧美一级黄色视屏 | 欧美 日韩精品 | a级国产乱理伦片在线播放 久久久久国产精品一区 | 国产手机av | 欧美激情综合五月色丁香 | av超碰在线 | 超碰国产在线播放 | 99久久国产免费,99久久国产免费大片 | 国产女v资源在线观看 | 91精品在线免费视频 | 91香蕉国产 | 亚洲国产大片 | 狠狠狠狠狠狠狠 | 97精品超碰一区二区三区 | 国产成人综合图片 | 中文字幕在线观看资源 | 人人dvd | 久久免费精品视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 狠狠色丁香婷婷综合久小说久 | 成人免费视频播放 | av成人免费在线观看 | 成人av资源在线 | 波多野结衣精品 | 亚洲精品久久久久久久不卡四虎 | 国产精品美女免费视频 | 国产美女免费 | 激情五月伊人 | 欧美日韩在线观看一区二区三区 | 欧美a级免费视频 | 亚洲精品在线电影 | 丁香六月中文字幕 | www91在线 | 久久99久国产精品黄毛片入口 | 激情网第四色 | 久草在线视频网 | 国产久草在线观看 | 91精品国产91 | 久久线视频 | 亚洲婷婷在线视频 | 国产精品观看视频 | 久草男人天堂 | 黄色毛片在线观看 | 久久一区二区三区超碰国产精品 | 国产高清免费视频 | 蜜臀av性久久久久av蜜臀妖精 | 永久免费毛片 | 国产亚洲婷婷免费 | 精品专区一区二区 | 四季av综合网站 | 成人久久久精品国产乱码一区二区 | 天天天色综合 | www.91av在线 | 久久久影院一区二区三区 | 国产精品四虎 | 成人精品视频久久久久 | 蜜臀aⅴ国产精品久久久国产 | 99精品视频免费在线观看 | 青青啪 | 亚洲a成人v | 日日草视频 | 国产精品午夜在线 | 久久精品五月 | 精品在线播放视频 | 国产不卡免费 | 超碰国产在线 | 久久不射影院 | av在线看片 | 四虎在线免费观看视频 | 精品国产乱码久久久久久三级人 | 精品视频免费 | 免费a现在观看 | 在线观看资源 | 国产一级做a | 国产免费观看久久黄 | 日批在线观看 | 69国产成人综合久久精品欧美 | 国产精品嫩草影视久久久 | 中文字幕精品一区二区精品 | 激情黄色av| 日韩精品久久久 | 国产一级不卡毛片 | 久久午夜影院 | 日本久久91 | 色综合a| 国产专区一| 婷婷激情综合网 | 奇米影视8888在线观看大全免费 | 国产伦理精品一区二区 | 中国一级特黄毛片大片久久 | 久久久久久久亚洲精品 | avlulu久久精品| 亚洲免费在线看 | 三级av免费观看 | 国产黄色看片 | 精品美女在线观看 | 国产精品视频永久免费播放 | 在线看国产一区 | 五月婷婷在线观看 | 精品国产色 | 欧美日韩在线观看一区二区 | 黄色软件大全网站 | 久久这里只有精品23 | 又污又黄的网站 | 久久99精品国产一区二区三区 | 久久免费成人网 | 日韩在线视频免费观看 | 天天爱天天射天天干天天 | 日韩午夜一级片 | 最新免费av在线 | www.com黄色| 一区二区三区av在线 | 97超级碰碰碰视频在线观看 | 肉色欧美久久久久久久免费看 | 97色在线观看免费视频 | 草 免费视频 | 日韩有码中文字幕在线 | 91桃色在线播放 | 激情综合五月网 | 99人成在线观看视频 | 超碰人人做 | 午夜骚影 | 在线观看视频一区二区三区 | 五月天婷婷狠狠 | 免费看片成人 | www亚洲精品| 国产精品久久久久久吹潮天美传媒 | 亚洲视频,欧洲视频 | av在线免费在线观看 | 精品一区二区久久久久久久网站 | 亚洲综合色丁香婷婷六月图片 |