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 不用开发者自己去释放内存。