barriers / 阅读 / 详情

android中looper的实现原理,为什么调用looper.prepare就在当前线程关联了一个lo

2023-08-22 08:09:49
共1条回复
clou
实际上:消息发送和计划任务提交之后,它们都会进入某线程的消息队列中,我们可以把这个线程称之为目标线程。不论是主线程还是子线程都可以成为目标线程。上例中之所以在主线程中处理消息,是因为我们要更新UI,按照android中的规定我们必须由主线程更新UI。所以我们让主线程成为了目标线程。

那么如何控制让某个线程成为目标线程呢?

这就引出了Looper的概念。Android系统中实现了消息循环机制,Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。Android系统中的通过Looper帮助线程维护着一个消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
前面提到每个线程都可以有自己的消息队列和消息循环,然而我们自己创建的线程默认是没有消息队列和消息循环的(及Looper),要想让一个线程具有消息处理机制我们应该在线程中先调用Looper.prepare()来创建一个Looper对象,然后调用Looper.loop()进入消息循环。如上面的源码所示。
当我们用Handler的构造方法创建Handler对象时,指定handler对象与哪个具有消息处理机制的线程(具有Looper的线程)相关联,这个线程就成了目标线程,可以接受消息和计划任务了。Handler中的构造方法如下:

[java] view
plaincopyprint?

public Handler() {

if (FIND_POTENTIAL_LEAKS) {

final Class<? extends Handler> klass = getClass();

if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&

(klass.getModifiers() & Modifier.STATIC) == 0) {

Log.w(TAG, "The following Handler class should be static or leaks might occur: " +

klass.getCanonicalName());

}

}

mLooper = Looper.myLooper();

if (mLooper == null) {

throw new RuntimeException(

"Can"t create handler inside thread that has not called Looper.prepare()");

}

mQueue = mLooper.mQueue;

mCallback = null;

}

public Handler(Looper looper) {

mLooper = looper;

mQueue = looper.mQueue;

mCallback = null;

}
public Handler() {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can"t create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}

public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}

在上述的计时器的例子中,之所以可以在主线程中处理消息而我们自己并没有调用Looper.prepare()等方法,是因为Android系统在Activity启动时为其创建一个消息队列和消息循环,当我们用无参的Handler构造方法创建对象时又用了当前线程的Looper对象,及将handler与主线程中的Looper对象进行了关联。

android中是使用Looper机制来完成消息循环的,但每次创建线程时都先初始化Looper比较麻烦,因此Android为我们提供了一个HandlerThread类,他封装了Looper对象,是我们不用关心Looper的开启和释放问题。

不管是主线程还是其他线程只要有Looper的线程,别的线程就可以向这个线程的消息队列中发送消息和任务。

我们使用HandlerThread类代替上一篇文章中的子线程,并用HandlerThread类中的Looper对象构造Handler,则接受消息的目标线程就不是主线程了,而是HandlerThread线程。代码如下:

[java] view
plaincopyprint?

public class clockActivity extends Activity {

/** Called when the activity is first created. */

private String TAG="clockActivity";

private Button endButton;

private TextView textView;

private int timer=0;

private boolean isRunning=true;

private Handler handler;

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

endButton=(Button)findViewById(R.id.endBtn);

textView=(TextView)findViewById(R.id.textview);

endButton.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// TODO Auto-generated method stub

isRunning=false;

}

});

HandlerThread thread=new HandlerThread("myThread");

handler=new Handler(thread.getLooper());//与HandlerThread中的Looper对象关联

thread.start();

Runnable r=new Runnable(){

@Override

public void run() {

// TODO Auto-generated method stub

if(isRunning){

textView.setText("走了"+timer+"秒");

timer++;

handler.postDelayed(this, 1000);//提交任务r,延时1秒执行

}

}

};

handler.postDelayed(r, 1000);

}

}
  public class clockActivity extends Activity {
/** Called when the activity is first created. */
private String TAG="clockActivity";
private Button endButton;
private TextView textView;
private int timer=0;
private boolean isRunning=true;
private Handler handler;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
endButton=(Button)findViewById(R.id.endBtn);
textView=(TextView)findViewById(R.id.textview);
endButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
isRunning=false;
}
});
HandlerThread thread=new HandlerThread("myThread");
handler=new Handler(thread.getLooper());//与HandlerThread中的Looper对象关联
thread.start();
Runnable r=new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
if(isRunning){
textView.setText("走了"+timer+"秒");
timer++;
handler.postDelayed(this, 1000);//提交任务r,延时1秒执行
}
}
};
handler.postDelayed(r, 1000);
}
}

  此时处理任务会在handlerThread线程中完成。当然这个例子会出线异常:依然是因为在非主线程中更新了UI。这样做只是为了大家能够理解这种机制。

  深入理解Android消息处理机制对于应用程序开发非常重要,也可以让我们对线程同步有更加深刻的认识,希望这篇文章可以对朋友们有所帮助。

相关推荐

looper上单崩过吗

Looper上单崩过吗?上单这个位置不同的选手风格差异很大,不同的版本上单霸主就会不同,但唯独Looper,他可以做到跨版本C,在上单坦克的版本,他是能掏出坦克来carry,基本上没有能难倒他的英雄,在他的帮助下,MLXG一度成为顶级肉食性打野。  Looper选手个人资料  ID:Looper  姓名:蒋(张)亨硕  年龄:28  擅长英雄:炼金、蒙多、大树、兰博、奎因、艾克  探龙点评:纵观整个英雄联盟职业赛上,有一个算一个,到现在为止也没有一个像Looper这样的选手,绝活海,拿出来就能C,你都不知道他什么时候练得,从肉到刺客,从法师到战士,都是他的拿手好戏,最可怕的是,Looper就像一颗石头,很难把他当做突破口。  Looper职业生涯  SSW在2014年夺得S4全球总决赛冠军之后,五个选手便开始了他们的魔幻人生,有的成为教练指点江山背起黑锅,有的后院着火净身出户,而大多数人却成为韩援,来到LPL,用剩下的职业生涯换来一张白纸黑字的合同,而Looper也是如此,无论是在M3还是RNG,Looper都是既当爹又当妈,拿着坦克要抗压,打团还要补输出,不到两年,便对职业和英雄联盟没了兴趣,退役后决定重返校园,而不是当主播养老,咱也不知道LPL有何等魔力,把他折磨成这样,只能说生不逢时,但凡他在年轻几年,赶上新一代LPL选手,还是有希望再LPL取得成绩的,好巧不巧,来的这两年恰逢第一代高手要么变捞,要么退役,而天才少年都在青训等着18出山。
2023-08-13 05:25:451

Android之Looper使用

Looper是Android中用于实现消息循环的一个类,它和Handler、MessageQueue、Message等一起组成了异步消息处理机制。通过它,我们可以在后台线程中实现UI更新等操作。使用Looper,一般需要以下步骤:1. 在子线程中创建Looper对象,并开启消息循环:```javaLooper.prepare();Looper.loop();```2. 在子线程中创建Handler对象,并通过Handler对象发送消息到消息队列中:```javaHandler handler = new Handler() { @Override public void handleMessage(Message msg) { // 在这里处理消息 }};handler.sendEmptyMessage(0);```3. 在主线程中创建Handler对象,并通过Handler对象发送消息到子线程中的消息队列中:```javanew Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 在这里处理消息 } }; Looper.loop(); }}).start();Handler handler = new Handler() { @Override public void handleMessage(Message msg) { // 在这里发送消息到子线程 handler.sendEmptyMessage(0); }};```需要注意的是,子线程中的消息循环要在消息发送之前开启,在消息处理完成之后才能结束,否则程序会崩溃。同时,在子线程退出前,需要调用Looper.quit()方法来结束消息循环。另外,在使用Looper时还需要注意避免内存泄露问题,避免使用匿名内部类等操作。
2023-08-13 05:25:544

Android-Looper

Looper.loop是一个死循环,拿不到需要处理的Message就会阻塞,那在UI线程中为什么不会导致ANR? 首先我们来看造成ANR的原因: 1.当前的事件没有机会得到处理(即主线程正在处理前一个事件,没有及时的完成或者looper被某种原因阻塞住了) 2.当前的事件正在处理,但没有及时完成 我们再来看一下APP的入口ActivityThread的main方法: 显而易见的,如果main方法中没有looper进行死循环,那么主线程一运行完毕就会退出,会导致直接崩溃,还玩什么! 现在我们知道了消息循环的必要性,那为什么这个死循环不会造成ANR异常呢? 我们知道Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它,这也就是我们为什么不能在UI线程中处理耗时操作的原因。 主线程Looper从消息队列读取消息,当读完所有消息时,主线程阻塞。子线程往消息队列发送消息,唤醒主线程,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。因此loop的循环并不会对CPU性能有过多的消耗。 初始化当前线程和Looper,这样可以在实际开始启动循环(loop())之前创建一个Handler并且关联一个looper。确保在先调用这个方法,然后调用loop()方法,并且通过调用quit()结束。 这里面的入参boolean表示Looper是否允许退出,true就表示允许退出,对于false则表示Looper不允许退出。 初始化当前当前线程的looper。并且标记为一个程序的主Looper。由Android环境来创建应用程序的主Looper。因此这个方法不能由咱们来调用。另请参阅prepare() 这里的sThreadLocal.get()是和prepare(boolean)方法里面的sThreadLocal.set(new Looper(quitAllowed));一一对应的。而在prepareMainLooper()方法里面。 退出循环 将终止(loop()方法)而不处理消息队列中的任何更多消息。在调用quit()后,任何尝试去发送消息都是失败的。例如Handler.sendMessage(Message)方法将返回false。因为循环终止之后一些message可能会被无法传递,所以这个方法是不安全的。可以考虑使用quitSafely()方法来确保所有的工作有序地完成。 安全退出循环 调用quitSafely()方法会使循环结束,只要消息队列中已经被传递的所有消息都将被处理。然而,在循环结束之前,将来不会提交处理延迟消息。 调用退出后,所有尝试去发送消息都将失败。就像调用Handler.sendMessage(Message)将返回false。
2023-08-13 05:26:011

