android線程睡眠
1. Android調用mtimer.schele(mtimertask, 1000, 5000);,然後在run中實現Thread.sleep()
在線程中睡眠不會影響timer的調度,即不會把間隔增加到9秒
在線程中不能設置UI的內容,不會生效,甚至會導致崩潰;改變UI的內容只能在UI線程中進行。
2. Android surfaceview實現顯示畫面但不立即播放功能!
package com.zsch.forestinventory.activity.left_activity;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.zsch.androidlib.activity.BaseActivity;
import com.zsch.androidlib.ui.ZoomableImageView;
import com.zsch.androidlib.view.LVCircularRing;
import com.zsch.forestinventory.R;
import java.io.IOException;
/**
* 查看單張照片
*/
public class ShowVideoActivity extends BaseActivity implements View.OnClickListener, MediaController.MediaPlayerControl, MediaPlayer.OnBufferingUpdateListener, SurfaceHolder.Callback {
private ImageButton ibBack;
private Uri uri;
private MediaPlayer mediaPlayer;
private MediaController controller; //視頻播放控制器
private int bufferPercentage = 0;
@Override
protected void initVariables() {
uri = getIntent().getData();
if (uri == null)
finish();
}
@Override
protected void initView(Bundle savedInstanceState) {
setContentView(R.layout.activity_show_video);
mediaPlayer = new MediaPlayer();
controller = new MediaController(this);
//媒體控制器將創建一個具有默認設置的控制項,並把它們放到一個窗口裡漂浮在你的應用程序上。具體來說,這些控制項會漂浮在通過setAnchorView()指定的視圖上
//設置這個控制器綁定(anchor/錨)到一個視圖上。例如可以旅轎者是一個VideoView對象,或者是你的activity的帆埋主視圖。
controller.setAnchorView(findViewById(R.id.root_ll));
if (savedInstanceState == null) {
// Bundle類型的數拆薯據與Map類型的數據相似,都是以key-value的形式存儲數據的。實際上,savedInstanceState也就是保存Activity的狀態的
//onsaveInstanceState方法是用來保存Activity的狀態的。當一個Activity在生命周期結束前,會調用該方法保存狀態
// 用來保存狀態信息的Bundle會同時傳給兩個method,即onRestoreInstanceState() and onCreate().
uri = getIntent().getData();
} else {
uri = savedInstanceState.getParcelable("uri");
}
if (uri == null) {
Toast.makeText(this, "無視頻展示", Toast.LENGTH_SHORT).show();
finish();
return;
}
SurfaceView videoSuf = (SurfaceView) findViewById(R.id.controll_surfaceView);
ibBack=(ImageButton) findViewById(R.id.ibBack);
ibBack.setOnClickListener(this);
videoSuf.setZOrderOnTop(false);//true時 會置頂到window的最上層,那麼會遮擋其它view ...
videoSuf.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
videoSuf.getHolder().addCallback(this); //只要繼承SurfaceView類並實現SurfaceHolder.Callback介面就可以實現一個自定義的SurfaceView了, 然後有surfaceCreated,surfaceChanged,surfaceDestroyed 等三種方法
// videoSuf.getHolder().setKeepScreenOn(true); //屏幕總是打開
//videoSuf.setFixedSize(320, 220);//顯示的解析度,不設置為視頻默認
}
@Override
protected void loadData() {
}
@Override
protected void onResume() {
super.onResume();
// try {
// mediaPlayer.setDataSource(uri.getPath()); //播放存儲設備的資源文件
// mediaPlayer.setOnBufferingUpdateListener(this); //監聽事件,網路流媒體的緩沖監聽。這個方法與上個介面中的方法int getBufferPercentage()進行結合使用
// //mediaPlayer.prepare();
// controller.setMediaPlayer(this);
// controller.setEnabled(true); //設置按鈕可點擊 false 設置為不可點擊
// }catch (IOException e){
// e.printStackTrace();
// }
}
@Override
protected void onPause() {
super.onPause();
if (mediaPlayer.isPlaying()){
mediaPlayer.stop();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (null != mediaPlayer){
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.ibBack:
onBackPressed();
break;
}
}
@Override
public void onBackPressed() {
// if (mediaPlayer.isPlaying()){
// mediaPlayer.stop();
// }
// if (null != mediaPlayer){
// mediaPlayer.release();
// mediaPlayer = null;
// }
finish(); // finish();//在Activity中執行this.finish()方法之後,執行如下過程: onPause(),onStop(),onDestory(),
}
@Override
public boolean onTouchEvent(MotionEvent event) { //實現這個方法來處理觸摸屏幕引發的事件。
controller.show();
return super.onTouchEvent(event);
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
//MediaPlayerControl
@Override
public void onBufferingUpdate(MediaPlayer mediaPlayer, int i) {
bufferPercentage = i;
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) { //這步很重要 surfaceCreated創建時使用 //必須在surface創建後才能初始化MediaPlayer,否則不會顯示圖像
try {
mediaPlayer.setDataSource(uri.getPath()); //播放存儲設備的資源文件
mediaPlayer.setOnBufferingUpdateListener(this); //監聽事件,網路流媒體的緩沖監聽。這個方法與上個介面中的方法int getBufferPercentage()進行結合使用
//mediaPlayer.prepare();
controller.setMediaPlayer(this);
controller.setEnabled(true); //設置按鈕可點擊 false 設置為不可點擊
}catch (IOException e){
e.printStackTrace();
}
//設置顯示視頻顯示在SurfaceView上
mediaPlayer.setDisplay(surfaceHolder);
// prepare方法是將資源同步緩存到內存中,一般載入本地較小的資源可以用這個,如果是較大的資源或者網路資源建議使用prepareAsync方法,非同步載入.
// 但如果想讓資源啟動,即start()起來,因為在非同步中,如果不設置監聽直接start的話,是拿不到這個資源,如果讓線程睡眠一段時間,則可以取得資源,
mediaPlayer.prepareAsync(); //准備 為非同步載入
controller.show(); //顯示控制器
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
//這里的 start()和pause() 指的是 media的拍攝過程中的 步驟
@Override
public void start() {
if (null != mediaPlayer){
mediaPlayer.start();
}
}
@Override
public void pause() {
if (null != mediaPlayer){
mediaPlayer.pause();
}
}
@Override
public int getDuration() {
return mediaPlayer.getDuration();
}
@Override
public int getCurrentPosition() { //獲得 視頻播放的位置 為了暫停後 繼續播放
return mediaPlayer.getCurrentPosition();
}
@Override
public void seekTo(int i) {
mediaPlayer.seekTo(i);
}
@Override
public boolean isPlaying() {
if (mediaPlayer.isPlaying()){
return true;
}
return false;
}
@Override
public int getBufferPercentage() {
return bufferPercentage;
}
@Override
public boolean canPause() {
return true;
}
@Override
public boolean canSeekBackward() {
return true;
}
@Override
public boolean canSeekForward() {
return true;
}
@Override
public int getAudioSessionId() {
return 0;
}
}
3. android 播放音樂時為什麼用不到混音線程mixerthread
MixerThread是按照音頻輸出的核心部分,所有Android的音頻都需要經過MixerThread進行混音後再輸出到音頻設備。
MixerThread的繼承關系如下:
MixerThread--->PlaybackThread--->ThreadBase--->Thread
在PlaybackThread中,重寫了Thread的threadLoop,onFirstRef等方法,因此在調用MixerThread這些方法時,實際上就是調用了PlaybackThread的方法。
1. onFirstRef
在getOutput的時候,我們創建了一個MixerThread對象,由於這個對象繼承於Thread,因此在創建對象時,會調用它的onFirstRef函數。
void AudioFlinger::PlaybackThread::onFirstRef(){ run(mName, ANDROID_PRIORITY_URGENT_AUDIO);}
在該方法內部,調用了run,即開始運行threadLoop。也就是說,其實在new MixerThread的時候就已經開始啟動PlaybackThread::threadLoop。
2. threadLoop
在分析threadLoop之前,我們先來了解MixerThread中的幾種Audio操作。
在Threads.cpp內有幾個threadLoop_xxx方法,這些方法就分別代表不同的Audio操作:
操作 方法 功能 standby threadLoop_standby 待機 mix threadLoop_mix 混音 write threadLoop_write 音頻輸出 exit threadLoop_exit 退出 drain threadLoop_drain 只有offload用到,還不清楚作用 sleep threadLoop_sleepTime 無音頻需要處理,睡眠
另外還有幾個非常重要的變數:
變數 取值 含義 tracksToRemove
需要被移除的Track,一旦所有的Track都被移除,則表明沒有音頻數據需要處理,那麼線程會進入睡眠
sleepTime
睡眠時間
standbyTime
如果持續睡眠超出standbyTime,則會進入待機
mStandby
表明當前是否為待機狀態
mActiveTracks
需要進行音頻處理的Track,如果該Track已經播放完成或者被停止,則會被移入tracksToRemove
mMixerStatus MIXER_IDLE
Mixer狀態,no active tracks,表明不需要混音,而是進入睡眠
4. 操作系統--阻塞,睡眠,掛起
線程從創建、運行到結束總是處於下面五個狀態之一:新建狀態、就緒狀態、運行狀態、阻塞狀態及死亡狀態。
所謂阻塞狀態是正在運行的線程沒有運行結束,暫時讓出CPU,這時其他處於就緒狀態的線程就可以獲得CPU時間,進入運行狀態。
線程運行過程中,可能由於各種原因進入阻塞狀態:
以上原因可以劃分成三大類:線程阻塞、線程睡眠、線程掛起。
操作系統中阻塞、睡眠、掛起純早的區別形象解釋。首先這些術語都是對於線程來說的,對線程的控制就好比你控制了一個僱工為你幹活。
線程阻塞:本來你讓僱工掃地,結果掃帚被偷了或被鄰居家借去了,你又沒讓僱工繼續干別的活,他就只好睡覺了。僱工一旦發現掃帚回來了,他就會自己去幹活的。
線程睡眠:你主動對僱工說:「你睡覺去吧,某時某刻過來報到,然後接著幹活」。
掛起線程:你對主動對僱工說:「你睡覺去吧,用著你的時候我主動去叫你,然後接著幹活」。
線程在運行做睜雀過程中必然要獲取訪問系統資源,暫且不說CPU,線程運行肯定要和磁碟進行交互,繼而發生IO操作,IO操作勢必要引起等待,在資源未讀取完成,線程必然要等待,那麼在等待IO完成這個部分就是阻塞狀態。所以從這里來看,阻塞是一種被動的方式,由於獲取資源獲取不到而引起的等待。
本人將線程阻塞細分成兩類:
當一個線程獲取資源失敗(但沒有觸發線程阻塞)暫時無法繼續運行時,可以有兩種處理方式:
從這里看,睡眠是一種主動的方式,且僅僅作為一種處理手段。睡眠不僅僅用於使線程進入阻塞狀態,更多的,我們可以在適當的時候設置讓線程睡眠一定的時間。
線程掛起是操作系統調度線程的手段之一,操作系統在調度時暫停當前線程的執行,將其切換至阻塞狀態,將CPU資源調度給其他的線程;在需要的時候,操作系統可以恢復某線程的執行許可權,將其切換至就緒狀態。
因此常見的線程掛起是一種被動的方式,場景如下:
某些情況下線程掛起是主動觸發的,比如調試程序時,線程執行到某個斷點,會主動掛起線程(trap陷入)。
線程掛起主要考慮CPU資源的調度,而進程掛起主要考慮是內存資源的分配。
掛起進程在操作系統中可以定義為暫時被淘汰出內存的進程,機器的資源是有限的,在資源不足的情況下,操作系統對在內存中的程序進行合理的安排,其中有的進程被暫時調離出內存,當條件允許的時候,會被操作系統再次調回內存,重新進入等待被執行的狀態即就緒態。
操作系統為什麼要引入掛起狀態?掛起狀態涉及到中級調度,因為當內存中的某個程序需要大的內存空間來執行,但這時內存有沒有空餘空間了,那麼操作系統就回根據調度演算法把一些進程放到外存中去,以騰出空間給正在執行的程序的數據和程序,所以引如了掛起狀態。引起掛起狀態的原因有如下幾方面:
(1)終端用戶的請求。當終端用戶在自己的程序運行期間發現有可疑問題時,希望暫停使自己的程序靜止下來。亦即,使正在執行的進程暫停執行;若此時用戶進程正處於就緒狀態而未執行,則該進程暫不接受調度,以便用戶研究其執行情況或對程序進行修改。我們把這種靜止狀態成為「掛起狀態」。
(2)父進程的請求。有時父進程希望掛起自己的某個子進程,以便考察和修改子進程,或者協調各子進程間的活動。
(3)負荷調節的需要。當實時系統中的工作負荷較重,已可能影響到對實時任務的控制時,可由系統把一些不重要的進程掛起,以保證系統能正常運行。
(4)操作系統的需要。操作系統有時希望掛起某些進程,以便檢查運行中的資源使用情況早跡或進行記賬。
(5)對換的需要。為了緩和內存緊張的情況,將內存中處於阻塞狀態的進程換至外存上。
5. Android中用什麼替換Thread.sleep
android 中,有的時候用Thread.sleep()是不合適的。
例如,你在用ProgressDialog 的時候,如果用的不合適,會使Progressdialog圖標不轉動。
代替方法是,用Handler.postDelayed需求是等2s,請求一下伺服器。等待的時候,顯示ProgressDialog 。
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sendMessage("");//耗時操作
替換成
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
sendMessage("");//耗時操作
}
}, 2000);
6. android開發等待一段時間後執行下一條語句,但是thread.sleep(30000)之後線程就掛起了
android的開發思路中,基本上都是由子線程去執行任務的,然後執行完了之後發回message再由handler去處理。這樣才不會影響程序連貫性的操作。
你這個需要sleep之後再執行的語句,就放到子線程中去。
7. android啟動後怎麼查看其裡面的進程和線程
1)一個 Android 程序開始運行時,會單獨啟動一個Process。
默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。
默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。
2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創建。該線程主要負責UI界面的顯示、更新和控制項交互,所以又叫UI Thread。
3)一個Android程序創建之初,一個Process呈現的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所以,MainThread所調用的每一個函數,其耗時應該越短越好,而對於比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程序出現ANR(Application not response)
一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態了?
【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬於哪個進程的。當然如果不明確指明,應該就是從屬於默認進程(Application指定的,如其未指定,應該就是默認主進程)。
Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。
原文地址:Android中的進程與線程 原文作者:江鵬
當應用程序的組件第一次運行時,Android將啟動一個只有一個執行線程的linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程:
1、進程
組件運行於哪個進程中由清單文件控制。組件元素——<activity>、<service>、<receiver>、<provider>,都有一個process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的許可權。<application>元素也有process屬性,為所有的組件設置一個默認值。
所有的組件都在特定進程的主線程中實例化,且系統調用組件是由主線程派遣。不會為每個實例創建單獨的線程,因此,對應這些調用的方法——諸如View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統調用時應該執行很長時間或阻塞操作(如網路操作或循環計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。
public boolean onKeyDown(int keyCode,KeyEvent event):默認實現KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然後釋放時執行,如果視圖可用且可點擊。
參數
keyCode-表示按鈕被按下的鍵碼,來自KeyEvent
event-定義了按鈕動作的KeyEvent對象
返回值
如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。
當內存剩餘較小且其它進程請求較大內存並需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。
當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前台進程),它更容易關閉一個進程,它的活動在屏幕是不可見(後台進程)。決定是否終結進程,取決於運行在進程中的組件狀態。關於組件的狀態,將在後面一篇——組件生命周期中介紹。
2、線程
雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些後台工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網路下載。任何不可能在短時間完成的操作應該分配到別的線程。
線程在代碼中是用標準的Java線程對象創建的,Android提供了一些方便的類來管理線程——Looper用於在線程中運行消息循環、Handler用戶處理消息、HandlerThread用戶設置一個消息循環的線程。
Looper類
該類用戶在線程中運行消息循環。線程默認沒有消息循環,可以在線程中調用prepare()創建一個運行循環;然後調用loop()處理消息直到循環結束。大部分消息循環交互是通過Handler類。下面是一個典型的執行一個Looper線程的例子,分別使用prepare()和loop()創建一個初始的Handler與Looper交互:
1. Android中進程與進程、線程與線程之間如何通信?
1)一個 Android 程序開始運行時,會單獨啟動一個Process。
默認情況下,所有這個程序中的Activity或者Service都會跑在這個Process。
默認情況下,一個Android程序也只有一個Process,但一個Process下卻可以有許多個Thread。
2)一個 Android 程序開始運行時,就有一個主線程Main Thread被創建。該線程主要負責UI界面的顯示、更新和控制項交互,所以又叫UI Thread。
3)一個Android程序創建之初,一個Process呈現的是單線程模型--即MainThread,所有的任務都在一個線程中運行,所以,MainThread所調用的每一個函數,其耗時應該越短越好,而對於比較耗時的工作,應該交給子線程去做,以避免主線程(UI線程)被阻塞,導致程序出現ANR(Application not response)
一個Activity就運行在一個線程中嗎?或者編碼時,如果不是明確安排在不同線程中的兩個Activity,其就都是在同一個線程中?那從一個Activity跳轉到另一個Activity時,是不是跳出的那個Activity就處在睡眠狀態了?
【答】 每個Activity都有一個Process屬性,可以指定該Activity是屬於哪個進程的。當然如果不明確指明,應該就是從屬於默認進程(Application指定的,如其未指定,應該就是默認主進程)。
Android中有Task的概念,而同一個Task的各個Activity會形成一個棧,只有站定的Activity才有機會與用戶交互。
原文地址:Android中的進程與線程 原文作者:江鵬
當應用程序的組件第一次運行時,Android將啟動一個只有一個執行線程的Linux進程。默認,應用程序所有的組件運行在這個進程和線程中。然而,你可以安排組件運行在其他進程中,且你可以為進程衍生出其它線程。本文從下面幾點來介紹Android的進程與線程:
1、進程
組件運行於哪個進程中由清單文件控制。組件元素——<activity>、<service>、<receiver>、<provider>,都有一個process屬性可以指定組件運行在哪個進程中。這個屬性可以設置為每個組件運行在自己的進程中,或者某些組件共享一個進程而其他的不共享。他們還可以設置為不同應用程序的組件運行在同一個進程中——假設這些應用程序共享同一個Linux用戶ID且被分配了同樣的許可權。<application>元素也有process屬性,為所有的組件設置一個默認值。
所有的組件都在特定進程的主線程中實例化,且系統調用組件是由主線程派遣。不會為每個實例創建單獨的線程,因此,對應這些調用的方法——諸如View.onKeyDown()報告用用戶的行為和生命周期通知,總是運行在進程的主線程中。這意味著,沒有組件當被系統調用時應該執行很長時間或阻塞操作(如網路操作或循環計算),因為這將阻塞進程中的其它組件。你可以為長操作衍生獨立的線程。
public boolean onKeyDown(int keyCode,KeyEvent event):默認實現KeyEvent.Callback.onKeyMultiple(),當按下視圖的KEYCODE_DPAD_CENTER或KEYCODE_ENTER然後釋放時執行,如果視圖可用且可點擊。
參數
keyCode-表示按鈕被按下的鍵碼,來自KeyEvent
event-定義了按鈕動作的KeyEvent對象
返回值
如果你處理事件,返回true;如果你想下一個接收者處理事件,返回false。
當內存剩餘較小且其它進程請求較大內存並需要立即分配,Android要回收某些進程,進程中的應用程序組件會被銷毀。當他們再次運行時,會重新開始一個進程。
當決定終結哪個進程時,Android會權衡他們對用戶重要性的相對權值。例如,與運行在屏幕可見的活動進程相比(前台進程),它更容易關閉一個進程,它的活動在屏幕是不可見(後台進程)。決定是否終結進程,取決於運行在進程中的組件狀態。關於組件的狀態,將在後面一篇——組件生命周期中介紹。
2、線程
雖然你可能會將你的應用程序限制在一個進程中,但有時候你會需要衍生一個線程做一些後台工作。因為用戶界面必須很快地響應用戶的操作,所以活動寄宿的線程不應該做一些耗時的操作如網路下載。任何不可能在短時間完成的操作應該分配到別的線程。
線程在代碼中是用標準的Java線程對象創建的,Android提供了一些方便的類來管理線程——Looper用於在線程中運行消息循環、Handler用戶處理消息、HandlerThread用戶設置一個消息循環的線程。
Looper類
該類用戶在線程中運行消息循環。線程默認沒有消息循環,可以在線程中調用prepare()創建一個運行循環;然後調用loop()處理消息直到循環結束。大部分消息循環交互是通過Handler類。下面是一個典型的執行一個Looper線程的例子,分別使用prepare()和loop()創建一個初始的Handler與Looper交互:
2.1、遠程過程調用(Remote procere calls,RPCs)
Android有一個輕量級的遠程過程調用機制——方法在本地調用卻在遠程(另外一個進程中)執行,結果返回給調用者。這需要將方法調用和它伴隨的數據分解為操作系統能夠理解的層次,從本地進程和地址空間傳輸到遠程進程和地址空間,並重新組裝調用。返回值以相反方向傳輸。Android提供了做這些工作的所有代碼,這樣我們可以專注於定義和執行RPC介面本身。
一個RPC介面僅包含方法。所有的方法同步地執行(本地方法阻塞直到遠程方法執行完成),即使是沒有返回值。簡言之,該機制工作原理如下:首先,你用簡單的IDL(interface definition language,介面定義語言)聲明一個你想實現的RPC介面。從這個聲明中,aidl工具生成一個Java介面定義,提供給本地和遠程進程。它包含兩個內部類,如下圖所示:
內部類有管理你用IDL定義的介面的遠程過程調用所需要的所有代碼。這兩個內部類都實現了IBinder介面。其中之一就是在本地由系統內部使用,你寫代碼可以忽略它。另外一個是Stub,擴展自Binder類。除了用於有效地IPC(interprocess communication)調用的內部代碼,內部類在RPC介面聲明中還包含方法聲明。你可以定義Stub的子類實現這些方法,如圖中所示。
通常情況下,遠程過程有一個服務管理(因為服務能通知系統關於進程和它連接的其它進程的信息)。它有由aidl工具生成的介面文件和Stub子類實現的RPC方法。服務的客戶端僅有由aidl工具生成的介面文件。
下面介紹服務如何與它的客戶端建立連接:
· 服務的客戶端(在本地端的)應該實現onServiceConnected() 和onServiceDisconnected() 方法,因此當與遠程服務建立連接成功和斷開連接是會通知它。然後調用bindService() 建立連接。
· 服務的onBind()方法將實現為接受或拒絕連接,者取決於它接受到的意圖(該意圖傳送到binServive())。如果連接被接受,它返回一個Stub子類的實例。
· 如果服務接受連接,Android調用客戶端的onServiceConnected()方法且傳遞給它一個IBinder對象,返回由服務管理的Stub子類的一個代理。通過代理,客戶端可以調用遠程服務。
這里只是簡單地描述,省略了一些RPC機制的細節。你可以查閱相關資料或繼續關注Android開發之旅,後面將為你奉上。
2.2、線程安全方法
在一些情況下,你實現的方法可能會被不止一個線程調用,因此必須寫成線程安全的。這對遠程調用方法是正確的——如上一節討論的RPC機制。當從IBinder進程中調用一個IBinder對象中實現的一個方法,這個方法在調用者的線程中執行。然而,當從別的進程中調用,方法將在Android維護的IBinder進程中的線程池中選擇一個執行,它不在進程的主線程中執行。例如,一個服務的onBind()方法在服務進程的主線程中被調用,在onBind()返回的對象中執行的方法(例如,實現RPC方法的Stub子類)將在線程池中被調用。由於服務可以有一個以上的客戶端,所以同時可以有一個以上的線程在執行同一個IBinder方法。因此,IBinder的方法必須是線程安全的。
同樣,一個內容提供者可以接受其它進程產生的數據請求。雖然ContentResolver 和 ContentProvider 類隱藏進程通信如何管理的,對應哪些請求的ContentResolver 方法——query()、insert()、delete()、update()、getType(),在內容提供者的進程的線程池中被調用,而不是在這一進程的主線程中。因為這些方法可以同時從任意數量的線程中調用,他們也必須實現為線程安全的。
8. android系統睡眠狀態如何喚醒線程和廣播
不能!
(不能手動喚醒,因為肯定需要點亮屏幕(手動點亮屏幕),所以並不是真睡眠狀態)。
只能提前設置,比如鬧鍾,具體到「廣播」即收音機,那麼只建議使用第三方程序,如「蜻蜓FM」,就像鬧鍾可以定時自動開啟。
如果是自己造,相當於重新編個程序出來,需要掌握大量專業性的東西,得不償失
9. kotlin實現android 消息機制
大部分人應該都明白,簡單過一下。
這個稍微復雜一點
此demo有一點與android的不同,在沒有消息時,android使用linux內核epoll機制 實現線程睡眠,而本demo使用的是線程鎖
demo傳送門 https://github.com/pokercc/message-demo
請注意工程結構基於idea,不是android studio
10. android 子線程長時間休眠會不會被殺死
會, android 應用程序層使用java 語言, java 有gc 自動回收機制, 長時間沒有使用的資源會自動回收,所以說一般情況下java 不用開發者自己去釋放內存。