当前位置:首页 » 安卓系统 » android线程looper

android线程looper

发布时间: 2022-09-24 03:23:49

A. 为什么Android系统会给程序的主线程自动添加Looper

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

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

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。

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

实际上:消息发送和计划任务提交之后,它们都会进入某线程的消息队列中,我们可以把这个线程称之为目标线程。不论是主线程还是子线程都可以成为目标线程。上例中之所以在主线程中处理消息,是因为我们要更新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
plainprint?

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
plainprint?

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

D. Android多线程的四种方式:Handler、AsyncTask、ThreadPoolExector、IntentService

     异步通信机制,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理。Handler不仅仅能将子线程的数据传递给主线程,它能实现任意两个线程的数据传递。

(1)Message

    Message 可以在线程之间传递消息。可以在它的内部携带少量数据,用于在不同线程之间进行数据交换。除了 what 字段,还可以使用 arg1 和 arg2 来携带整型数据,使用 obj 来携带 Object 数据。

(2) Handler

    Handler 作为处理中心,用于发送(sendMessage 系列方法)与处理消息(handleMessage 方法)。

(3) MessageQueue

    MessageQueue 用于存放所有通过 Handler 发送的消息。这部分消息会一直存放在消息队列中,直到被处理。每个线程中只会有一个 MessageQueue 对象

(4) Looper

    Looper 用于管理 MessageQueue 队列,Looper对象通过loop()方法开启了一个死循环——for (;;){},不断地从looper内的MessageQueue中取出Message,并传递到 Handler 的 handleMessage() 方法中。每个线程中只会有一个 Looper 对象。

    AsyncTask 是一种轻量级的任务异步类,可以在后台子线程执行任务,且将执行进度及执行结果传递给 UI 线程。

(1)onPreExecute()

    在 UI 线程上工作,在任务执行 doInBackground() 之前调用。此步骤通常用于设置任务,例如在用户界面中显示进度条。

(2)doInBackground(Params... params)

    在子线程中工作,在 onPreExecute() 方法结束后执行,这一步被用于在后台执行长时间的任务,Params 参数通过 execute(Params) 方法被传递到此方法中。任务执行结束后,将结果传递给 onPostExecute(Result) 方法,同时我们可以通过 publishProgress(Progress) 方法,将执行进度发送给 onProgressUpdate(Progress) 方法。

(3)onProgressUpdate(Progress... values)

    在 UI 线程上工作,会在 doInBackground() 中调用 publishProgress(Progress) 方法后执行,此方法用于在后台计算仍在执行时(也就是 doInBackgound() 还在执行时)将计算执行进度通过 UI 显示出来。例如,可以通过动画进度条或显示文本字段中的日志,从而方便用户知道后台任务执行的进度。

(4)onPostExecute(Result result)

    在 UI 线程上工作,在任务执行完毕(即 doInBackground(Result) 执行完毕)并将执行结果传过来的时候工作。

使用规则:

(1)AsyncTask 是个抽象类,所以要创建它的子类实现抽象方法

(1)AsyncTask 类必须是在 UI 线程中被加载,但在Android 4.1(API 16)开始,就能被自动加载完成。

(2)AsyncTask 类的实例对象必须在 UI 线程中被创建。

(3)execute() 方法必须是在 UI 线程中被调用。

(4)不要手动调用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()

(5)任务只能执行一次(如果尝试第二次执行,将抛出异常)。即一个AsyncTask对象只能调用一次execute()方法。

原理:

          其源码中原理还是 Thread 与 Handler 的实现,其包含 两个线程池,一个 Handler,如下所示:

名称类型作用

SERIAL_EXECUTOR线程池分发任务,串行分发,一次只分发一个任务

THREAD_POOL_EXECUTOR线程池执行任务,并行执行,执行的任务由 SERIAL_EXECUTOR 分发

InternalHandlerHandler负责子线程与主线程的沟通,通知主线程做 UI 工作

    一方面减少了每个并行任务独自建立线程的开销,另一方面可以管理多个并发线程的公共资源,从而提高了多线程的效率。所以ThreadPoolExecutor比较适合一组任务的执行。Executors利用工厂模式对ThreadPoolExecutor进行了封装。

Executors提供了四种创建ExecutorService的方法,他们的使用场景如下:

1. Executors.newFixedThreadPool()

    创建一个定长的线程池,每提交一个任务就创建一个线程,直到达到池的最大长度,这时线程池会保持长度不再变化。

当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。

只有核心线程并且不会被回收,能够更加快速的响应外界的请求。

