Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android基礎第七篇

Android基礎第七篇

編輯:關於Android編程

1. 清單文件AndroidManifest.xml


1.1. 清單文件的作用
每個Android應用都需要一個名為AndroidManifest.xml的程序清單文件,這個清單文件名是固定的並且放在每個Android應用的根目錄下。它定義了該應用對於Android系統來說一些非常重要的信息,Android系統需要這些信息才能正常運行該應用。Android程序清單文件主要具有下面作用:
(a)它給應用程序Java包命名,這個包名作為應用程序唯一標識符。
(b)它描述了應用程序中的每個程序組件—Activity,Service,Broadcast Receivers和Content Provider。它描述了實現每個應用程序組件的類名稱和組件能力(比如組件能夠處理哪種類型的Intent消息)。這些描述幫助Andoid操作系統了解這些程序組件和在何種條件下可以啟動這些程序組件。
(c)它決定哪些進程用來運行應用程序組件。
(d)它描述了應用程序使用某些受保護的程序API或和其它應用程序交互所需的權限。
(e)它描述了其它應用程序和該應用交互時應擁有的權限。
(f)它列出了Instrumentation類用於提供應用程序運行時一些性能統計和其它信息。這些生命只在測試或開發應用時使用。在發布應用時應該刪除。
(g)它給出了應用運行所需AndroidAPI版本的最低要求。
(h)它列出了應用程序需要調用的開發庫定義。

1.2. 清單文件的一些細節

(a)一個應用程序可以創建多個桌面圖標;
(b)創建快捷圖標的方法(程序多個啟動入口):


    
        //應用程序的入口
        
        //啟動器
        
    

(c)activity的label標簽中的值是這個activity界面的標題名稱;
(d)activity的label標簽中的值也是它的桌面快捷圖標的名稱;
(e)application中的label標簽和activity中的label標簽不是一個概念,application中的label表示應用程序的名稱,activity中的label標簽表示的是它的界面的名稱;
(f)action:表示動作,可以自定義,也可以使用系統定義的action;
(g)category:表示類型

類型 含義 android.intent.category.LAUNCHER 啟動器 android.intent.category.DEFAULT 默認類型,一般使用這個默認類型 android.intent.category.CAR_DOCK 指定手機被插入汽車底座(硬件)時運行該Activity android.intent.category.CAR_MODE 設置該Activity可在車載環境下使用

2. 使用意圖開啟界面


Intent 意圖:做一件事情的想法,如:吃飯,打人,喝茶。
Intent包含動作:action,數據:data
Intent的作用:激活組件和攜帶參數。

2.1. 設計Intent 的目的

意圖設計的目的:解耦,實現應用程序的高內聚、低耦合。保證應用程序之間能夠相互獨立運行,又能彼此相互調用。

2.2. 顯式意圖

顯式意圖通過指定應用的包名和類名開啟界面。應用場景:開啟自己的應用界面。
首先我們編寫下面兩個界面,點擊按鈕計算跳轉到第二個頁面:
這裡寫圖片描述
這裡寫圖片描述
點擊按鈕跳轉到第二個界面:

public void click(View view){
    //創建意圖對象,參數1是上下文,參數2是需要跳轉的Activity
    Intent intent = new Intent(MainActivity.this,ResultActivity.class);
    //下面兩行注釋的代碼是另一種創建意圖對象的方法,首先創建意圖對象,然後給意圖對象設置類名,參數1代表包名,參數2代表需要開啟的Activity的全路徑名
    //Intent intent = new Intent();  
    //intent.setClassName("com.itheima.rpcalc","com.itheima.rpcalc.ResultActivity");
    //開啟意圖
    startActivity(intent);
}

2.3. 隱式意圖

通過指定一組動作或者數據開啟一個activity。應用場景:開啟別的應用的界面,不是自己應用的界面。
首先我們編寫下面兩個界面:
這裡寫圖片描述
這裡寫圖片描述
點擊計算,跳轉到第二個頁面:
我們需要給第二個頁面的Activity配置intent-filter:


    
        //配置Activity的action
        
        //配置Activity的類型,一般默認android.intent.category.DEFAULT
        
        //配置data,其中有mineType,scheme等
        
    

對於mineType類型,我們可以查看tomcat中的config目錄下的web.xml文件,其中extension標簽表示的是該類型的擴展名:
這裡寫圖片描述

點擊“計算”按鈕,跳轉到第二個頁面:

//創建意圖對象
Intent intent = new Intent(); 
//設置意圖的action
intent.setAction("com.itheima.result");
//設置意圖攜帶的數據
intent.setData(Uri.parse("itheima:"+"nihao"));
//設置意圖的category屬性
intent.addCategory("android.intent.category.DEFAULT");
//調用Context的startActivity()開啟意圖
startActivity(intent);

2.4. 打開浏覽器案例

本案例實現在EditText輸入網址路徑,點擊按鈕跳轉到浏覽器打開網頁。以下是布局頁面:
這裡寫圖片描述



    

點擊按跳轉到浏覽器:

public void click(View view){
   //獲取EditText中的數據
   String path = et_path.getText().toString().trim();
   Intent intent = new Intent();
   //設置Action為Intent.ACTION_VIEW
   intent.setAction(Intent.ACTION_VIEW);
   //設置Data,參數為一個URI類型的數據,利用Uri.parse()方法
   intent.setData(Uri.parse(path));
   //開啟Activity
   startActivity(intent);
}

測試結果:
這裡寫圖片描述
這裡寫圖片描述

當我們打開模擬器的浏覽器應用,查看日志輸出打開的activity:
這裡寫圖片描述

通過分析日志,可以看到浏覽器的Activity是BrowserActivity,除了使用隱式意圖打開浏覽器外還可以通過顯式意圖來打開浏覽器。但是如果使用顯式意圖打開浏覽器,就只能打開系統默認的浏覽器應用,這樣就限制了意圖打開應用的個數,所以使用顯式意圖就大大增加了應用程序的耦合。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMiBpZD0="25-uri和url介紹及區別">2.5. URI和URL介紹及區別

URI統一資源標識符(Uniform Resource Identifier),用來表示某一互聯網資源名稱的字符串。
URL統一資源定位符(Uniform Resource Locator),是可以從互聯網上得到資源的位置和訪問方法的一種簡潔的表示,是互聯網上標准資源的地址。

就Android平台而言,URI主要分三個部分:scheme,authority,path。其中authority又分為host和port。格式如下:
scheme://host:port/path

URL和URI的區別:URL是URI的子集。

2.6. 人品計算器案例

該案例實現在EditText中輸入姓名,選擇性別,點擊計算按鈕,跳轉到第二個頁面,並且第二個頁面根據輸入的名字和選擇的性別計算生成人品分值並且顯式在界面上。那麼如何將第一個界面的數據傳遞給第二個頁面呢?通過該案例可以掌握Intent傳遞數據。
這裡寫圖片描述
這裡寫圖片描述

第一個頁面布局:



    

    

    

        

    
    

第二個頁面布局:




    

    

    


點擊按鈕實現Intent傳遞數據,利用數據計算出人品分值:

public void click(View v) {
    String name = et_name.getText().toString().trim();
    if (TextUtils.isEmpty(name)) {
        Toast.makeText(getApplicationContext(), "請輸入姓名", 0).show();
        return;
    }
    int id = rg_group.getCheckedRadioButtonId();
    int sex = 0;
    switch (id) {
    case R.id.rb_male: // 選中的男
        sex = 1;
        break;
    case R.id.rb_female: // 選中的女
        sex = 2;
        break;
    case R.id.rb_other: // 選中的人妖
        sex = 3;
        break;
    default:
        break;
    }
    if (sex == 0) {
        //性別被選中 
        Toast.makeText(getApplicationContext(), "請選中性別", 0).show();
        return;
    }
    Intent intent = new Intent(MainActivity.this, ResultActivity.class);
    //通過intent的putExtra()方法,向intent中添加數據,將name和sex的值添加到intent中,參數1是數據的名稱,參數2是數據的值
    intent.putExtra("name", name);
    intent.putExtra("sex", sex);
    startActivity(intent);
}

結果頁面獲取第一個頁面的數據,生成人品值:

//通過上下文獲取到傳遞過來的意圖對象,getIntent()
Intent intent = getIntent();
//調用intent.getString()方法,獲取name的值,參數1表示數據的名稱,如果獲取不到,該方法返回null
String name = intent.getStringExtra("name");
//調用intent.getInt()方法,獲取sex的值,參數1表示數據的名稱,參數2表示如果獲取不到返回的默認值
int sex = intent.getIntExtra("sex", 0);
TextView tv_name = (TextView) findViewById(R.id.tv_name);
TextView tv_sex = (TextView) findViewById(R.id.tv_sex);
TextView tv_result = (TextView) findViewById(R.id.tv_result);
tv_name.setText(name);
byte[] bytes = null;
try {
    switch (sex) {
    case 1:     //男
        tv_sex.setText("男");
        bytes = name.getBytes("gbk");   
        break;
    case 2:     //女
        tv_sex.setText("女");
        bytes = name.getBytes("utf-8");
        break;          
    case 3:    //人妖
        tv_sex.setText("人妖");
        bytes = name.getBytes("iso-8859-1");
        break;
    default:
        break;
    }
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
int total = 0;
for (byte b : bytes) {                // 0001 1111
    int number = b&0xff;              // 1111 1111
    total += number;
}
score = Math.abs(total)%100;
if (score >90 ) {
    tv_result.setText("您的人品非常好 .您家的祖墳都冒青煙了.....");
}else if(score >=70){
    tv_result.setText("您的人品還可以 !!!");
}else if(score >=60){
    tv_result.setText("您的人品剛剛及格");
}else{
    tv_result.setText("您的人品太次了 趕快自己想想吧!!!");
}

2.7. 意圖傳遞數據的類型

意圖傳遞的數據類型:
1、8大基本數據類型、數組;
2、Bundle類似於map的數據結構;
3、Parcelable序列化到內存;
4、Serializable序列化到文件;

2.8. 短信大全案例

該案例實現功能有:ListView展示短信模板,通過點擊ListView子條目,跳轉到系統發送短信頁面,並且將模板中的短信顯式到系統短信發送頁面輸入框中。下圖是效果圖:
這裡寫圖片描述
這裡寫圖片描述

點擊模擬器中發送短信頁面,查看日志:

03-12 04:01:53.472: I/ActivityManager(861): Starting: Intent{dat=content://mms-sms/conversations/2cmp=com.android.mms/.ui.ComposeMessageActivity}from pid 1237

從日志中可以看到我們打開的activity是ComposeMessageActivity。我們到系統上層應用源碼中找到這個activity的清單文件,查看該Activity的意圖過濾器。如下圖:
這裡寫圖片描述

由於我們發送的短信是文本相關的,所以我們在intent-filter中找mimeType是文本的過濾器。這樣我們找到如下過濾器:


      
       
       

頁面布局:



    
   


Activity頁面邏輯代碼:

public class MainActivity extends Activity {
    //模擬創建出短信內容
    String objects[] = { "丫頭,生活是你自己的,你哭它就對你哭,你笑它就對你笑。轉眼,又是一年,你的生日即將來到。今年,還是少不了我對你的祝福,我忍不住...",
            "世界上最動聽的聲音,是媽媽聲聲的呼喚;世界上最溫暖的笑容,是媽媽溫暖的笑
臉。媽媽,原諒生日時我不能陪在您身邊,在這個日子裡,我...",
            "春天的鮮花,夏天的浪花,秋天的繁華,冬天的雪花,不論何時何地都希望你樂開
花,朋友,在這陽光明媚的日子,我為你放飛一群祝福,祝你...",
            "我把春風織成一塊溫暖的毯子送給你,將幸福包住。我把春雨編成一條夢幻的絲帶
送給你,把快樂纏住。我把春天掛滿祝福送給你,讓美好留住..." };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ListView lv = (ListView) findViewById(R.id.lv);
        lv.setAdapter(new ArrayAdapter(getApplicationContext(),R.layout.item, objects));
        // 給listview設置點擊事件
        lv.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view,int position, long id) {
                // 點擊item獲取我點擊條目的內容
                String data = objects[position];
                // 把data傳入到短信應用的發送界面 用隱式意圖
                Intent intent = new Intent();
                // 設置動作
                intent.setAction("android.intent.action.SEND");
                intent.setType("text/plain");
                intent.addCategory("android.intent.category.DEFAULT");
                intent.putExtra("sms_body", data);
                startActivity(intent);
            }
        });
    }
}

給intent添加數據。那麼這個key應該寫什麼呢?我們需要上層應用短信應用源碼中查找。由於短信頁面需要通過intent獲取到攜帶過來的短信數據,所以我們可以在源碼中搜索getStringExtra()搜索,最終我們搜索到了我們需要的代碼如下圖:
這裡寫圖片描述

2.9. 短信發送小案例

主頁面:
這裡寫圖片描述

點擊“+”按鈕跳轉到選擇聯系人界面:
這裡寫圖片描述

點擊插入短信模板跳轉到短信模板頁面:
這裡寫圖片描述

選擇短信模板返回到主頁面:
這裡寫圖片描述
點擊發送後,將短信發送出去。

本案例最主要需要掌握:
(a)開啟Activity,當關閉該Activity後獲取返回值;
(b)發送短信。

開啟Activity獲取返回值步驟:
1 在開啟activity時調用以下方法:

startActivityForResult(intent, 200);

2 在目標activity中設置關閉時返回的數據