如何在iPhone上循环播放视频

1、下载Looper。2、打开Looper。3、点击+4、查看相册。5、按提示点击所有照片6、选择一个视频。7、点击选择8、点击红色的"重复"(repeat)按钮。9、拖动屏幕底部的滑块到无限播放10、点击[[Image:11、点击是12、选择屏幕方向。13、点击是14、出现成功信息后,点击Ok本文会教你在iPhone上循环播放视频。虽然iPhone上没有循环视频的内置方法,但你可以下载一个叫Looper的免费应用程序,创建连续循环50次的视频。1、下载Looper。Looper可以让你从iPhone上导出视频的循环版本,而无需牺牲音质,也无需购买应用。它是同类型中唯一一款免费软件。按下面的步骤下载Looper:打开iPhoneAppStore。点击搜索。点击搜索栏。输入looper后点击搜索。向下滚动到带有白色无穷大符号的红色应用程序,然后点击安装。出现提示时,输入iPhone的TouchID或AppleID密码。2、打开Looper。点击应用商店里的打开,或者点击iPhone主屏幕上的环形应用程序图标。3、点击+。它在Looper程序屏幕的顶部。然后会弹出一个菜单。4、查看相册。点击+后就会进入此页面。5、按提示点击所有照片。打开你的iPhone相册。6、选择一个视频。向下滚动直到找到想要循环的视频,然后单击一次视频。可能与你想像的相反,Looper会在列表的顶部打开你最旧的视频。你要一直滑动到列表底部,才能看到最新的视频。7、点击选择。它在屏幕的右下角。这样会在Looper打开视频。8、点击红色的"重复"(repeat)按钮。此选项位于屏幕的右下角。9、拖动屏幕底部的滑块到无限播放。这样做可以让视频一直循环无数次。如果你希望视频只循环几次,不要向右滑动到底。拖动滑块到显示"播放#次"和你想要循环的次数。10、点击[[Image:|techicon|x30px]]按钮。这个图标在屏幕的顶部。11、点击是。Looper会开始导出视频。12、选择屏幕方向。可以选择纵向或横向,取决于视频是垂直拍摄还是水平拍摄的。13、点击是。允许Looper在相册中存储视频。14、出现成功信息后,点击Ok。这样就完成了整个过程。你的循环视频现在保存在"照片"应用中。你可以打开"照片"应用。找到视频,点击它来循环播放。小提示打开“Forever”(无限)开关,导出视频后可以让视频连续循环50次。不过如果视频时间较长,可能会减少循环次数。如果只是想在Looper程序内循环视频,通过“+”菜单进行选择,打开“Forever”开关后,点击左上角的“播放”按钮。警告在导出视频之前,Looper会降低视频的质量。
2023-08-13 05:26:081

英雄联盟历史中各位置最佳选手是谁

LOL这个游戏已经陪伴大家走过了数个春秋,而在职业联赛中,每个时期都有那么几位冠绝全场的选手,只要他们一出场,其他选手就只能成为背景板。 那么在游戏5个位置中,大家心目中历史上最完美的选手是哪些呢?本期资讯要谈到的这5位选手,当时都是各个位置的NO1。 1、上单位:S4总决赛时期SSW Looper。 还记得在S4的时候,Looper是当时玩家们公认的世界第一上单。 他的风格打法非常全面,既能玩carry型上单,又能当团队前排。 拿最少的资源,发挥最大的作用,打法稳健,是当时队伍里的中流砥柱。 但自SSW解散后Looper来到LPL加入WEA队惨被军训,不复以往,S6来到RNG在LPL联赛终捧杯,近日已宣告退役。 2、中单位:S6总决赛时期SKT Faker。 Faker作为LOL中最传奇的选手,每年S赛状态都非常好。 但是要说到最强的状态,应该还是在S6总决赛上,那年他的瑞兹一场未败,英雄池更是深不见底。 刺客英雄、传统法师、辅助中单,没有Faker不会玩的英雄。 加上当时SKT其他选手也正处巅峰,他们的配合,成就了大魔王般的Faker。 但如今的SKT王朝没落,能不能打进S8都是很大的问题。 3、打野位:S5MSI时期EDG Clearlove。 那年EDG在首届MSI上,就打败了当时的巅峰SKT, 双方打满5场,尤其是最后1把厂长秒锁寡妇,配合队友完美发挥,击败了当时无敌的男人Faker,载入LPL史册。 那时候的厂长,敢打敢拼,无论是意识还是操作都是巅峰期,在韩服更是70多胜率打上前十,让人怀念。 如今厂长经历了食草期、腐食期,如今想转回食肉的风格,或许已经回不去了。 4、AD位: S8MSI时期RNG UZI。 严格来说,小狗在每个时期实力都是很强的,但是只有在MSI上,小狗的发挥,完全超出其他AD选手至少一个身位,拿了优势就可以打爆下路,被针对也能在团战中打出爆炸输出,完全没有克制他的方法。 他的卡莎在MSI上保持着不败金身,其他AD选手只能望尘莫及。 5、辅助位:S4总决赛时期SSW Mata。 这个位置很多玩家可能会认为是Madelife,虽然他是辅助的传奇人物,但是他在S赛上并没有太多成绩而mata是S4总决赛的MVP,他同样是辅助位置的革新者,最开始把风女当作进攻性辅助的选手。 他的指挥、视野布控,在当时无人能比,作为辅助选手,还在世界官方排名里位列第三。
2023-08-13 05:26:181

缝纫机零件looper是什么?

是“环套”的意思。
2023-08-13 05:26:261

ThreadLocal如何保证一个线程只能有一个Looper?

我们都知道在调用Looper.prepare的时候会创建一个Looper,那么是如何保证一个线程只有一个Looper的? 首先要知道Looper中有一个sThreadLocal变量,ThreadLocal用于存储上下文信息 并且用final static 修饰,所以它是唯一的内容不可变的 了解sThreadLocal是干啥用的后,再来看看prepare 先调用sThreadLocal.get()方法 而ThreadLocalMap 是一个HashMap,那么取到一个HashMap后判断是否为null 如果不存在key为sThreadLocal的节点,得到value = null,并把这个value作为sThreadLocal的值即<sThreadLocal,null>;如果map为null,则创建一个HashMap并把<sThreadLocal,null>节点加入 这样get方法就要么取到一个Looper,要么就是null,如果为Looper则抛异常,如果为null,则调用sThreadLocal.set() 其实都是把Looper作为sThreadLocal的value值 回到开头说的,怎么保证一个线程只有一个Looper? 因为sThreadLocal是线程的上下文,并且唯一,而线程中存有<sThreadLocal,Looper>key-value键值对,所以一个sThreadLocal对应一个Looper,并且再次修改Looper是,会抛异常,因为Looper已经存在。 所以一个线程只有一个Looper。 如果对HashMap还不了解的同学,这篇文章可能对你有一定帮助 HashMap原理
2023-08-13 05:26:511

looper鼓击什么牌子好?

JOYO卓乐效果不错音质清晰,表面平滑完整是不错的选择。JOYO卓乐科技,成立于2006年,起初为开发生产电子调音器,现为中国最大的单块效果器开发、设计、生产于一体的科技公司。自成立以来一直处于快速发展状态,吸引了大批手工单块工程师的加入,产品深受国内外乐手们的喜爱。卓乐旗下独立运作的高端品牌,它是能够让你做出属于你自己音色的单块效果器,音乐发烧友的最爱。深圳市卓乐科技有限公司是一家专注和精于开发、生产,销售音乐教育电子数字产品的科技公司。公司拥有一批敬业和经验丰富的优秀开发、生产、销售人员。拥有先进的管理理念,理性化的制度,采用优越的电脑管理软件
2023-08-13 05:27:201

怎么获得当前线程的looper

  Looper.prepare()方法在当前线程里面调用,目的是创建一个新的Looper,且一个线程只能创建一个Looper.  public static void prepare() {  if (sThreadLocal.get() != null) {  throw new RuntimeException("Only one Looper may be created per thread");  }  sThreadLocal.set(new Looper());  }  public void set(T value) {  Thread currentThread = Thread.currentThread();  Values values = values(currentThread);  if (values == null) {  values = initializeValues(currentThread);  }  values.put(this, value);  }  可以看出set的时候绑定了currentThread。
2023-08-13 05:27:301

全球十大上单排行榜 韩国选手霸榜

英雄同盟游戏中,上单地位是相当重要的,能够说一代版本一代神,可是有些选手从出道直至本人职业生活结尾,都是处于很顶峰的状况。那么明天百街秀小编就来为人人清点寰球十大上单,感兴味的同伙们快来看看吧。寰球十大上单:一、Theshy二、MaRin3、looper4、impact5、Smeb6、Duke7、CuVee8、Nuguri9、Gogoing10、Khan一、Theshy具体介绍:Theshy关于目前年青的观众来讲是一名很熟识的职业选手,也是现在公认的天下第一上单,不管是在LPL联赛的统治显露,仍是天下赛上的ldquo;天神下凡rdquo;,都给人记忆犹新。二、MaRin具体介绍:MaRin于2014年参加SKT战队,资助部队斩获了多个联赛冠军,S5资助SKT斩获了天下冠军,自己还获取了那时总决赛的MVP。3、looper具体介绍:looper最早效能于三星白战队,S4资助部队克服了皇族,夺患有天下冠军,后来参加到了LPL联赛,负责RNG战队上单,有着异常波动的显露,不管是进攻仍是抗压。4、impact具体介绍:impact被称作是SKT战队的一代目上单,实力相对是无庸置疑的,资助部队拿下多个联赛冠军,同时也是S3天下冠军上单,目前参加了北美赛区,实力维持得不停都很波动。5、Smeb具体介绍:Smeb很早就最先了职业生活,早年间在ROX战队就曾经是大放异彩,在LCK联赛以及天下赛上的显露都异常优异,加盟KT战队之后也是资助部队斩获了LCK联赛冠军。6、Duke具体介绍:Duke原为KT战队选手,后来转回至NaJin,2016年景为了SKT首发上单,资助部队获取了当年的寰球总决赛冠军,加盟IG之后,追随部队前后获取了2018年洲际赛冠军,以及S8寰球总决赛冠军。7、CuVee具体介绍:CuVee最早效能于三星战队,资助部队获取了S7寰球总决赛冠军;2018年部队堕入低谷,可是CuVee凭仗在冒泡赛上卓越的变现,再次率领着部队进去了寰球总决赛。8、Nuguri具体介绍:Nuguri为DWG战队上单,是一名长于进攻的选手,压抑才能异常强,虽然部队现在没有取得很好的成果,可是Nuguri不停都被以为是战队的波动carry位,相对是一名排得上名号的上单选手。9、Gogoing具体介绍:Gogoing于2012年参加OMG负责上单位,在2013年资助部队取患有LPL春天赛冠军,在那时更是彻底统治了LPL的上路,天下赛上的鳄鱼、瑞兹更是如入无人之境,当时候阴郁权势OMG一起前行离不开老大的优异施展。10、Khan具体介绍:Khan被良多人熟知是在S8时期参加KZ后随队拿下了LCK春天赛冠军,并一度有第一上单的名称。2019转会SKT,资助部队夺患有LCK春天赛冠军,虽然S9天下赛止步四强,但Khan小我的团体施展照旧长短常亮眼的,本年来到FPX也照旧维持着高水准的竞技状况。王者之心2点击试玩
2023-08-13 05:27:371

为什么rng上单一个接一个垮掉?

为什么rng上单一个接一个垮掉?作为RNG的粉丝我认为我可以简略的解答一下这个问题.我来列一下rng历届上单在rng队内期间的表现和最后的结局。另一个就是所谓的垮掉是什么。我以我个人的理解暂定为:这个人能力下滑,捞逼了。建队的时候上单letme,当时是king和gt的老人凑起来的,具体哪些人出自哪个队伍记不清了,当是让确实不强,也不能说垮,因为本来也不厉害,当时那支rng也不厉害,后来就下放二队了。第二任looper,冠军上单,这个人没别的,就是强,因为当年下路无心实力确实一般,looper近乎rng亲爹,最后走的时候更谈不上垮掉。looper走后letme又辗转回到一队,但这次不同以往的是letme下了很大决心要打好。之后确实慢慢成长起来,18年那段时间更是一跃成为世界级上单,但是s8世界赛一战之后到德杯打完,明显感觉到letme没有当年决定回到rng的时候那股心气了,自己在心里都在告诉自己:“严君泽你打不了了。”非常可惜,某种层面上来说,letme最后是垮掉了。letme还在首发时,18年初招入了姿态,算是替补吧,姿态算是上古选手了,之前是打中单,被rng叫来打上单,有心carry,但是神经刀,在rng一年后退役,19年又拉出来救火,然并卵,姿态也没垮,他除了早期惊鸿一现,接下来几年都是这样。再往后来到s9,aj加入,这也是来救火,本来都已经要退役了。何况aj也一直不是carry型选手,一直玩肉坦,又碰上打架的版本,苦的一批。无法适应版本,玩不了战士上单,这对于一名职业选手来说,算是有点垮吧。aj和姿态挣扎了一个春季赛之后,s9夏季赛狼行加入,狼行是以carry(大保健)表现出名的,不过来到也神经刀了,垮还不至于,看后续表现吧。lovezrr打的不多,不好评价。不过看得出来有一颗carry的心,就是被shy爹教育的有点惨。这么看下来,rng历任上单选手,我觉得说得上垮掉的,letme算一个,心气没了,自己也承认玩不来剑魔这种类型的上单,回去试训了几把效果不好,所以退役了。aj只能说人家一直这种英雄池,这版本对他不太友好,但他玩不来战士也是有点垮。其实也谈不上一个一个都垮掉,当年looper在的时候下路mata无心,rng是打上中野的,looper基本就是被养的那个爹,只能说全华班的rng没法引入强力的上单选手了,隔壁的cuvee、kiin、semb、nuguri、khan都很强,还有blg的add也不错,所以今年世界赛还真不好说。
2023-08-13 05:27:451

什么时候使用Looper.prepare

Handler类怎么会算线程呢,它是用来发送和处理消息用的,而Looper类是用来存储消息队列以及处理消息循环的一个封装类。UI线程本身已经实现了消息队列,所有可以直接创建Handler类而自己创建的线程要实现消息处理,必须调用Looper.prepare()来创建消息队列以及其他一些步骤的初始化,再创建Handler,最后调用Looper.loop()实现消息循环
2023-08-13 05:28:101

拥有超强的意志控制力是什么体验,《环形使者》讲述了什么故事?

一名杀手通过超能力去杀未来的,让这个人在时间上永远的消失,后来他遇到了自己心爱的人,并为此特别纠结。
2023-08-13 05:28:183

looper为什么离开rng

因为bug
2023-08-13 05:28:532

循环中Looper.loop;之后,代码不能运行,是怎么回事

import fund123.com.db.DownDatasTask;import fund123.com.db.OnDownDatasListener;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Looper;import android.os.Message;import android.provider.Settings.Secure;import android.util.Log;public class MessageService extends Service { private static final String ITEM_MESSAGE = "message"; private static final String ITEM_TITLE = "title"; private static final String ITEM_TIME = "addtime";//获取消息线程 private Thread mThread = null; //点击查看 //private Intent msgIntent = null; private PendingIntent msgPendingIntent = null; //通知栏消息 private int msgNotificationid = 1000; private Notification msgNotification = null; private NotificationManager msgNotificatiomanager = null; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onStart(Intent intent, int startId) { //初始化 msgNotification = new Notification(); msgNotification.icon = R.drawable.icon1; msgNotification.tickerText = "新消息"; msgNotification.defaults = Notification.DEFAULT_SOUND; msgNotification.flags = Notification.FLAG_AUTO_CANCEL; msgNotificatiomanager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); //开启线程 MsgThread thread=new MsgThread(); mThread=new Thread(thread); mThread.start(); } // @Override// public void onDestroy() {//// System.exit(0);// super.onDestroy();// }class MsgThread implements Runnable{ public boolean isrunning = true; public void run() { while(isrunning){ try { //休息1分钟 Thread.sleep(60000); //获取服务器消息 Looper.prepare(); Log.v("测试1", "测试1"); loadPushMessage(); Looper.loop(); Log.v("测试2", "测试2"); } catch (InterruptedException e) { e.printStackTrace(); } } } }private void loadPushMessage(){ String mobileid = Secure.getString(getBaseContext().getContentResolver(), Secure.ANDROID_ID); String string_url = Client3Application.url_getData + getResources().getString(R.string.url_push_msg, mobileid); final DownDatasTask down_datas_task_ = new DownDatasTask(); down_datas_task_.execute(string_url); down_datas_task_.setOnDownDatasListener(new OnDownDatasListener() { @Override public void onDownData() { int count = down_datas_task_.getDataCount(); if (count > 0) { Message msg=new Message(); msg.what=1; String string_msg = down_datas_task_.getData(0, ITEM_MESSAGE).toString(); String string_title = down_datas_task_.getData(0, ITEM_TITLE).toString(); String string_time = down_datas_task_.getData(0, ITEM_TIME).toString(); Bundle data = new Bundle(); data.putString("message", string_msg); data.putString("time", string_time); data.putString("title", string_title); msg.setData(data); mHandler.sendMessage(msg); Log.v("测试3", "测试3"); } down_datas_task_.cancel(true); down_datas_task_.clearData(); } }); } private Handler mHandler=new Handler(){ public void handleMessage(Message msg) { int i = msg.what; if(i > 0){ Bundle data = msg.getData(); String string_msg = data.getString("message"); String string_time = data.getString("time"); String string_title = data.getString("title"); Bundle bundle = new Bundle(); Intent msgIntent = new Intent(); bundle.putString("message", string_msg); bundle.putString("time", string_time); bundle.putString("title", string_title); msgIntent.putExtras(bundle); msgIntent.setClass(MessageService.this, MessageActivity.class); msgPendingIntent = PendingIntent.getActivity(MessageService.this,0,msgIntent,0); //更新通知栏 msgNotification.setLatestEventInfo(MessageService.this,"新消息",string_title,msgPendingIntent); msgNotificatiomanager.notify(msgNotificationid, msgNotification); //每次通知完,通知id递增一下,避免消息覆盖掉 msgNotificationid++; } } };}
2023-08-13 05:29:142

请问VLP8效果器单块LOOPER如何使用?

LOOP仅仅就是一个线路选择器~它没有任何效果,没有任何干扰性,对于串联进他的单块本身也没有任何控制力,他只是在控制你TS9所在的那一线路罢了,如你所言把TS9踩灭了,A和B里的音色里就没有TS9的声音了,你打开里面就有TS9了,你放个OD1进去A和B里就是OD1的动静。也就是说LOOP只能控制经不经过这一路,至于这一路里是TS9还是SD1跟LOOP没有关系,至于你的单块是过载音色还是失真音色也跟他没有关系~他只控制线路,唯一的用处就是图方便。VLP8挺好玩一个玩意 如果单块多而复杂的话,用它归置归置还不错,比马丁便宜,比很多网友手工的看起来精细,如果你就几个单块穿着用,实在没必要~VLP8的使用方法:(1):将单块效果器连接入L1-L8接口,SEND接单块效果器的INPUT端,RETRUN接单块效果器的OUTPUT端。(2):将吉他连接到Input插口(3):将Output连接到音箱的Input端(4):接通电源,将接入的全部单块开启。(5):接上电源后为全部BYPASS状态,这时可以看到组状态指示灯在闪动,通过调整BANK+/-及AB(CD)选择你要使用一组音色。(6):踩下A或BCD任意一键进行库内的音色切换,连续踩下A B C D中任意一只开关,可切换BYPASS或开启(7):踩下BANK+或BANK-进行库切换,总工有1-8 8个可选库。编组:(1):按下EDIT键,可以看见显示屏幕显示“E.”字样,表明PXL已经进入编辑模式(2):在按下EDIT键后,即可通过操作A B C D开关来打开或关闭单块,对于VLP8来说,需要配合库减(BANK-)按键进行操作,按动BANK-按键,屏幕会显示“H”或“L”字样,当显示为H时,A B C D操作L5-L8接口中接入的单块;当显示为L时,A B C D操作L1-L4接口中对应的单块,按下一次A或B C D任意一个,将打开或关闭对应单块一次(3):在设置完需要打开或关闭的单块后,按一下STORE(存储)按键,设定即可被保存下来。
2023-08-13 05:29:591

Android中为什么主线程不会因为Looper.loop方法造成阻塞

因为Android 的是由事件驱动的,Looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下。所以不存在主线程会被Looper.loop方法阻塞。如果 Looper.loop()被干掉了,应用也就挂掉了。
2023-08-13 05:30:421

android主线程中是不是只有一个Looper,一个MessageQueue

Android中的Runnable并不一定是新开的线程,比如下面调用的方法就是运行在UI主线程中Hanlder handler = new Handler();handler.post(new Runnable(){ public void run(){}});官方文档对此的解释是:The runnable will be run on the user interface thread. ”boolean android.view.View .post(Runnable action)Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.Parameters: action The Runnable that will be executed. Returns: Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.我们可以通过handler的对象的post方法,把Runnable对象(一般是Runnable的子类)传过去,handler会在Looper中调用Runnable的run方法执行,Runnable是一个接口,不是一个线程,一般线程会实现Runnable接口这里我们看代码handler.post(new Runnable(){好像是new了一个interface,其实是new一个实现Runnable的匿名内部类(Inner Anoymous Class)}) 这是一个简练的方法Runnalbe是一个接口,不是一个线程,一般线程会实现Runnalbe接口,所以如果我们使用匿名内部类是运行在UI主线程的,如果我们使用实现这个Runnable接口的线程类,则是运行在对应的线程的。具体来说这个函数的工作原理如下:View.post(Runnalbe)方法,在post(Runanble action)方法中,View获得当前主线程(即UI线程)的handler,然后将action对象post到handler里面去,在Handler里,它将传递过来的action对象封装成一个Message(Message 的callback为action),然后将其投入到UI线程的消息循环中,在handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法,而此时,已经路由到UI线程里,因此我们可以毫无顾虑来更新UI。如下图,前面看到的代码,我们这里的Message的callback为一个Runnalbe的匿名内部类,这种情况下,由于不是在新的线程中使用,所以千万别做复杂的计算逻辑。
2023-08-13 05:30:491

Android Handle中Looper.loop()的死循环为什么在主线程中不会产生卡死现象

1. 主线程,负责一些UI更新操作,归类为一个线程,线程在Android中是有生命周期的,任务最终是会结束的。 2. Looper.loop()的死循环正是维护了主线程的超长生命周期,loop方法一直循环处理任务,没有任务的时候会休眠,有任务的时候会唤醒然后进行处理,所以也不会占用太多系统资源。 3. 卡死,可能有误解,循环的过程中本生不会出现ANR,在循环的过程中,如果执行了耗时且在规定时间内没有完成消息派发,才会出现ANR。
2023-08-13 05:31:121

Looper.myLooper;什么意思

环形使者 时凶猎杀 回路杀手
2023-08-13 05:31:412

android启动后怎么查看其里面的进程和线程

. 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 procedure 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(),在内容提供者的进程的线程池中被调用,而不是在这一进程的主线程中。因为这些方法可以同时从任意数量的线程中调用,他们也必须实现为线程安全的。
2023-08-13 05:31:491

效果器的作用是什么

摘要:效果器是专用于产生各种效果的电子仪器,效果器有什么用呢?效果器的作用是改变原有声音的波形,调制或延迟声波的相位、增强声波的谐波成分等一系列措施,产生各种特殊声效。许多乐器、合唱等都会使用效果器,下面一起来详细了解一下什么是效果器以及效果器的作用吧。什么是效果器效果器是一种可以令电子乐器或音讯的音色加以修饰的电子器材。效果器之于电吉他系统,类似滤镜之于照相机,或是酱油之于红烧排骨。拍照的时候,滤镜没法让云彩变成大象,但能让他更好看;做菜的时候,酱油没法让排骨变成鸡腿,但能让他更好吃。吉他和音箱作为音色的主要来源,决定了声音的基本特质,效果器则使其更加丰富多变的形式呈现出来。效果器的作用是什么效果器是提供各种声场效果的音响周边器材。原先主要用于录音棚和电影伴音效果的制作,现在已广泛应用现场扩声系统。无论效果器的品质如何优秀,如果不能掌握其调整技巧,不但无法获得预期的音响效果,而且还会破坏整个系统的音质。效果器的基本效果类型有声场效果、特殊效果和声源效果三大类。数字效果一般都储存有几十种或数百种效果类型,有的效果器还有参数均衡、噪声门、激励器和压缩/限幅某功能。使用者可根据自己的需要选择相应的效果类型。效果器的种类有哪些1、如果按结构来分类,效果器有:①机架式效果器,因为售价、体积、使用方式等问题,并不是大众的最佳选择。②踏板式效果器,大家对“效果器”的第一反应往往是这个,不光我们在用,大师也在用。按照功能的多寡还能再分为单块效果器和综合效果器,这两者之间的关系类似于纯手动的定焦镜头和带自动对焦马达的变焦镜头。③软件式效果器,没有必要贬低软件效果器,毕竟科技在进步,有人拍照喜欢镜头前装滤镜,有人就喜欢回家用lightroom调,具体选哪种跟经济条件、使用场景、使用习惯有很大关系。现在很多音箱自带一些周边效果,可以看作是内置了效果器。2、如果按对信号的处理方式,效果器有:削波类(失真、过载等),滤波类(压缩、哇音等),调制类(颤音、合唱等),复制类(延迟、混响等)。在此基础上按功能细分,就是我们通常直观能见的效果器种类了:(1)过载overdrive失真distortion法兹fuzz(2)压缩compression哇音wah均衡equalize(3)合唱chorus颤音tremolo(改变音量)&vibrato(改变音高)相位phaser镶边flanger噪音门noisegate(4)延迟delay混响reverb循环looper
2023-08-13 05:31:561

C++里子线程回调主线程的怎么做

首先,当主线程创建的时候,会建立一个Looper对象,然后子线程执行到需要主线程调用某方法的时候,会将Message加入到一个MessageQueue队列,Looper对象所属的线程在Looper.Loop方法中循环执行从MessageQueue队列读取Message对象当读取到Message的时候,就会调用主线程中的相应方法
2023-08-13 05:32:391

Android 重学系列 View的绘制流程(六) 硬件渲染(上)

本文开始聊聊Android中的硬件渲染。如果跟着我的文章顺序,从SF进程到App进程的绘制流程一直阅读,我们到这里已经有了一定的基础,可以试着进行横向比对如Chrome浏览器渲染流程,看看软件渲染,硬件渲染,SF合成都做了什么程度的优化。 先让我们回顾一下负责硬件渲染的主体对象ThreadedRenderer在整个绘制流程中做了哪几个步骤。 在硬件渲染的过程中,有一个很核心的对象RenderNode,作为每一个View绘制的节点对象。 当每一次进行准备进行绘制的时候,都会雷打不动执行如下三个步骤: 如果遇到什么问题欢迎来到 https://www.jianshu.com/p/c84bfa909810 下进行讨论 实际上整个硬件渲染的设计还是比较庞大。因此本文先聊聊ThreadedRender整个体系中主要对象的构造以及相关的原理。 首先来认识下面几个重要的对象有一个大体的印象。 在Java层中面向Framework中,只有这么多,下面是一一映射的简图。 能看到实际上RenderNode也会跟着View 树的构建同时一起构建整个显示层级。也是因此ThreadedRender也能以RenderNode为线索构建出一套和软件渲染一样的渲染流程。 仅仅这样?如果只是这么简单,知道我习惯的都知道,我喜欢把相关总结写在最后。如果把总揽写在正文开头是因为设计比较繁多。因为我们如果以流水线的形式进行剖析容易造成迷失细节的困境。 让我继续介绍一下,在硬件渲染中native层的核心对象。 如下是一个思维导图: 有这么一个大体印象后,就不容易迷失在源码中。我们先来把这些对象的实例化以及上面列举的ThreadedRenderer在ViewRootImpl中执行行为的顺序和大家来聊聊其原理,先来看看ThreadedRenderer的实例化。 当发现mSurfaceHolder为空的时候会调用如下函数: 而这个方法则调用如下的方法对ThreadedRenderer进行创建: 文件:/ frameworks / base / core / java / android / view / ThreadedRenderer.java 能不能创建的了ThreadedRenderer则决定于全局配置。如果ro.kernel.qemu的配置为0,说明支持OpenGL 则可以直接返回true。如果qemu.gles为-1说明不支持OpenGL es返回false,只能使用软件渲染。如果设置了qemu.gles并大于0,才能打开硬件渲染。 我们能看到ThreadedRenderer在初始化,做了三件事情: 关键是看1-3点中ThreadRenderer都做了什么。 文件:/ frameworks / base / core / jni / android_view_ThreadedRenderer.cpp 能看到这里是直接实例化一个RootRenderNode对象,并把指针的地址直接返回。 能看到RootRenderNode继承了RenderNode对象,并且保存一个JavaVM也就是我们所说的Java虚拟机对象,一个java进程全局只有一个。同时通过getForThread方法,获取ThreadLocal中的Looper对象。这里实际上拿的就是UI线程的Looper。 在这个构造函数有一个mDisplayList十分重要,记住之后会频繁出现。接着来看看RenderNode的头文件: 文件:/ frameworks / base / libs / hwui / RenderNode.h 实际上我把几个重要的对象留下来: 文件:/ frameworks / base / core / java / android / view / RenderNode.java 能看到很简单,就是包裹一个native层的RenderNode返回一个Java层对应的对象开放Java层的操作API。 能看到这个过程生成了两个对象: 这个对象实际上让RenderProxy持有一个创建动画上下文的工厂。RenderProxy可以通过ContextFactoryImpl为每一个RenderNode创建一个动画执行对象的上下文AnimationContextBridge。 文件:/ frameworks / base / libs / hwui / renderthread / RenderProxy.cpp 在这里有几个十分重要的对象被实例化,当然这几个对象在聊TextureView有聊过( SurfaceView和TextureView 源码浅析 ): 我们依次看看他们初始化都做了什么。 文件:/ frameworks / base / libs / hwui / renderthread / RenderThread.cpp 能看到其实就是简单的调用RenderThread的构造函数进行实例化,并且返回对象的指针。 RenderThread是一个线程对象。先来看看其头文件继承的对象: 文件:/ frameworks / base / libs / hwui / renderthread / RenderThread.h 其中RenderThread的中进行排队处理的任务队列实际上是来自ThreadBase的WorkQueue对象。 文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h ThreadBase则是继承于Thread对象。当调用start方法时候其实就是调用Thread的run方法启动线程。 另一个更加关键的对象,就是实例化一个Looper对象到WorkQueue中。而直接实例化Looper实际上就是新建一个Looper。但是这个Looper并没有获取当先线程的Looper,这个Looper做什么的呢?下文就会揭晓。 WorkQueue把一个Looper的方法指针设置到其中,其作用可能是完成了某一件任务后唤醒Looper继续工作。 而start方法会启动Thread的run方法。而run方法最终会走到threadLoop方法中,至于是怎么走进来的,之后有机会会解剖虚拟机的源码线程篇章进行讲解。 在threadloop中关键的步骤有如下四个: 在这个过程中创建了几个核心对象: 另一个核心的方法就是initializeDisplayEventReceiver,这个方法为WorkQueue的Looper注册了监听: 能看到在这个Looper中注册了对DisplayEventReceiver的监听,也就是Vsync信号的监听,回调方法为displayEventReceiverCallback。 我们暂时先对RenderThread的initializeDisplayEventReceiver方法探索到这里,我们稍后继续看看回调后的逻辑。 文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h 能看到这里的逻辑很简单实际上就是调用Looper的pollOnce方法,阻塞Looper中的循环,直到Vsync的信号到来才会继续往下执行。详细的可以阅读我写的 Handler与相关系统调用的剖析 系列文章。 文件:/ frameworks / base / libs / hwui / thread / ThreadBase.h 实际上调用的是WorkQueue的process方法。 文件:/ frameworks / base / libs / hwui / thread / WorkQueue.h 能看到这个过程中很简单,几乎和Message的loop的逻辑一致。如果Looper的阻塞打开了,则首先找到预计执行时间比当前时刻都大的WorkItem。并且从mWorkQueue移除,最后添加到toProcess中,并且执行每一个WorkItem的work方法。而每一个WorkItem其实就是通过从某一个压入方法添加到mWorkQueue中。 到这里,我们就明白了RenderThread中是如何消费渲染任务的。那么这些渲染任务又是哪里诞生呢? 上文聊到了在RenderThread中的Looper会监听Vsync信号,当信号回调后将会执行下面的回调。 能看到这个方法的核心实际上就是调用drainDisplayEventQueue方法,对ui渲染任务队列进行处理。 能到在这里mVsyncRequested设置为false,且mFrameCallbackTaskPending将会设置为true,并且调用queue的postAt的方法执行ui渲染方法。 还记得queue实际是是指WorkQueue,而WorkQueue的postAt方法实际实现如下: / frameworks / base / libs / hwui / thread / WorkQueue.h 情景带入,当一个Vsync信号达到Looper的监听者,此时就会通过WorkQueue的drainDisplayEventQueue 压入一个任务到队列中。 每一个默认的任务都是执行dispatchFrameCallback方法。这里的判断mWorkQueue中是否存在比当前时间更迟的时刻,并返回这个WorkItem。如果这个对象在头部needsWakeup为true,说明可以进行唤醒了。而mWakeFunc这个方法指针就是上面传下来: 把阻塞的Looper唤醒。当唤醒后就继续执行WorkQueue的process方法。也就是执行dispatchFrameCallbacks方法。 在这里执行了两个事情: 先添加到mPendingRegistrationFrameCallbacks集合中,在上面提到过的threadLoop中,会执行如下逻辑: 如果mPendingRegistrationFrameCallbacks大小不为0,则的把mPendingRegistrationFrameCallbacks中的IFrameCallback全部迁移到mFrameCallbacks中。 而这个方法什么时候调用呢?稍后就会介绍。其实这部分的逻辑在TextureView的解析中提到过。 接下来将会初始化一个重要对象: 这个对象名字叫做画布的上下文,具体是什么上下文呢?我们现在就来看看其实例化方法。 文件:/ frameworks / base / libs / hwui / renderthread / CanvasContext.cpp 文件:/ device / generic / goldfish / init.ranchu.rc 在init.rc中默认是opengl,那么我们就来看看下面的逻辑: 首先实例化一个OpenGLPipeline管道,接着OpenGLPipeline作为参数实例化CanvasContext。 文件:/ frameworks / base / libs / hwui / renderthread / OpenGLPipeline.cpp 能看到在OpenGLPipeline中,实际上就是存储了RenderThread对象,以及RenderThread中的mEglManager。透过OpenGLPipeline来控制mEglManager进而进一步操作OpenGL。 做了如下操作: 文件:/ frameworks / base / libs / hwui / renderstate / RenderState.cpp 文件:/ frameworks / base / libs / hwui / renderthread / DrawFrameTask.cpp 实际上就是保存这三对象RenderThread;CanvasContext;RenderNode。 文件:/ frameworks / base / core / jni / android_view_ThreadedRenderer.cpp 能看到实际上就是调用RenderProxy的setName方法给当前硬件渲染对象设置名字。 文件:/ frameworks / base / libs / hwui / renderthread / RenderProxy.cpp 能看到在setName方法中,实际上就是调用RenderThread的WorkQueue,把一个任务队列设置进去,并且调用runSync执行。 能看到这个方法实际上也是调用post执行排队执行任务,不同的是,这里使用了线程的Future方式,阻塞了执行,等待CanvasContext的setName工作完毕。
2023-08-13 05:32:471

lol喜欢玩上单和辅助,比较喜欢looper和madlife,我想换个id,有啥好的id吗?

Penta Kill
2023-08-13 05:32:566

Android——消息分发机制

什么是 Handler 机制 ? Handler 机制是 Android 中用于 线程间通信 的一套通信机制。 为什么是 Handler ?Handler 机制为什么被那么多次的提及 ? 从Android4.0开始,Android 中网络请求强制不允许在主线程中操作,而更新UI的操作则不允许在子线程中执行。当在子线程中执行网络请求,拿到服务器返回的数据之后,要更新UI。由于系统的要求,势必会产生一种矛盾:数据在子线程,更新UI要在主线程。此时我们必须要把数据返回到主线程中才行,Handler机制应运而生。 Android 中针对耗时的操作,放在主线程操作,轻者会造成 UI 卡顿,重则会直接无响应,造成 Force Close。同时在 Android 3.0 以后,禁止在主线程进行网络请求。 针对耗时或者网络操作,那就不能在主线程进行直接操作了,需要放在子线程或者是工作线程中进行操作,操作完成以后,再更新主线程即 UI 线程。这里就涉及到一个问题了,在子线程执行完成以后,怎么能更新到主线程即 UI 线程呢,针对以上问题,就需要用到 Android 的消息机制了,即: Handler, Message, MessageQueue, Looper 全家桶 Handler机制中最重要的四个对象 Handler的构造方法: Looper : Handler的使用: MessageQueue: Looper.loop() Handler.dispatchMessage() handler导致activity内存泄露的原因: handler发送的消息在当前handler的消息队列中,如果此时activity finish掉了,那么消息队列的消息依旧会由handler进行处理,若此时handler声明为内部类(非静态内部类),我们知道内部类天然持有外部类的实例引用,这样在GC垃圾回收机制进行回收时发现这个Activity居然还有其他引用存在,因而就不会去回收这个Activity,进而导致activity泄露。 假如在子线程执行了耗时操作,这时用户操作进入了其他的 acitvity, 那么 MainActivity 就会被内存回收的,但是这个时候发现 Handler 还在引用着 MainActivity,内存无法及时回收,造成内存泄漏。 Handler 防止内存泄漏常见方法: 为什么通过 Handler 可以把子线程的结果通知或者携带给 UI 线程 ? 这里的 Handler 指的是主线程的 Handler ,同时与 Handler 配套的 Looper , MessageQueue 是在 UI 线程初始化的,所以在子线程中调用 Handler 发送消息可以更新 UI 线程。 Looper 在 UI 线程源码, 在 ActivityThread 类:
2023-08-13 05:33:111

Handler 源码解析:nativePollOnce阻塞和nativeWake唤醒

Android Handler机制 - MessageQueue如何处理消息 Handler 如何做到阻塞 Android篇:2019初中级Android开发社招面试解答(中) Handler消息机制组成: 如何保证looper的唯一性 每个线程只有一个looper,而每个Thread中都又一个关键Threadlocal。是用于存放每个线程的looper对象的,存取的方式是通过get/set。相当于一个map的存放方式。键位key是当前线程的实例。value就是looper对象。所以每次创建looper都会去ThreadLocal里面找有没有当前线程的looper。 如何知道 message 发送到哪个handler处理 当使用 Handler.sendMessage() 发送消息时,调用 enqueueMessage 方法内有 msg.target = this 将 Handler 实例赋值给 msg 对象。当 loop() 取出消息时,调用 dispatchMessage 方法根据 target 属性,回调对应 handler 实例的 handlerMessage 方法处理消息。 调用nativeWake唤醒(这部分内容出自头部连接,详细源码分析可看前辈的) 既然有写入消息,那必定要把消息处理掉,所以唤醒了epoll_wait(),然后继续方法调动awoken(),这个方法就是将之前写入的1读出,表示消费这个事件 随后在Java 层的next()@MessageQueue 就被唤醒,读取在enqueueMessage()@MessageQueue 插在队头的消息进行处理
2023-08-13 05:33:191

labview ui线程和任意线程的区别

实际上:消息发送和计划任务提交之后,它们都会进入某线程的消息队列中,我们可以把这个线程称之为目标线程。不论是主线程还是子线程都可以成为目标线程。上例中之所以在主线程中处理消息,是因为我们要更新UI,按照android中的规定我们必须由主线程更新UI。所以我们让主线程成为了目标线程。那么如何控制让某个线程成为目标线程呢?这就引出了Looper的概念。Android系统中实现了消息循环机制,Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。Android系统中的通过Looper帮助线程维护着一个消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。前面提到每个线程都可以有自己的消息队列和消
2023-08-13 05:33:401

bboxlooper软件如何保存已编辑的内容?

在软件中编辑好标签内容之后,点击文件-保存,弹出保存对话框,给标签起个名字,就可以根据自己的需求保存到合适的位置,如图所示:
2023-08-13 05:34:031

App在启动后的运行逻辑

假设一个App被启动了,界面成功显示,那么站在进程的角度去看它后续的运行过程,究竟是怎样的呢? 当App进程启动完成之后,ActivityThread类被创建出来,他的main()方法执行,执行main()方法的这个线程称作UI线程。然后执行Looper.prepareMainLooper(),此时UI线程的消息队列已经准备好,可以通过Handler发送消息到该队列了(后续与AMS的通讯正是通过这种方式执行的)。然后,再执行Looper.loop(),也就是阻塞的从消息队列中去取消息(可以是用户发的消息,也可以是系统发的消息),如果没有,UI线程进入睡眠状态。 UI线程被唤醒的时机: 3.Binder中断。当应用程序中创建了一个Binder,便会自动创建一个线程用来接收消息,如ApplicationThread用来接收AMS的IPC消息,如果在Binder线程中收到消息后向UI队列中发送一条消息,那么next()方法也会被唤醒。
2023-08-13 05:34:221

Android 中的“子线程”解析

Android 中线程可分为 主线程 和 子线程 两类,其中主线程也就是 UI线程 ,它的主要这作用就是运行四大组件、处理界面交互。子线程则主要是处理耗时任务,也是我们要重点分析的。 首先 Java 中的各种线程在 Android 里是通用的,Android 特有的线程形态也是基于 Java 的实现的,所以有必要先简单的了解下 Java 中的线程,本文主要包括以下内容: 在 Java 中要创建子线程可以直接继承 Thread 类,重写 run() 方法: 或者实现 Runnable 接口,然后用Thread执行Runnable,这种方式比较常用: 简单的总结下: Callable 和 Runnable 类似,都可以用来处理具体的耗时任务逻辑的,但是但具体的差别在哪里呢?看一个小例子: 定义 MyCallable 实现了 Callable 接口,和之前 Runnable 的 run() 方法对比下, call() 方法是有返回值的哦,泛型就是返回值的类型: 一般会通过线程池来执行 Callable (线程池相关内容后边会讲到),执行结果就是一个 Future 对象: 可以看到,通过线程池执行 MyCallable 对象返回了一个 Future 对象,取出执行结果。 Future 是一个接口,从其内部的方法可以看出它提供了取消任务(有坑!!!)、判断任务是否完成、获取任务结果的功能: Future 接口有一个 FutureTask 实现类,同时 FutureTask 也实现了 Runnable 接口,并提供了两个构造函数: 用 FutureTask 一个参数的构造函数来改造下上边的例子: FutureTask 内部有一个 done() 方法,代表 Callable 中的任务已经结束,可以用来获取执行结果: 所以 Future + Callable 的组合可以更方便的获取子线程任务的执行结果,更好的控制任务的执行,主要的用法先说这么多了,其实 AsyncTask 内部也是类似的实现! 注意, Future 并不能取消掉运行中的任务,这点在后边的 AsyncTask 解析中有提到。 Java 中线程池的具体的实现类是 ThreadPoolExecutor ,继承了 Executor 接口,这些线程池在 Android 中也是通用的。使用线程池的好处: 常用的构造函数如下: 一个常规线程池可以按照如下方式来实现: 执行任务: 基于 ThreadPoolExecutor ,系统扩展了几类具有新特性的线程池: 线程池可以通过 execute() 、 submit() 方法开始执行任务,主要差别从方法的声明就可以看出,由于 submit() 有返回值,可以方便得到任务的执行结果: 要关闭线程池可以使用如下方法: IntentService 是 Android 中一种特殊的 Service,可用于执行后台耗时任务,任务结束时会自动停止,由于属于系统的四大组件之一,相比一般线程具有较高的优先级,不容易被杀死。用法和普通 Service 基本一致,只需要在 onHandleIntent() 中处理耗时任务即可: 至于 HandlerThread,它是 IntentService 内部实现的重要部分,细节内容会在 IntentService 源码中说到。 IntentService 首次创建被启动的时候其生命周期方法 onCreate() 会先被调用,所以我们从这个方法开始分析: 这里出现了 HandlerThread 和 ServiceHandler 两个类,先搞明白它们的作用,以便后续的分析。 首先看 HandlerThread 的核心实现: 首先它继承了 Thread 类,可以当做子线程来使用,并在 run() 方法中创建了一个消息循环系统、开启消息循环。 ServiceHandler 是 IntentService 的内部类,继承了 Handler,具体内容后续分析: 现在回过头来看 onCreate() 方法主要是一些初始化的操作, 首先创建了一个 thread 对象,并启动线程,然后用其内部的 Looper 对象 创建一个 mServiceHandler 对象,将子线程的 Looper 和 ServiceHandler 建立了绑定关系,这样就可以使用 mServiceHandler 将消息发送到子线程去处理了。 生命周期方法 onStartCommand() 方法会在 IntentService 每次被启动时调用,一般会这里处理启动 IntentService 传递 Intent 解析携带的数据: 又调用了 start() 方法: 就是用 mServiceHandler 发送了一条包含 startId 和 intent 的消息,消息的发送还是在主线程进行的,接下来消息的接收、处理就是在子线程进行的: 当接收到消息时,通过 onHandleIntent() 方法在子线程处理 intent 对象, onHandleIntent() 方法执行结束后,通过 stopSelf(msg.arg1) 等待所有消息处理完毕后终止服务。 为什么消息的处理是在子线程呢?这里涉及到 Handler 的内部消息机制,简单的说,因为 ServiceHandler 使用的 Looper 对象就是在 HandlerThread 这个子线程类里创建的,并通过 Looper.loop() 开启消息循环,不断从消息队列(单链表)中取出消息,并执行,截取 loop() 的部分源码: dispatchMessage() 方法间接会调用 handleMessage() 方法,所以最终 onHandleIntent() 就在子线程中划线执行了,即 HandlerThread 的 run() 方法。 这就是 IntentService 实现的核心,通过 HandlerThread + Hanlder 把启动 IntentService 的 Intent 从主线程切换到子线程,实现让 Service 可以处理耗时任务的功能! AsyncTask 是 Android 中轻量级的异步任务抽象类,它的内部主要由线程池以及 Handler 实现,在线程池中执行耗时任务并把结果通过 Handler 机制中转到主线程以实现UI操作。典型的用法如下: 从 Android3.0 开始,AsyncTask 默认是串行执行的: 如果需要并行执行可以这么做: AsyncTask 的源码不多,还是比较容易理解的。根据上边的用法,可以从 execute() 方法开始我们的分析: 看到 @MainThread 注解了吗?所以 execute() 方法需要在主线程执行哦! 进而又调用了 executeOnExecutor() : 可以看到,当任务正在执行或者已经完成,如果又被执行会抛出异常!回调方法 onPreExecute() 最先被执行了。 传入的 sDefaultExecutor 参数,是一个自定义的串行线程池对象,所有任务在该线程池中排队执行: 可以看到 SerialExecutor 线程池仅用于任务的排队, THREAD_POOL_EXECUTOR 线程池才是用于执行真正的任务,就是我们线程池部分讲到的 ThreadPoolExecutor : 再回到 executeOnExecutor() 方法中,那么 exec.execute(mFuture) 就是触发线程池开始执行任务的操作了。 那 executeOnExecutor() 方法中的 mWorker 是什么? mFuture 是什么?答案在 AsyncTask 的构造函数中: 原来 mWorker 是一个 Callable 对象, mFuture 是一个 FutureTask 对象,继承了 Runnable 接口。所以 mWorker 的 call() 方法会在 mFuture 的 run() 方法中执行,所以 mWorker 的 call() 方法在线程池得到执行! 同时 doInBackground() 方法就在 call() 中方法,所以我们自定义的耗时任务逻辑得到执行,不就是我们第二部分讲的那一套吗! doInBackground() 的返回值会传递给 postResult() 方法: 就是通过 Handler 将最终的耗时任务结果从子线程发送到主线程,具体的过程是这样的, getHandler() 得到的就是 AsyncTask 构造函数中初始化的 mHandler , mHander 又是通过 getMainHandler() 赋值的: 可以在看到 sHandler 是一个 InternalHandler 类对象: 所以 getHandler() 就是在得到在主线程创建的 InternalHandler 对象,所以 就可以完成耗时任务结果从子线程到主线程的切换,进而可以进行相关UI操作了。 当消息是 MESSAGE_POST_RESULT 时,代表任务执行完成, finish() 方法被调用: 如果任务没有被取消的话执行 onPostExecute() ,否则执行 onCancelled() 。 如果消息是 MESSAGE_POST_PROGRESS , onProgressUpdate() 方法被执行,根据之前的用法可以 onProgressUpdate() 的执行需要我们手动调用 publishProgress() 方法,就是通过 Handler 来发送进度数据: 进行中的任务如何取消呢?AsyncTask 提供了一个 cancel(boolean mayInterruptIfRunning) ,参数代表是否中断正在执行的线程任务,但是呢并不靠谱, cancel() 的方法注释中有这么一段: 大致意思就是调用 cancel() 方法后, onCancelled(Object) 回调方法会在 doInBackground() 之后被执行而 onPostExecute() 将不会被执行,同时你应该 doInBackground() 回调方法中通过 isCancelled() 来检查任务是否已取消,进而去终止任务的执行! 所以只能自己动手了: AsyncTask 整体的实现流程就这些了,源码是最好的老师,自己跟着源码走一遍有些问题可能就豁然开朗了!
2023-08-13 05:34:421

Android: 关于Handler的Looper.loop();为什么休眠一段时间后,Handler接收不到消息了。。。求高手

把handleMessage 放到 run里试试new Handler(@Overridepublic boolean handleMessage(Message mGRCMessage) {//...}}
2023-08-13 05:34:511

HandleThread的用法

什么是HandleThread呢? 这个类的作用是创建一个包含looper的线程。 什么时候使用到它呢? 加入在应用程序当中为了实现同时完成多个任务,所以我们会在应用程序当中创建多个线程。为了让多个线程之间能够方便的通信,我们会使用Handler实现线程间的通信。这个时候我们手动实现的多线程+Handler的简化版就是我们HandlerThrea所要做的事了。 HandleThread的基本用法: 首先创建一个HandleThread: HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand"); mHandlerThread.start();//调用run方法 其次: 通过HandleThread的Lopper来创建Handle final Handler mHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { Log.i("tag", "接收到消息:" + msg.obj.toString()); } }; 然后就可以使用了: mHandler.sendMessage(msg); 最后在不需要再用的时候记得手动收回: protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); //quitSafely();可以用这个 } 分析: 可以看出HandleThread的本质其实就是一个Thread.内部自己维护了一个消息队列和一个Looper; 总结: HandlerThread本质上是一个Thread对象,只不过其内部帮我们创建了该线程的Looper和MessageQueue; 通过HandlerThread我们不但可以实现UI线程与子线程的通信同样也可以实现子线程与子线程之间的通信; HandlerThread在不需要使用的时候需要手动的回收掉;
2023-08-13 05:34:581

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 procedure 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(),在内容提供者的进程的线程池中被调用,而不是在这一进程的主线程中。因为这些方法可以同时从任意数量的线程中调用,他们也必须实现为线程安全的。
2023-08-13 05:35:261

android中handle在内部类中为什么不执行

当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。如果外部类是Activity,则会引起Activity泄露 。当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。
2023-08-13 05:35:361

汇编语言 解释一下这个程序 每行的作用意思

这个程序是计算5!DATAS SEGMENT 数据段开始DATA1 DB 1,2,3,4,5 DB型数组DATA1DATAS ENDS 数据段结束CODES SEGMENT 代码段开始ASSUME CS:CODES,DS:DATAS 设置数据段和代码段START: MOV AX,DATAS 取数据段地址 MOV DS ,AX 送数据段地址寄存器 MOV CX ,4 cx为循环次数 MOV SI ,0 si中为DATA1首地址 CLC 清进位标志 MOV AL,DATA1[SI] 取DATA1第一个数据,LOOPER:MOV BL,DATA1[SI+1] 取DATA1后续数据,从第二个开始 MUL BL AL乘以BL,结果保存在AL中 INC SI 下一个数据 DEC CX 循环计数器-1JNZ LOOPER 不为零继续循环 MOV DL,AL 为零,AL结果值送DL MOV AH,2H 输出DL中的结果 INT 21H MOV AH,4CH 退出程序INT 21HCODES ENDS END START若满意请及时采纳,谢谢
2023-08-13 05:35:461

android面试题会出现什么内容

1.android dvm 的进程和Linux的进程,应用程序的进程是否为同一个概念:答:dvm是dalivk虚拟机。每一个android应用程序都在自己的进程中运行,都拥有一个dalivk虚拟机实例。而每一个dvm都是在linux的一个进程。所以说可以认为是同一个概念。2.android的动画有哪几种?他们的特点和区别是什么?答:两种,一种是tween动画,一种是frame动画。tween动画,这种实现方式可以使视图组件移动,放大或缩小以及产生透明度的变化。frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影。3.handler进制的原理:答:android提供了handler和looper来满足线程间的通信。Handler先进先出原则。looper用来管理特定线程内对象之间的消息交换(message Exchange).1)looper:一个线程可以产生一个looper对象,由它来管理此线程里的message queue(消息队列)2)handler:你可以构造一个handler对象来与looper沟通,以便push新消息到messagequeue里;或者接收looper(从messagequeue里取出)所送来的消息。3)messagequeue:用来存放线程放入的消息。4)线程:UI thread 通常就是main thread,而android启动程序时会为它建立一个message queue.4.android view的刷新:答:Android中对View的更新有很多种方式,使用时要区分不同的应用场合。我感觉最要紧的是分清:多线程和双缓冲的使用情况。1).不使用多线程和双缓冲这种情况最简单了,一般只是希望在View发生改变时对UI进行重绘。你只需在Activity中显式地调用View对象中的invalidate()方法即可。系统会自动调用 View的onDraw()方法。2).使用多线程和不使用双缓冲这种情况需要开启新的线程,新开的线程就不好访问View对象了。强行访问的话会报:android.view.ViewRoot$CalledFromWrongThreadException:Only the originalthread that created a view hierarchy can touch its views.这时候你需要创建一个继承了android.os.Handler的子类,并重写handleMessage(Messagemsg)方法。android.os.Handler是能发送和处理消息的,你需要在Activity中发出更新UI的消息,然后再你的Handler(可以使用匿名内部类)中处理消息(因为匿名内部类可以访问父类变量,你可以直接调用View对象中的invalidate()方法 )。也就是说:在新线程创建并发送一个Message,然后再主线程中捕获、处理该消息。3).使用多线程和双缓冲Android中SurfaceView是View的子类,她同时也实现了双缓冲。你可以定义一个她的子类并实现SurfaceHolder.Callback接口。由于实现SurfaceHolder.Callback接口,新线程就不需要android.os.Handler帮忙了。SurfaceHolder中lockCanvas()方法可以锁定画布,绘制玩新的图像后调用unlockCanvasAndPost(canvas)解锁(显示),还是比较方便得。5.说说mvc模式的原理,它在android中的运用:答:android的官方建议应用程序的开发采用mvc模式。何谓mvc?mvc是model,view,controller的缩写,mvc包含三个部分:l模型(model)对象:是应用程序的主体部分,所有的业务逻辑都应该写在该层。2视图(view)对象:是应用程序中负责生成用户界面的部分。也是在整个mvc架构中用户唯一可以看到的一层,接收用户的输入,显示处理结果。3控制器(control)对象:是根据用户的输入,控制用户界面数据显示及更新model对象状态的部分,控制器更重要的一种导航功能,想用用户出发的相关事件,交给m哦得了处理。android鼓励弱耦合和组件的重用,在android中mvc的具体体现如下:1)视图层(view):一般采用xml文件进行界面的描述,使用的时候可以非常方便的引入,当然,如何你对android了解的比较的多了话,就一定 可以想到在android中也可以使用javascript+html等的方式作为view层,当然这里需要进行java和javascript之间的通 信,幸运的是,android提供了它们之间非常方便的通信实现。2)控制层(controller):android的控制层的重 任通常落在了众多的acitvity的肩上,这句话也就暗含了不要在acitivity中写代码,要通过activity交割model业务逻辑层处理, 这样做的另外一个原因是android中的acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。3)模型层(model):对数据库的操作、对网络等的操作都应该在model里面处理,当然对业务计算等操作也是必须放在的该层的。6.Activity的生命周期:答:onCreate: 在这里创建界面,做一些数据 的初始化工作onStart: 到这一步变成用户可见不可交互的onResume:变成和用户可交互 的,(在activity 栈系统通过栈的方式管理这些个Activity的最上面,运行完弹出栈,则回到上一个Activity)onPause: 到这一步是可见但不可交互的,系统会停止动画 等消耗CPU 的事情从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在onstop: 变得不可见,被下一个activity覆盖了onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方法或者是系统为了节省空间将它暂时性的干掉7.让Activity变成一个窗口:答:Activity属性设定:有时候会做个应用程序是漂浮在手机主界面的。这个只需要在设置下Activity的主题theme,即在Manifest.xml定义Activity的地方加一句:android :theme="@android:style/Theme.Dialog"如果是作半透明的效果:android:theme="@android:style/Theme.Translucent"8.Android中常用的五种布局:答:LinearLayout线性布局;AbsoluteLayout绝对布局;TableLayout表格布局;RelativeLayout相对布局;FrameLayout帧布局;9.Android的五种数据存储方式:答:sharedPreferences;文件;SQLite;contentProvider;网络附上出处链接:http://www.51edu.com/it/bckf/36635.html
2023-08-13 05:35:542

ThreadLocal是如何实现保存线程私有对象的

最早知道ThreadLocal是在Looper的源码里,用一个ThreadLocal保存了当前的looper对象。 当时就查了下ThreadLocal,发现是保存线程私有对象的容器,以为就是一个类似hashmap,用线程做key,存value。最近看了下并不是如此,实际上是以ThreadLocal自身为key来存储对象的。于是来学习下ThreadLocal源码是如何做到保存线程私有对象的。 ThreadLocal、ThreadLocalMap、Thread之间的关系和我们下意识中想的不太一样,不过一步步看下去之后就能明白为啥ThreadLocal能保存线程私有对象了。 这个是Thread源码,每一个Thread都有一个ThreadLocalMap对象,而ThreadLocalMap是ThreadLocal的内部类,是实际存储对象的容器。 基本关系知道了,最后再来看看ThreadLocal的方法: 那么现在基本完全清楚ThreadLocal与Thread还有ThreadLocalMap之间的关系了。 每个Thread都有一个成员变量ThreadLocalMap。这个ThreadLocalMap对象不是public,所以外部调用不了,可以看做是线程私有对象。 ThreadLocalMap存了一个table,table里保存了一些entry,每个entry对应一个key和value,而这个key就是ThreadLocal对象。 因此一个ThreadLocal只能存一个value,但是可以通过new多个ThreadLocal来保存多个线程私有对象。 在上面的源码中我们看到Entry里持有的ThreadLocal对象是弱引用持有,因此ThreadLocal不会因为线程持有而泄露,比如我们Android的主线程,正常使用过程中是不会挂掉的。 但是Enrty的value的是强引用的,因此ThreadLocal中的value还是会因为线程持有而无法回收。如果继续看源码的话,会发现在ThreadLocalMap的resize和expungeStaleEntry方法里会检查key为空的value值为空帮助GC。 因此为了避免value内存泄露,我们需要在ThreadLocal不需要的时候主动remove掉。 ThreadLocal通过自身的threadLocalHashCode来碰撞得到自己在ThreadLocalMap的table里的索引i。因此这个threadLocalHashCode就十分重要了。 这里需要保证threadLocalHashCode是唯一的,否则两个线程同时创建ThreadLocal得到相同的hashcode,那就破坏了ThreadLocalMap的线程私有特性了。 这里生成threadLocalHashCode是通过一个静态对象nextHashCode不断增加来获得的。那怎么保证多个进程并发实例化ThreadLocal对象,不会生成相同的hashcode呢? 答案是AtomicInteger,通过这个类来保证变量自增操作在多线程操作时候的原子性。 我们知道Synchronized也可以保证原子性,但相比于它,AtomicInteger类是通过非阻塞方法来实现原子性的,需要的性能开销更小。 这种非阻塞实现原子性的方法和处理器的CAS指令有关,感兴趣的小伙伴自行研究吧~
2023-08-13 05:36:011

Android中的线程怎么获取主线程

使用Looper判断,方法为: Looper.myLooper() != Looper.getMainLooper()使用线程句柄判断,将主线程的Thread.currentThread()获取到主线程当前句柄,保存起来,在需要判断的时候调用Thread.currentThread()来与之比较,即可判断当前线程是否是主线程了
2023-08-13 05:36:091

如何通过运行界面找到printslooper

按win键,在最下面有个搜索栏,输入print spooler上面就会显示出来了。1、开始菜单(或按win键),在最下面有个搜索栏,输入print spooler上面就会显示出来了。如果是要查看print spooler服务是否开启,那么需要单击计算机,管理。服务和应用程序,双击服务。在列表里找到print spooler查看该服务的相关信息。(快捷查找列表可以按下p。列表直接跳到p开头的服务)。服务名称: Spooler显示名称: Print Spooler。服务描述: 管理所有本地和网络打印队列及控制所有打印工作。如果此服务被停用,本地计算机上的打印将不可用。如果此服务被禁用,任何依赖于它的服务将无法启用。拓展资料:Spooler(打印后台处理服务)的进程名是spoolsv.exe,WinXP Home/PRO默认安装的启动类型是自动,依赖于Remote Procedure Call。Spooler是为了提高文件打印效率,将多个请求打印的文档统一进行保存和管理,先将要打印的文件拷贝到内存,待打印机空闲后,再将数据送往打印机处理。这样处理速度更快些。建议将其设置为手动,有打印任务时再打开。如果没有打印机自然是禁用了。它和office2007的PowerPoint有关,如果把它关掉,那么PowerPoint无法在快速访问工具栏中添加快捷按钮,在打开“PowerPoint选项”的时候也会提示“无法找到打印机”这类的问题。
2023-08-13 05:36:301