2. Executors.newCachedThreadPool()

    创建一个可缓存的线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程,当需要增加时,它可以灵活的添加新的线程,而不会对池的长度作任何限制

    线程数量不定的线程池,只有非核心线程,最大线程数为 Integer.MAX_VALUE。当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则利用空闲的线程来处理新任务。线程池中的空闲线程具有超时机制,为 60s。

    任务队列相当于一个空集合,导致任何任务都会立即被执行,适合执行大量耗时较少的任务。当整个线程池都处于限制状态时,线程池中的线程都会超时而被停止。

3. Executors.newScheledThreadPool()

    创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。

    非核心线程数没有限制,并且非核心线程闲置的时候立即回收,主要用于执行定时任务和具有固定周期的重复任务。

4. Executors.newSingleThreadExecutor()

    创建一个单线程化的executor,它只创建唯一的worker线程来执行任务

    只有一个核心线程,保证所有的任务都在一个线程中顺序执行,意义在于不需要处理线程同步的问题。

    一般用于执行后台耗时任务,当任务执行完成会自动停止;同时由于它是一个服务,优先级要远远高于线程,更不容易被系统杀死,因此比较适合执行一些高优先级的后台任务。

使用步骤:创建IntentService的子类,重写onHandleIntent方法,在onHandleIntent中执行耗时任务

    原理:在源码实现上,IntentService封装了HandlerThread和Handler。onHandleIntent方法结束后会调用IntentService的stopSelf(int startId)方法尝试停止服务。

    IntentService的内部是通过消息的方式请求HandlerThread执行任务,HandlerThread内部又是一种使用Handler的Thread,这就意味着IntentService和Looper一样是顺序执行后台任务的

(HandlerThread:封装了Handler + ThreadHandlerThread适合在有需要一个工作线程(非UI线程)+任务的等待队列的形式,优点是不会有堵塞,减少了对性能的消耗,缺点是不能同时进行多个任务的处理,需要等待进行处理。处理效率低,可以当成一个轻量级的线程池来用)

E. Android如何保证一个线程最多只能有一个Looper

Looper的构造方法为private,所以不能直接使用其构造方法创建。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}1234

要想在当前线程创建Looper,需使用Looper的prepare方法,Looper.prepare()。
如果现在要我们来实现Looper.prepare()这个方法,我们该怎么做?我们知道,Android中一个线程最多只能有一个Looper,若在已有Looper的线程中调用Looper.prepare()会抛出RuntimeException(“Only one Looper may be created per thread”)。面对这样的需求,我们可能会考虑使用一个HashMap,其中Key为线程ID,Value为与线程关联的Looper,再加上一些同步机制,实现Looper.prepare()这个方法,代码如下:

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

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

G. android线程间通信有哪些方式

进程:是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
  线程:是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一些在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
  区别:
  (1)、一个程序至少有一个进程,一个进程至少有一个线程;
  (2)、线程的划分尺度小于进程,使得多线程程序的并发性高;
  (3)、进程在执行过程中拥有独立的内存单元,而多个线程共享内存,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉。
---------------------
一、Android进程间通信方式
1.Bundle
  由于Activity,Service,Receiver都是可以通过Intent来携带Bundle传输数据的,所以我们可以在一个进程中通过Intent将携带数据的Bundle发送到另一个进程的组件。
  缺点:无法传输Bundle不支持的数据类型。
2.ContentProvider
  ContentProvider是Android四大组件之一,以表格的方式来储存数据,提供给外界,即Content Provider可以跨进程访问其他应用程序中的数据。用法是继承ContentProvider,实现onCreate,query,update,insert,delete和getType方法,onCreate是负责创建时做一些初始化的工作,增删查改的方法就是对数据的查询和修改,getType是返回一个String,表示Uri请求的类型。注册完后就可以使用ContentResolver去请求指定的Uri。
3.文件
  两个进程可以到同一个文件去交换数据,我们不仅可以保存文本文件,还可以将对象持久化到文件,从另一个文件恢复。要注意的是,当并发读/写时可能会出现并发的问题。
4.Broadcast
  Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播。
5.AIDL方式
  Service和Content Provider类似,也可以访问其他应用程序中的数据,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。
6.Messenger
  Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。
  双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。
7.Socket
  Socket方法是通过网络来进行数据交换,注意的是要在子线程请求,不然会堵塞主线程。客户端和服务端建立连接之后即可不断传输数据,比较适合实时的数据传输
二、Android线程间通信方式
  一般说线程间通信主要是指主线程(也叫UI线程)和子线程之间的通信,主要有以下两种方式:
1.AsyncTask机制
  AsyncTask,异步任务,也就是说在UI线程运行的时候,可以在后台的执行一些异步的操作;AsyncTask可以很容易且正确地使用UI线程,AsyncTask允许进行后台操作,并在不显示使用工作线程或Handler机制的情况下,将结果反馈给UI线程。但是AsyncTask只能用于短时间的操作(最多几秒就应该结束的操作),如果需要长时间运行在后台,就不适合使用AsyncTask了,只能去使用Java提供的其他API来实现。