Intent intent = new Intent();
intent.putExtra("username", username);
setResult(0, intent);

3 關閉目標Activity

finish();

4 重寫onActivityResult()方法接收返回的數據。

在MainActivity中點擊“+”號跳轉到聯系人界面:

public void click(View v){
    Intent intent = new Intent(MainActivity.this,ContactActivity.class);
    //調用startActivityForResult()跳轉到聯系人界面,並且等待返回數據。參數1是意圖對象,參數2是請求碼
    startActivityForResult(intent, 10);
}

在聯系人界面點擊聯系人條目將數據返回給MainActivity:

lv_contact.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView parent, View view,
    int position, long id) {
        Person person = contactLists.get(position);
        String phone = person.getPhone();
        Intent intent = new Intent();
        intent.putExtra("phone", phone);
        //通過調用setResult()方法將數據返回給MainActivity。參數1是結果碼,參數2是攜帶數據的意圖對象
        setResult(10, intent);
        //調用finish()方法用來關閉聯系人Activity
        finish();
    }
});

MainActivity中重寫onActivityResult()方法用來接收聯系人界面返回的聯系人號碼:

//requestCode參數是請求碼,resultCode參數是結果碼。使用requestCode,resultCode來判斷是哪個業務邏輯界面返回的數據
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    //requestCode請求碼。由於Activity可能會打開多個其他的Activity並且獲得返回數據,所以用requestCode請求碼來區分獲取的是哪個Activity的返回值
    if (requestCode == 10) {
        //獲取Intent中的phone數據
        String phone = data.getStringExtra("phone");
        et_phone.setText(phone);
    }else if(requestCode == 20){
        String smsContent = data.getStringExtra("smscontent");
        et_sms_body.setText(smsContent);
    }
    super.onActivityResult(requestCode, resultCode, data);
}

由於插入短信模板功能和選擇聯系人功能類似,所以這邊不再闡述。
點擊發送發送短信:

public void send(View v){
    String phone = et_phone.getText().toString().trim();
    String smsBody = et_sms_body.getText().toString().trim();
    //通過SmsManager.getDefault()方法創建SmsManager管理類
    SmsManager smsManager = SmsManager.getDefault();
    //調用smsManager.divideMessage()方法將短信分割
    ArrayList divideMessages = smsManager.divideMessage(smsBody);
    //遍歷分割的短信集合,通過smsManager的sendTextMessage()方法發送短信。參數1是電話號碼,參數2是服務中心地址,參數3是發送的內容,參數4是發送成功的廣播,參數5是消息發送給接受者的廣播
    for (String smsContent : divideMessages) {
        smsManager.sendTextMessage(phone, null, smsContent, null, null);
    }
}

3. Activity生命周期


3.1. 生命周期的概念

舉例:人被生下來,經歷幼年、童年、青年、中年、老年。
從被創建到銷毀經歷幾個階段,每個階段就表示一個方法,這些方法就是生命周期的回調。

3.2. Activity的生命周期

生命周期方法 調用時間 onCreate() 當Activity第一次創建的時候調用 onDestory() 當Activity銷毀的時候調用 onStart() 當Activity變成可見的時候調用 onStop() 當Activity不可見的時候調用 onResume() 當Activity可以和用戶交互的時候調用 onPause() 當Activity不可和用戶交互的時候調用 onRestart() 當Activity停止了,但是沒有銷毀,從停止到啟動時調用


下圖是Activity生命周期圖:

這裡寫圖片描述

從圖解可知一個Activity有三個生命循環,如下圖所示:
這裡寫圖片描述

從上圖api文檔中可以知道Activity的生命周期有三個循環:
(1)完整生命周期:從onCreate(Bundle)開始到onDestory()結束。Activity在onCreate()設置的所有“全局“狀態,onDestory()釋放所有的資源。
(2)可見生命周期:從onStart()開始到onStop()結束。在這段時間,可以看到Activity在屏幕上,盡管可能不在前台,不能和用戶交互。在兩個接口之間,需要保持顯式給用戶UI的數據和資源等。
(3)前台生命周期:從onResume()開始到onPause()結束,在這段時間裡,該Activity處於所有Activity的最前面,和用戶進行交互。
Activity的整個生命周期都定義在對應的接口方法中,所有方法都可以被重載。所有的Activity都需要實現 onCreate(Bundle)去初始化設置,大部分Activity需要實現onPause()去提交更改過的數據。

3.3. 橫豎屏切換的生命周期變化

模擬器中,按快捷鍵Ctrl+F11進行橫豎屏切換。生命周期變化如下:

