1,本章是android入門最後一篇,從後面開始將進入進階階段。我也會加快更新速度。但願能保持每天三篇博文的數量。但是是在保證質量的前提下。後面我還會發布一些實際開發中用到的應用案例。敬請關注!
應用組件是一個android應用程序的重要基石。每個組件的應用角度不同,各自負責所特有的功能。並非所有的組件都有實際的切入點,或許與別的組件相互依賴。但都作爲一個獨立的實體存在,起着特定的作用。有四種不同類型的應用組件。每種類型提供不同的用途,並各自擁有不同的生命週期。
所謂組件你可以這麼理解。一個汽車的構成一般有發動機,變速箱,底盤,車身,懸掛這幾部門組成。每一部分又都有獨立的作用。這和android中得組件類似。
下面是四種類型的應用程序組件:
Activity
字面意思活動,其實就表示與用戶交互的一塊單屏幕。比如說短信應用程序可能有一個活動,顯
示收發短信的列表,另一項活動,可以編寫短信。他們是不同的兩塊屏幕。一個Activity是單獨
的,它的關注點在於用戶能做什麼。幾乎所有的Activity都與用戶交互。在Android中一個程序 可
以訪問另一個程序中得某個Activity,這在其他語言程序中是不可想象的。極大的節省了系統資源。
所有的Activity必須在 AndroidManifest.xml.清單文件中註冊方可使用。
Service
服務是運行在後臺的一個組件,提到服務你可能首先想到的是windows中的服務。它在後臺默默
的爲你提供着你需要的功能。Android中得服務其實與windows中得服務類似,它執行長時間運
行的操作,或運程進程執行工作。服務不提供用戶界面,例如在後臺下載東西,播放音樂,在你
播放音樂的同時還可以幹其他事情,而不會阻塞用於與其他活動的交互。另一個組件,比如Activity
可以啓動一個服務,並運行或者綁定到它。
ContentProvider
內容提供者主要用於應用程序的數據共享設置,你可以把數據存儲在文件系統中,或者SQLite數
據庫上,網絡,或者其他的持久性存儲位置。你可以訪問這些數據或者修改,其他應用程序也可
以訪問或者修改。(當然這需要內容提供商的允許)。最典型的例子就是android程序中得通訊錄
它就是通過內容提供者對外共享數據的。
BroadcastReceiver
廣播接收者,其實和我們生活中得廣播意思相近,在發生什麼事情的時候,會以廣播的形式告知
我們。廣播又分爲普通廣播和有序廣播。普通廣播是異步的,理論上是同時收到的。你不能對他
做任何操作,不能終止。有序廣播,在接收到廣播時可以加入自己的操作,傳遞給下一個接收者,
也可以終止廣播。 舉個例子 溫州動車追尾了,國家通過電視廣播的方式同時告知了我們。你沒
辦法終止它,或者改變它。這屬於普通廣播。有序廣播就是,比如張三的老婆郭美美在動車上,
國家通過電話通知張三:“你老婆很不幸在這次事故中喪生了”。張三可以在接到通知時終止它,
不告訴他丈母孃,也可以加入自己的操作,然後再告知丈母孃:“媽呀,美美在火車上出了點事,
在醫院呢。”當然有序廣播是有優先級的。國家打電話優先通知她老公。而不是她老母。這在後面
會詳細講解!Android系統中最常見的廣播電池電量低得時候,收到短信的時候,USB連接的時
候等等。
先暫時介紹一下四大組件,進階部分會有詳盡講解。多謝關注!下面來個簡單的例子作爲入門的結束!
先上圖:
<!--EndFragment-->
打電話的主要代碼:
- mCall.setOnClickListener(new Button.OnClickListener(){
- @Override
- public void onClick(View v) {
- String phoneNumber=mPhoneNumber.getText().toString();
- //意圖 用於激活組件,綁定數據。充 當信使的作用
- Intent intent=new Intent();
- /*要執行的動作。執行不同的動作的Action去這找
- http://developer.android.com/reference/android/content/Intent.html */
- intent.setAction("android.intent.action.CALL");
- //綁定數據
- intent.setData(Uri.parse("tel:"+phoneNumber));
- //激活打電話組件 通過隱式意圖 另外不要忘記在清單文件中註冊一下打電話的權限
- startActivity(intent);
- }
- });
- mCall.setOnClickListener(new Button.OnClickListener(){
- @Override
- public void onClick(View v) {
- String phoneNumber=mPhoneNumber.getText().toString();
- //意圖 用於激活組件,綁定數據。充 當信使的作用
- Intent intent=new Intent();
- /*要執行的動作。執行不同的動作的Action去這找
- http://developer.android.com/reference/android/content/Intent.html */
- intent.setAction("android.intent.action.CALL");
- //綁定數據
- intent.setData(Uri.parse("tel:"+phoneNumber));
- //激活打電話組件 通過隱式意圖 另外不要忘記在清單文件中註冊一下打電話的權限
- startActivity(intent);
- }
- });
發送短信的主要代碼:
- mSendButton.setOnClickListener(new Button.OnClickListener(){
- @Override
- public void onClick(View v) {
- String phoneNumber=mPhoneNumber.getText().toString();
- String content=mMessage.getText().toString();
- //得到短信管理器
- SmsManager manager=SmsManager.getDefault();
- //如果短信內容超過70個字將被分割成多條
- ArrayList<String> messages=manager.divideMessage(content);
- //循環發送
- for(String ms:messages){
- //注:在模擬器中發送中文短信會亂碼 這跟底層的網絡有關。不過到真機上就沒事了。
- manager.sendTextMessage(phoneNumber, null, ms, null, null);
- Toast.makeText(getApplicationContext(), "發送成功!", 0).show();
- }
- }
- });
- mSendButton.setOnClickListener(new Button.OnClickListener(){
- @Override
- public void onClick(View v) {
- String phoneNumber=mPhoneNumber.getText().toString();
- String content=mMessage.getText().toString();
- //得到短信管理器
- SmsManager manager=SmsManager.getDefault();
- //如果短信內容超過70個字將被分割成多條
- ArrayList<String> messages=manager.divideMessage(content);
- //循環發送
- for(String ms:messages){
- //注:在模擬器中發送中文短信會亂碼 這跟底層的網絡有關。不過到真機上就沒事了。
- manager.sendTextMessage(phoneNumber, null, ms, null, null);
- Toast.makeText(getApplicationContext(), "發送成功!", 0).show();
- }
- }
- });
之所以還會在講這一點主要是 這是電話的最基本的兩個功能,還有一點在很多應用中還是會用到這些的,比如在CRM,OA,SNS應用上都有可能用上這個功能。最典型的在CRM上,在客戶資料上有電話號碼這一項,你可以直接加一按鈕就能撥打,總比再把號碼記下來用內置的撥打吧。
2,在實際開發中,開發android應用程序的過程中是需要不斷的進行單元測試的,使用JUnit測試框架,是正規android開發比用技術,良好的測試習慣,一是能減少後期維護 和增強軟件的健壯性。在JUnit中可以得到組件,可以模擬發送事件和檢測程序處理的正確性。
其實android中也是擴展了JUnit,派生出好幾個類傾向於不同情況下的測試。這一點與Spring中初始化容器相似,你可以通過BeanFactory 也可以通過ApplicationContext 來完成。只不過他們的傾向點不同。在android中你可以使用這些類來完成單元測試:
Test—TestCase—AndroidTestCase :多用於對業務邏輯的單元測試
Test—TestCase—InstrumentationTestCase :用於測試與組件交互的功能
Test—TestSuite—InstrumentationTestSuite :一組測試用例
TestListener——BaseTestRunner—AndroidTestRunner
Instrumentation—InstrumentationTestRunner
我們常用到的一般是前前兩個,你會發現他們的基類都是Test。只不過各自的應用場景不同。
第一步:在AndroidManifest.xml中加入下面藍色代碼:
<!--EndFragment-->
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <!-- 使用的類庫 -->
- <SPAN style="COLOR: #0000ff"><uses-library android:name="android.test.runner"/></SPAN>
- <activity android:name="com.iteye.androidtoast.JUnitActivity"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- <!-- 這裏的 targetPackage的內容與上面package內容需相同。表示該測試運行在此包下,說白了就是在同一個進程 -->
- <SPAN style="COLOR: #0000ff"><instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.iteye.androidtoast" android:label="Tests for My App" /></SPAN>
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <!-- 使用的類庫 -->
- <span style="color:#0000ff;"><uses-library android:name="android.test.runner"/></span>
- <activity android:name="com.iteye.androidtoast.JUnitActivity"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
- <!-- 這裏的 targetPackage的內容與上面package內容需相同。表示該測試運行在此包下,說白了就是在同一個進程 -->
- <span style="color:#0000ff;"><instrumentation android:name="android.test.InstrumentationTestRunner"
- android:targetPackage="com.iteye.androidtoast" android:label="Tests for My App" /></span>
第二步,看代碼
首先是AndroidTestCase的簡單應用
- package com.iteye.service.tests;
- import junit.framework.Assert;
- import android.test.AndroidTestCase;
- import android.util.Log;
- import com.iteye.service.SomeService;
- /**
- * 需要測試類要繼承AndroidTestCase
- * AndroidTestCase 多用於對系統中業務邏輯的測試
- * 需要與界面交互的測試一般採用InstrumentationTestCase
- * @author androidtoast
- *
- */
- public class SomeServiceTest extends AndroidTestCase {
- private static final String TAG="SomeServiceTest";
- SomeService some;
- protected int a;
- protected int b;
- //初始化測試環境 在實例化當前類的時候自動調用此方法
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- some=new SomeService();
- a=3;
- b=8;
- }
- //測試結束後調用此方法,用於清理測試環境中得變量
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- Log.i(TAG, "Test Over!");
- }
- //測試getAdd方法
- public void testAdd()throws Exception{
- Log.d(TAG, "testAdd");
- int result=some.getAdd(a, b);
- Assert.assertEquals(11, result);
- }
- }
- package com.iteye.service.tests;
- import junit.framework.Assert;
- import android.test.AndroidTestCase;
- import android.util.Log;
- import com.iteye.service.SomeService;
- /**
- * 需要測試類要繼承AndroidTestCase
- * AndroidTestCase 多用於對系統中業務邏輯的測試
- * 需要與界面交互的測試一般採用InstrumentationTestCase
- * @author androidtoast
- *
- */
- public class SomeServiceTest extends AndroidTestCase {
- private static final String TAG="SomeServiceTest";
- SomeService some;
- protected int a;
- protected int b;
- //初始化測試環境 在實例化當前類的時候自動調用此方法
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- some=new SomeService();
- a=3;
- b=8;
- }
- //測試結束後調用此方法,用於清理測試環境中得變量
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- Log.i(TAG, "Test Over!");
- }
- //測試getAdd方法
- public void testAdd()throws Exception{
- Log.d(TAG, "testAdd");
- int result=some.getAdd(a, b);
- Assert.assertEquals(11, result);
- }
- }
InstrumentationTestCase應用代碼:
- package com.iteye.androidtoast.tests;
- import com.iteye.androidtoast.JUnitActivity;
- import com.iteye.androidtoast.R;
- import android.content.Intent;
- import android.os.SystemClock;
- import android.test.InstrumentationTestCase;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- /**
- * InstrumentationTestCase多用於測試與組件相關的操作
- * @author androidtoast
- *
- */
- public class JUnitActivityTest extends InstrumentationTestCase {
- JUnitActivity mActivityTested;
- public JUnitActivityTest() {
- }
- /**
- * 初始化測試環境
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- //意圖用於激活Activity
- Intent intent = new Intent();
- //設置用於激活哪個Activity
- intent.setClassName("com.iteye.androidtoast", JUnitActivity.class.getName());
- //啓動一個新的任務 並在後臺運行
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- //獲得Instrumentation 啓動一個活動
- mActivityTested = (JUnitActivity) getInstrumentation().startActivitySync(intent);
- }
- //清理資源
- @Override
- protected void tearDown() throws Exception {
- mActivityTested.finish();//測試完成後關閉Activity
- super.tearDown();
- }
- //測試方法 (其實就是一個點擊按鈕 然後隱藏自身顯示文本這麼一簡單功能)
- public void testClickButtonToShowText() throws Exception {
- TextView tv = (TextView) mActivityTested.findViewById(R.id.text);
- SystemClock.sleep(2000);//等待兩秒
- //如果當前的TextView的狀態是隱藏的則正確通過
- assertEquals("TextView should be Gone before Button Clicking",
- View.GONE, tv.getVisibility());
- Button btn = (Button) mActivityTested.findViewById(R.id.button);
- //在主線程裏執行點擊按鈕這一動作
- getInstrumentation().runOnMainSync(new PerformClick(btn));
- SystemClock.sleep(2000);
- assertEquals("TextView should be Visible after Button Clicking",
- View.VISIBLE, tv.getVisibility());
- }
- private class PerformClick implements Runnable {
- Button mBtnClicked;
- public PerformClick(Button button) {
- mBtnClicked = button;
- }
- public void run() {
- mBtnClicked.performClick();
- }
- }
- }
- package com.iteye.androidtoast.tests;
- import com.iteye.androidtoast.JUnitActivity;
- import com.iteye.androidtoast.R;
- import android.content.Intent;
- import android.os.SystemClock;
- import android.test.InstrumentationTestCase;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- /**
- * InstrumentationTestCase多用於測試與組件相關的操作
- * @author androidtoast
- *
- */
- public class JUnitActivityTest extends InstrumentationTestCase {
- JUnitActivity mActivityTested;
- public JUnitActivityTest() {
- }
- /**
- * 初始化測試環境
- */
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- //意圖用於激活Activity
- Intent intent = new Intent();
- //設置用於激活哪個Activity
- intent.setClassName("com.iteye.androidtoast", JUnitActivity.class.getName());
- //啓動一個新的任務 並在後臺運行
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- //獲得Instrumentation 啓動一個活動
- mActivityTested = (JUnitActivity) getInstrumentation().startActivitySync(intent);
- }
- //清理資源
- @Override
- protected void tearDown() throws Exception {
- mActivityTested.finish();//測試完成後關閉Activity
- super.tearDown();
- }
- //測試方法 (其實就是一個點擊按鈕 然後隱藏自身顯示文本這麼一簡單功能)
- public void testClickButtonToShowText() throws Exception {
- TextView tv = (TextView) mActivityTested.findViewById(R.id.text);
- SystemClock.sleep(2000);//等待兩秒
- //如果當前的TextView的狀態是隱藏的則正確通過
- assertEquals("TextView should be Gone before Button Clicking",
- View.GONE, tv.getVisibility());
- Button btn = (Button) mActivityTested.findViewById(R.id.button);
- //在主線程裏執行點擊按鈕這一動作
- getInstrumentation().runOnMainSync(new PerformClick(btn));
- SystemClock.sleep(2000);
- assertEquals("TextView should be Visible after Button Clicking",
- View.VISIBLE, tv.getVisibility());
- }
- private class PerformClick implements Runnable {
- Button mBtnClicked;
- public PerformClick(Button button) {
- mBtnClicked = button;
- }
- public void run() {
- mBtnClicked.performClick();
- }
- }
- }
http://androidtoast.iteye.com/blog/1169635