2.Handler机制
  Handler,继承自Object类,用来发送和处理Message对象或Runnable对象;Handler在创建时会与当前所在的线程的Looper对象相关联(如果当前线程的Looper为空或不存在,则会抛出异常,此时需要在线程中主动调用Looper.prepare()来创建一个Looper对象)。使用Handler的主要作用就是在后面的过程中发送和处理Message对象和让其他的线程完成某一个动作(如在工作线程中通过Handler对象发送一个Message对象,让UI线程进行UI的更新,然后UI线程就会在MessageQueue中得到这个Message对象(取出Message对象是由其相关联的Looper对象完成的),并作出相应的响应)。
三、Android两个子线程之间通信
  面试的过程中,有些面试官可能会问Android子线程之间的通信方式,由于绝大部分程序员主要关注的是Android主线程和子线程之间的通信,所以这个问题很容易让人懵逼。
  主线程和子线程之间的通信可以通过主线程中的handler把子线程中的message发给主线程中的looper,或者,主线程中的handler通过post向looper中发送一个runnable。但looper默认存在于main线程中,子线程中没有Looper,该怎么办呢?其实原理很简单,把looper绑定到子线程中,并且创建一个handler。在另一个线程中通过这个handler发送消息,就可以实现子线程之间的通信了。
  子线程创建handler的两种方式:
  方式一:给子线程创建Looper对象:
new Thread(new Runnable() {
public void run() {
Looper.prepare(); // 给这个Thread创建Looper对象,一个Thead只有一个Looper对象
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop(); // 不断遍历MessageQueue中是否有消息
};
}).start();
---------------------
方式二:获取主线程的looper,或者说是UI线程的looper:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 区别在这!!!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();

H. android 关于线程looper问题。。。急!!!错误问题如下。。

我的猜想是:你的线程是在另外的一个类里,而android不允许其它线程更新Activity,
解决方法:在线程的run()方法里开头加上Looper.prepare(),末尾加上Looper.loop();
本人也刚开始学习android,具体原理还不清楚。

I. 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的匿名内部类,这种情况下,由于不是在新的线程中使用,所以千万别做复杂的计算逻辑。

J. 为什么Android系统会给程序的主线程自动添加Looper

Android 在进程的入口函数 ActivityThread.main()中,调用 Looper.prepareMainLooper, 为应用的主线程创建Looper,然后调用Looper.loop()就启动了进程的消息循环,然后就可以处理消息了。

ActivityThread源码:

151 public final class ActivityThread {

2202 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
2253 if (activity != null) {
2259 activity.attach(appContext, this, ..., );

5219 public static void main(String[] args) {
// 在这儿调用 Looper.prepareMainLooper, 为应用的主线程创建Looper
5240 Looper.prepareMainLooper();
5242 ActivityThread thread = new ActivityThread();
5245 if (sMainThreadHandler == null) {
5246 sMainThreadHandler = thread.getHandler();
5247 }
5254 Looper.loop();
5257 }
5258}
Looper源码:

52 public final class Looper {
// Initialize the current thread as a looper, marking it as an application's main looper.
// The main looper for your application is created by the Android environment,
// so you should never need to call this function yourself. See also: prepare()
87 public static void prepareMainLooper() {
88 prepare(false);
89 synchronized (Looper.class) {
90 if (sMainLooper != null) {
91 throw new IllegalStateException("The main Looper has already been prepared.");
92 }
93 sMainLooper = myLooper();
94 }
95 }
Activity源码:

660 public class Activity extends ContextThemeWrapper {
699 /*package*/ ActivityThread mMainThread;

5922 final void attach(Context context, ActivityThread aThread, ..., ) {
5944 mMainThread = aThread;

热点内容
ea编程入门 发布:2025-01-15 13:30:11 浏览:411
应缴费档次配置异常怎么回事 发布:2025-01-15 13:20:34 浏览:617
成都php招聘 发布:2025-01-15 13:12:16 浏览:380
怎么调用服务器数据库 发布:2025-01-15 13:06:25 浏览:656
人人网设置访问权限 发布:2025-01-15 13:02:06 浏览:563
崩坏学园2脚本 发布:2025-01-15 12:58:43 浏览:459
我的世界服务器等级如何升 发布:2025-01-15 12:45:55 浏览:689
c语言程序填空题 发布:2025-01-15 12:45:53 浏览:545
怎么配置氯化钠浓度 发布:2025-01-15 12:34:06 浏览:206
4000除以125简便算法 发布:2025-01-15 12:27:41 浏览:464