onPause()-onStop()-onDestory()-onCreate()-onStart()-onResume()

從上面橫豎屏切換的生命周期變化可以知道:當橫豎屏切換時先銷毀當前的Activity實例,再創建一個新Activity實例。

3.4. 橫豎屏配置

我們知道:在橫豎屏切換時,Activity會銷毀,然後再重新創建。那麼,如何操作才能使在切屏之後數據顯式保持原來而不變呢? 解決方案如下:

(a)在AndroidManifest.xml中配置橫豎屏:
android:screenOrientation=”portrait” 豎屏
android:screenOrientation=”landspace” 橫屏



上述配置,在清單文件中指定了屏幕的方向,即為“portrait”豎直方向。同理,我們也可以寫死為橫屏,即android:screenOrientation=”landscape”。若不指定該屬性的值,默認情況下該值為“sensor”,即根據傳感器來自動設置屏幕的方向。

(b)設置系統的環境,使其不再敏感橫豎屏的切換。讓系統不再敏感橫豎屏切換可以在activity中設置:
android:configChanges=”orientation|keyboardHidden|screenSize”
以下是configChanges中各個值的含義:

參數 含義 configChanges=”orientation” 屏幕方向改變:不讓屏幕在切換時重新創建activity。 sreensize 屏幕大小 keyboardHidden 軟鍵盤,如果切換屏幕,軟鍵盤會去判斷屏幕大小是否合適顯式軟鍵盤,在判斷過程中會重啟activity

4. 任務棧


4.1. 棧的概念

棧作為一種數據結構,是一種只能在一端進行插入和刪除操作的特殊線性表。它按照先進後出的原則存儲數據,先進入的數據被壓入棧底,最後的數據在棧頂,需要讀數據的時候從棧頂開始彈出數據。棧具有記憶作用,對棧的插入與刪除操作中,不需要改變棧底指針。棧可以用下圖表示:
這裡寫圖片描述

這裡寫圖片描述

4.2. 隊列的概念

隊列也是一種特殊的線性表,特殊之處在於它只允許在表的前端(front)進行刪除操作,而在表的後端(rear)進行插入操作,和棧一樣,隊列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。隊列中沒有元素時,稱為空隊列。通過對棧和隊列的比較,我們知道:棧是先進後出,後進先出;隊列是先進先出,後進後出。隊列可以用下圖表示:

這裡寫圖片描述

4.3. 任務棧的概念

任務棧:任務棧是用來提升用戶體驗而設計的,記錄打開界面和關閉界面的信息。每開啟一個應用程序,android操作系統就會給這個應用程序分配一個任務棧。

一般情況下每個應用程序一開啟就會創建一個任務棧,任務棧的id是自動增長的。

最小化的時候,應用程序實際上是後台運行,任務棧是保留的,當Activity退出了實際上就是任務棧清空了。

通過調用getTaskId()方法,可以獲取當前任務棧的Id。

5. Activity的啟動模式


在AndroidManifest.xml中,可以配置每個activity的啟動模式:例如:

    android:launchMode="standard"

(a)standard 標准模式
此模式,不管有沒有已存在的實例,都生成新的實例。每次調用startActivity()啟動Activity時都會創建一個新的Activity放在棧頂,每次返回都會銷毀實例並出棧,可以重復創建。

(b)singletop 單一頂部模式
如果任務棧的棧頂存在這個要開啟的activity,不會重新創建新的activity,而是復用已存在的activity。保證棧頂如果存在,則不會重復創建,但如果不在棧頂,那麼還是會創建新的實例。
應用場景:浏覽器的書簽

(c)singletask 單一任務模式
是一個比較嚴格的模式,在當前任務棧裡面只能有一個實例存在,當開啟activity的時候,就去檢查在任務棧裡面是否有實例已經存在,如果有實例存在就復用這個已經存在的activity,並且把這個activity上面的所有的別的activity都清空,復用這個已經存在的activity。
應用場景:BrowserActivity浏覽器界面,播放器的播放Activity
如果一個activity的創建需要占用大量的系統資源(cpu,內存)一般配置這個activity為singletask的啟動模式。webkit內核(c) 初始化需要大量內存如js解析引擎、html渲染引擎、http解析、下載…如果使用singletask模式,可以減少內存開銷,cpu占用。

(d)singleInstance
這種啟動模式比較特殊,它會啟用一個新的任務棧,activity會運行在自己的任務棧裡,這個任務棧裡面只有一個實例存在並且保證不再有其他Activity實例進入。在整個手機操作系統裡面只有一個實例存在。
應用場景:來電頁面。InCallScreenActivity

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved