Android學習之進程與消息處理(一)

Android學習之進程與線程

  進程與線程
  1.1 什麼是進程?
  是一個具有一定獨立功能的程序關於某個數據集合的一次運行活動,是操作系統動態執行的基本單元。
  通俗地講一個進程代表一個應用程序,該應用程序運行在自己的進程當中,使用系統爲其分配的堆內存,不受其他應用程序或者是其他進程的影響,是獨立運行的。當然一個進程中可以同時運行多個應用程序,這時堆內存是共享的。
  Android系統中,一個進程對應一個虛擬機,缺省情況下,一個應用的所有組件都運行在同一個進程中,當啓動一個應用程序組件時,如果該應用沒有正在運行的其它程序組件,那麼Android系統將爲這個應用創建一個新進程用於運行應用;在啓動一個應用程序組件時,這個應用已經有進程在運行(因爲有應用的其它組件存在),那麼這個應用程序組件將使用同一進程運行;你可以使用不同進程來運行不同的組件,或者在進程中創建新的線程。
  1.2 進程模型
  基於用戶ID的分配機制:
  安裝Android應用程序時,Android系統會爲每個程序分配一個Linux用戶ID,並設置相應的權限,這樣其它應用程序就不能訪問此應用程序所擁有的數據和資源。在Android系統上,一個用戶ID識別一個應用程序。應用程序通常位於設備上的ROM中,其在安裝時被分配一個用戶ID,並且保持不變。默認情況下,每個Android應用程序運行在它自己的進程中。當需要執行應用程序時,Android會啓動一個虛擬機,即一個新的進程來執行,因此不同的Android應用程序運行在相互隔離的環境中。
在這裏插入圖片描述
  假如兩個應用程序的用戶ID是一樣的,那麼這兩個應用程序將運行在同一個進程中,這就是一個進程中存在多個應用程序的情況,此時這兩個應用程序使用同一份堆內存,使用同一個虛擬機。要實現這個功能,首先必須使用相同的私鑰簽署這些應用程序,然後必須使用AndroidManifest.xml文件給它們分配相同的 Linux用戶ID,這通過在manifest節點下得屬性android:shared UserId來實現。
在這裏插入圖片描述
  1.3 Android中進程的生命週期
  Android系統爲每個應用程序分配了一個進程,應用程序中組件(Activity,Service,BroadCast)的狀態決定的一個進程的“重要性層次”,層次最低的屬於舊進程。這個“重要性層次”有五個等級,也就是進程的生命週期,按最高層次到最低層次排列如下:
  前臺進程 可見進程 服務進程 背景進程 空進程
  1.3.1 前臺進程:
  進程被認爲是前臺進程需滿足下面條件之一:
  本進程中有Activity是當前和用戶有交互的Activity;
  本進程中有Service和當前用戶有交互Activity的綁定;
  本進程中有在前臺運行的Service;
  本進程中有Service正在執行某個生命週期回調函數;
  本進程中的某個BroadcastReceiver正在執行onReceive()方法。
  1.3.2 可見進程:
  這種進程不含有任何在前臺運行的組件,但會影響當前顯示給用戶屏幕上的內容。
  進程被認爲是可見進程需滿足下面條件之一:
  本進程含有一個雖然不在前臺但卻部分可見的Activity;
  本進程含有綁定到可見Activity的Service。
  1.3.3 服務進程:
  該進程運行了某個使用startService()啓動的Service,此服務進程不直接和用戶可以看到的任何部分有關聯,服務會運行一些用戶關心的事情,比如在後臺播放音樂或者通過網絡下載文件,因此Android系統會盡量讓它們運行直到系統資源低到無法滿足前臺和可見進程的運行。
  1.3.4 後臺(背景)進程:
  進程運行一些目前用戶不可見的Activity,系統資源低時爲保證前臺、可見或服務進程運行,可隨時殺死該進程;通常系統中有很多進程在後臺運行,這些進程保存在LRU列表中,LRU列表可以保證用戶最後看到的進程最後被殺死。該進程對用戶體驗無直接的影響,如果一個Activity正確實現了它的生命週期函數,並保存了它的狀態,用戶回到該Activity時,該Activity就能夠正確恢復之前屏幕上的狀態。
  1.3.5 空進程:
  該進程不運行任何活動的應用程序組件,保持這種進程運行的唯一原因是由於緩存以縮短下次運行某個程序組件時的啓動時間;系統會爲了進程緩存和內核緩存之間的平衡經常會清除空進程。

  Android會依據進程中當前活躍組件的重要程度來儘可能高的估量一個進程的級別,比如說,如一個進程中同時有一個服務和一個可視的Activity,則進程會被判定爲可視進程,而不是服務進程。此外,一個進程的級別可能會由於其他進程依賴於它而升高。一個爲其他進程提供服務的進程級別永遠高於使用它服務的進程。
  1.4 Android進程間的通信(IPC)
  基於Binder的機制:
  Android系統並沒有採用Linux系統中那麼複雜的進程通信機制,可能是考慮到移動終端的硬件設備或者是其設備內存的問題。Android的Binder是基於OpenBinder來實現的。Binder可以參考Service來了解Android進程的通信。

  2.1 什麼是線程?
  線程是進程中的一個實體,基本思想是將程序的執行和資源分開,只擁有一點必不可少的資源。一個進程可擁有多個線程,可以和同屬於同一進程的其他線程共享進程所擁有的所有資源,同一進程中的線程之間可以併發執行,併發程度可以獲得顯著的提高。線程也具有許多進程所具有的特徵,因此被稱爲輕型進程。
  結合Android系統來說,當一個程序第一次啓動時,Android會同時啓動一個對應的主線程(Main Thread),主線程主要負責處理與UI相關的事件,比如:用戶的按鍵事件、用戶接觸屏幕的事件以及屏幕繪圖事件,並把相關的事件分發到對應的組件進行處理。所以主線程通常又被叫做UI線程。在開發Android應用時必須遵守單線程模型的原則: Android UI操作並不是線程安全的並且這些操作必須在UI線程中執行。
  2.2 Android的線程模型
  2.2.1 什麼是單線程模型?
  就是在一個進程中只能有一個線程在運行,剩下的線程必須等待當前的線程執行完了才能運行。
  2.2.2 什麼是線程安全?
  1.可以同時被多個線程調用,而調用者不需要任何動作(同步)來確保線程的安全性。
  2.當多個線程訪問一個類時,如果不用考慮這些線程在運行時環境下的調度和交替執行,並且不需要額外的同步及在調用方代碼不必作其他的協調,這個類的行爲仍然是正確的,那麼稱這個類是線程安全的。

  Android是單線程模型、線程非安全的。
  開發中特別注意:
  不要阻塞UI線程(單線程模型導致):會導致無法分發組件,繪製等,使得UI不再響應用戶操作,如果UI線程阻塞超過五秒鐘,系統將顯示“應用程序無響應”對話框。
  不要再非UI線程中調用和刷新UI相關的組件(線程非安全導致):UI線程本身會對組件進行調用,其他線程調用必須進行協調,可在其他線程中完成特定操作,再反饋給UI線程進行UI組件的操作,這樣所有的UI操作均有UI線程實現,避免出現訪問衝突。
  2.3 進程與線程
  一個Android應用只能存在一個進程,但是可以存在多個線程,也就是說,當應用啓動後,系統分配了內存,這個進程的內存不被其他進程使用,但被進程中一個或多個線程共享。宏觀地講所有的進程是併發執行的,而進程中的多個線程同時執行但並不是併發的,系統的CPU會根據應用的線程數觸發每個線程執行的時刻,當CPU時間輪到分配某個線程執行時刻時該線程開始執行,執行到下一個線程執行的時,依此輪詢,直到線程執行結束。
  2.4 進程與線程的重要性
  在Android應用的開發中,對進程的屬性的修改是有限的,僅僅操作一些屬性。對於線程來說,開發者就可以自由的進行操作,一個應用最少具有一個線程,可以有多個線程。合理的應用線程可以提高系統資源的利用率,提高應用的質量,給用戶更好的體驗,所以每個開發者都應該理解並熟練掌握線程知識。
  3 實現線程的主要方法
  3.1 通過繼承Thread類來實現
  · 定義一個線程類,繼承Thread類;
  · 重寫該類中的run()方法:將需要通過線程執行的操作,寫入該方法中;
  · 定義新建的線程類對象以實現線程操作。

    start():啓動線程
    sleep():線程休眠,交出cpu,線程進入阻塞態,不會釋放鎖
    wait():交出cpu,線程進入阻塞態,並釋放鎖
    interrupt():中斷線程,停止正在運行的線程,線程必須在阻塞態

  3.2 通過實現Runnable接口來實現
  · 和使用Thread類似,定義Runnable對象,並重寫其中的run()方法。
  3.3 通過實現Callable接口來實現
  · 定義Callable對象,並重寫其call()方法。
  3.4 三種方法的區別:
  · Callable可以返回值,其他兩個方法不能返回值;
  · Callable可以拋出異常,其他兩個方法不能拋出異常;
  · Callable可以獲得一個Future對象,以瞭解任務的執行情況。

  ☆☆☆Android Studio實現掌握Thread類的使用方法
  1.打開Android Studio,新建工程後,在activity_main.xml中界添加一個按鈕。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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="lession.example.com.androidlession2019522.MainActivity">
    
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <Button
            android:text="使用Thread類子線程"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAllCaps="false"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:id="@+id/button"
            android:textColor="@android:color/holo_red_dark"
            android:textSize="20sp" />
    </LinearLayout>
    
</RelativeLayout>

  2.在MainActivity中,編寫代碼。

package lession.example.com.androidlession2019522;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    int count;
    class mThread extends Thread{
        mThread(String name){
            super(name);
        }
        @Override
        public void run() {
            while (count<10000)
                Log.e("MainActivity",
                        Thread.currentThread().getName()+"--->"+count++);
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt = (Button) findViewById(R.id.button);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                count = 0;
                mThread mt1 = new mThread("Td1");
                mThread mt2 = new mThread("Td2");
                mThread mt3 = new mThread("Td3");
                mt1.start();
                mt2.start();
                mt3.start();
            }
        });
    }
}

  運行結果:
  在這裏插入圖片描述
  在這裏插入圖片描述
  這就是進程與線程的使用,如果轉載以及CV操作,請務必註明出處,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章