什么是效果器

摘要:效果器是专用于产生各种效果的电子仪器,效果器有什么用呢?效果器的作用是改变原有声音的波形,调制或延迟声波的相位、增强声波的谐波成分等一系列措施,产生各种特殊声效。许多乐器、合唱等都会使用效果器,下面一起来详细了解一下什么是效果器以及效果器的作用吧。什么是效果器效果器是一种可以令电子乐器或音讯的音色加以修饰的电子器材。效果器之于电吉他系统,类似滤镜之于照相机,或是酱油之于红烧排骨。拍照的时候,滤镜没法让云彩变成大象,但能让他更好看;做菜的时候,酱油没法让排骨变成鸡腿,但能让他更好吃。吉他和音箱作为音色的主要来源,决定了声音的基本特质,效果器则使其更加丰富多变的形式呈现出来。效果器的作用是什么效果器是提供各种声场效果的音响周边器材。原先主要用于录音棚和电影伴音效果的制作,现在已广泛应用现场扩声系统。无论效果器的品质如何优秀,如果不能掌握其调整技巧,不但无法获得预期的音响效果,而且还会破坏整个系统的音质。效果器的基本效果类型有声场效果、特殊效果和声源效果三大类。数字效果一般都储存有几十种或数百种效果类型,有的效果器还有参数均衡、噪声门、激励器和压缩/限幅某功能。使用者可根据自己的需要选择相应的效果类型。效果器的种类有哪些1、如果按结构来分类,效果器有:①机架式效果器,因为售价、体积、使用方式等问题,并不是大众的最佳选择。②踏板式效果器,大家对“效果器”的第一反应往往是这个,不光我们在用,大师也在用。按照功能的多寡还能再分为单块效果器和综合效果器,这两者之间的关系类似于纯手动的定焦镜头和带自动对焦马达的变焦镜头。③软件式效果器,没有必要贬低软件效果器,毕竟科技在进步,有人拍照喜欢镜头前装滤镜,有人就喜欢回家用lightroom调,具体选哪种跟经济条件、使用场景、使用习惯有很大关系。现在很多音箱自带一些周边效果,可以看作是内置了效果器。2、如果按对信号的处理方式,效果器有:削波类(失真、过载等),滤波类(压缩、哇音等),调制类(颤音、合唱等),复制类(延迟、混响等)。在此基础上按功能细分,就是我们通常直观能见的效果器种类了:(1)过载overdrive失真distortion法兹fuzz(2)压缩compression哇音wah均衡equalize(3)合唱chorus颤音tremolo(改变音量)&vibrato(改变音高)相位phaser镶边flanger噪音门noisegate(4)延迟delay混响reverb循环looper
2023-08-13 05:36:391

有一种类似多轨录音机的设备,可以现场用脚踩来切换录音并混响的,以前在视频网上看一个女的用一把吉他加敲

效果器淘宝和一些琴行都有卖
2023-08-13 05:36:514

MediaRecorder: stop failed :-1007 在录音停止的时候报的这个错误 是什么意思?

向软件开发者咨询最直接,看这段运行时错误提示很难猜测确凿原因。到软件的“关于”里或许能找到开发者的邮箱地址。
2023-08-13 05:37:002

Handler.post()问题

子线程中不能用操作主线程,你looper准备后还需要在队列最后调用looper.loop()才行,最好的方法是你new handler的时候给handler的参数用looper.getMainlooper()就好了
2023-08-13 05:37:141

奇特:子线程的Toast怎么显示不出来?

晕,在子线程不能操作任何组件,你调用activity方法里面的runOnUIThread()就可以toast了
2023-08-13 05:37:452

如何关闭android中的HandlerThread

android 中的HandlerThread包含了android中的消息处理机制必须的looper,当你启动这个线程的时候,就会闯进looper,并开启消息处理的循环。跟其它线程一样,HandlerThread是可不可以直接stop掉的,不过经过本人测试,你可以调用:getLooper().quit();来退出这个线程,其实原理很简单,就是改变在消息循环里面标志位,退出整个while循环,使线程执行完毕。 部分 测试代码如下:public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);tv_name = (TextView) findViewById(R.id.tv_name);btn_name = (Button) findViewById(R.id.btn_name);Log.i(TAG, "==================main thread:" + Thread.currentThread().getName());final HandlerThread thread = new HandlerThread("handlerThread");thread.start();final MyHandler handler = new MyHandler(thread.getLooper());btn_name.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {handler.sendEmptyMessage(1);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}thread.getLooper().quit();}});}class MyHandler extends Handler {public MyHandler(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {Log.i(TAG, "==================" + Thread.currentThread().getName());//tv_name.setText("hello, this is the first message from handler");不过要注意:要想更新界面内容,还是需要使用界面的Looper,不然的话还是会抛错误,还是那句话,所有跟改变界关的操作,都得通过界面的Looper来执行
2023-08-13 05:38:011

很不错 英文?

amazing
2023-08-13 05:26:503

电子烟品烟师对身体有害吗

有。电子烟的原理是将尼古丁和焦油成分通过电子进行加热,加热后再进行吸服,此时会减少肺泡、肺壁毛细血管或者肺黏膜的损伤,因此会减少肺癌的罹患率。但是减轻肺癌的发病率并不代表电子烟没有毒,通常电子烟的毒性表现为加热后的焦油成分对于心血管内皮细胞有一定的损伤和糜烂,因此尤其对于既往存在冠状动脉粥样硬化性心脏病或者心肌梗塞患者,不能过量吸电子烟,此时会对心血管甚至脑血管造成毒害。
2023-08-13 05:26:502

如烟 电子烟的原理是什么?

电子烟的工作原理主要是配套的“烟弹”(也称“烟芯”)里的烟碱溶液(如烟与全球最大的化工企业陶氏化工合作研发生产),经超微泵加压后进入雾化室,再由2.2MHZ频率的超声波高压雾化成直径0.5—1.5um左右的水雾滴。 内置芯片中有气流传感器,该器械只有通过嘴吸气的方式将极少量的烟液吸入肺中,从而使烟液在肺中被吸收。 如烟科技根据个体差异,将吸入的烟液量设置成不同的规格,以适应不同人群的需求。目前如烟按照国际惯例,将烟碱含量分为形成16毫克高含量版、11毫克低含量版、0毫克无含量版三种。
2023-08-13 05:26:431

美剧《犯罪现场调查》(CSI)中Sofia的去向?

没有介绍她离去的原因就是直接新的一季开始后这个角色就去掉了我看的时候也挺郁闷
2023-08-13 05:26:422