當前位置:首頁 » 安卓系統 » android線程循環

android線程循環

發布時間: 2023-08-24 13:12:26

『壹』 Android-Handle(線程間通信)詳解

線程間通信是在Android開發中比較經常遇到的,我們刷新UI界面一般是通過子線程做完某些事情後,要改變主頁面就要通過數據的通信,讓主線程接收到信息後自己改變UI界面。

1. Handle 先進先出原則;
2. Looper 類用來管理特定線程內對象之間的消息交換(MessageExchange);
3. Message 類用來保存數據。

1.Looper: 一個線程可以產生一個Looper對象,由它來管理此線程里的MessageQueue(消息隊列);
2.Handler: 你可以構造Handler對象來與Looper溝通,以便push新消息到MessageQueue里;或者接收Looper從Message Queue取出)所送來的消息;

android.os.Message的主要功能是進行消息的封裝,同時可以指定消息的操作形式,Message類定義的變數和常用方法如下:

在整個消息處理機制中,message又叫task,封裝了任務攜帶的信息和處理該任務的handler。message的用法比較簡單,但是有這么幾點需要注意:

在使用Handler處理Message時,需要Looper(通道)來完成。在一個Activity中,系統會自動幫用戶啟動Looper對象,而在一個用戶自定義的類中,則需要用戶手工調用Looper類中的方法,然後才可以正常啟動Looper對象。Looper的字面意思是「循環者」,它被設計用來使一個普通線程變成Looper線程。所謂Looper線程就是循環工作的線程。在程序開發中(尤其是GUI開發中),我們經常會需要一個線程不斷循環,一旦有新任務則執行,執行完繼續等待下一個任務,這就是Looper線程。使用Looper類創建Looper線程很簡單:

這是在子線程中創建Handler的情況,如果在主線程中創建Handler是不需要調用 Looper.prepare(); 和 Looper.loop(); 方法。

Handler是更新UI界面的機制,也是消息處理的機制。我們可以通過Handle發送消息,也可以處理消息。

Android在設計的時候,封裝了一套消息創建、傳遞、處理機制,如果不遵循這樣的機制就沒有辦法更新UI信息,就會拋出異常。
創建Handler實例化對象時,可以重寫的回調方法:

『貳』 Android Handle中Looper.loop()的死循環為什麼在主線程中不會產生卡死現象

1. 主線程,負責一些UI更新操作,歸類為一個線程,線程在Android中是有生命周期的,任務最終是會結束的。
2. Looper.loop()的死循環正是維護了主線程的超長生命周期,loop方法一直循環處理任務,沒有任務的時候會休眠,有任務的時候會喚醒然後進行處理,所以也不會佔用太多系統資源。
3. 卡死,可能有誤解,循環的過程中本生不會出現ANR,在循環的過程中,如果執行了耗時且在規定時間內沒有完成消息派發,才會出現ANR。

『叄』 Android中的線程和線程池

一、除了Thread外,扮演線程角色的還有:AsyncTask和IntentService,同時HandlerThread也扮演特殊的線程。

      IntentService:內部採用HandlerThread來執行,像一個後台線程,同時是一個服務,不容易被系統殺死。

二、HandlerThread的run方法是一個無限循環

三、IntentService中任務是排隊執行的

四、AsyncTask 

1、Android1.6之前串悄段桐行執行任務,1.6時候採用線程池裡的並行,Android3.0開始又開始串列(為了避免並發錯誤),單任可以並行。

2、AsyncTask必須在UI線程調用(不過這個不是絕對的,和版本有關燃腔系,API 16之前,API 16到 22, API 22以後) 參考一

原因:內部有靜態Handler,採用UI線程的Looper來處理消息,這就是為什麼AsyncTask必須在UI線程調用,因為子線程默認沒有Looper無法創建下面的Handler,程序會直接Crash

3、AsyncTask中有兩個線程池和一個Handler,一個線程池用啟坦於任務排隊,一個線程池用於真正的執行任務,InternalHandler用於將

執行環境從線程池切換到主線程

AsyncTask串列與並行

五、線程池

線程池中多餘的線程是如何回收的

『肆』 Android在子線程用handler發送的消息,主線程是怎麼loop到的

因為你是在主線程創建的handler實例,比如你是這樣實例化handler
那麼我們進到handler源碼看一下
可以看到這里會調用重載的另外一個構造方法,我們再跟進
我們可以看到
mLooper=looper.myLooper();
這是獲取當前線程的looper實例,也就是主線程的looper。所以當發送消息的時候主線程就可以獲取到消息。往下看系統還會mLooper是否為空,如果為空就會拋出異常,意思是當前線程沒有looper實例,這也是我們在子線程中沒有創建looper的實例的時候創建handler會報錯的原因,主線程不會報錯是因為程序在啟動的時候在activitythread中的main方法就創建了looper實例,看系統源碼
然後調用looper.loop();就開始了消息循環。這就是為什麼在主線程發消息住線程還能收到消息的原因。因為發送消息的實例是在主線程實例化的就有了主線程的looper。

『伍』 Android線程池ThreadPoolExecutor詳解

       傳統的多線程是通過繼承Thread類及實現Runnable介面來實現的,每次創建及銷毀線程都會消耗資源、響應速度慢,且線程缺乏統一管理,容易出現阻塞的情況,針對以上缺點,線程池就出現了。

       線程池是一個創建使用線程並能保存使用過的線程以達到復用的對象,簡單的說就是一塊緩存了一定數量線程的區域。

       1.復用線程:線程執行完不會立刻退出,繼續執行其他線程;
       2.管理線程:統一分配、管理、控制最大並發數;

       1.降低因頻繁創建&銷毀線程帶來的性能開銷,復用緩存在線程池中的線程;
       2.提高線程執行效率&響應速度,復用線程:響應速度;管理線程:優化線程執行順序,避免大量線程搶占資源導致阻塞現象;
       3.提高對線程的管理度;

       線程池的使用也比較簡單,流程如下:

       接下來通過源碼來介紹一下ThreadPoolExecutor內部實現及工作原理。

       線程池的最終實現類是ThreadPoolExecutor,通過實現可以一步一步的看到,父介面為Executor:

       其他的繼承及實現關系就不一一列舉了,直接通過以下圖來看一下:

       從構造方法開始看:

       通過以上可以看到,在創建ThreadPoolExecutor時,對傳入的參數是有要求的:corePoolSize不能小於0;maximumPoolSize需要大於0,且需要大於等於corePoolSize;keepAliveTime大於0;workQueue、threadFactory都不能為null。
       在創建完後就需要執行Runnable了,看以下execute()方法:

       在execute()內部主要執行的邏輯如下:
       分析點1:如果當前線程數未超過核心線程數,則將runnable作為參數執行addWorker(),true表示核心線程,false表示非核心線程;
       分析點2:核心線程滿了,如果線程池處於運行狀態則往workQueue隊列中添加任務,接下來判斷是否需要拒絕或者執行addWorker();
       分析點3:以上都不滿足時 [corePoolSize=0且沒有運行的線程,或workQueue已經滿了] ,執行addWorker()添加runnable,失敗則執行拒絕策略;
        總結一下:線程池對線程創建的管理,流程圖如下:

       在執行addWorker時,主要做了以下兩件事:
       分析點1:將runnable作為參數創建Worker對象w,然後獲取w內部的變數thread;
       分析點2:調用start()來啟動thread;
       在addWorker()內部會將runnable作為參數傳給Worker,然後從Worker內部讀取變數thread,看一下Worker類的實現:

       Worker實現了Runnable介面,在Worker內部,進行了賦值及創建操作,先將execute()時傳入的runnable賦值給內部變數firstTask,然後通過ThreadFactory.newThread(this)創建Thread,上面講到在addWorker內部執行t.start()後,會執行到Worker內部的run()方法,接著會執行runWorker(this),一起看一下:

       前面可以看到,runWorker是執行在子線程內部,主要執行了三件事:
       分析1:獲取當前線程,當執行shutdown()時需要將線程interrupt(),接下來從Worker內部取到firstTask,即execute傳入的runnable,接下來會執行;
       分析2:while循環,task不空直接執行;否則執行getTask()去獲取,不為空直接執行;
       分析3:對有效的task執行run(),由於是在子線程中執行,因此直接run()即可,不需要start();
       前面看到,在while內部有執行getTask(),一起看一下:

       getTask()是從workQueue內部獲取接下來需要執行的runnable,內部主要做了兩件事:
       分析1:先獲取到當前正在執行工作的線程數量wc,通過判斷allowCoreThreadTimeOut[在創建ThreadPoolExecutor時可以進行設置]及wc > corePoolSize來確定timed值;
       分析2:通過timed值來決定執行poll()或者take(),如果WorkQueue中有未執行的線程時,兩者作用是相同的,立刻返回線程;如果WorkQueue中沒有線程時,poll()有超時返回,take()會一直阻塞;如果allowCoreThreadTimeOut為true,則核心線程在超時時間沒有使用的話,是需要退出的;wc > corePoolSize時,非核心線程在超時時間沒有使用的話,是需要退出的;
       allowCoreThreadTimeOut是可以通過以下方式進行設置的:

       如果沒有進行設置,那麼corePoolSize數量的核心線程會一直存在。
        總結一下:ThreadPoolExecutor內部的核心線程如何確保一直存在,不退出?
       上面分析已經回答了這個問題,每個線程在執行時會執行runWorker(),而在runWorker()內部有while()循環會判斷getTask(),在getTask()內部會對當前執行的線程數量及allowCoreThreadTimeOut進行實時判斷,如果工作數量大於corePoolSize且workQueue中沒有未執行的線程時,會執行poll()超時退出;如果工作數量不大於corePoolSize且workQueue中沒有未執行的線程時,會執行take()進行阻塞,確保有corePoolSize數量的線程阻塞在runWorker()內部的while()循環不退出。
       如果需要關閉線程池,需要如何操作呢,看一下shutdown()方法:

       以上可以看到,關閉線程池的原理:a. 遍歷線程池中的所有工作線程;b. 逐個調用線程的interrupt()中斷線程(註:無法響應中斷的任務可能永遠無法終止)
       也可調用shutdownNow()來關閉線程池,二者區別:
       shutdown():設置線程池的狀態為SHUTDOWN,然後中斷所有沒有正在執行任務的線程;
       shutdownNow():設置線程池的狀態為STOP,然後嘗試停止所有的正在執行或暫停任務的線程,並返回等待執行任務的列表;
       使用建議:一般調用shutdown()關閉線程池;若任務不一定要執行完,則調用shutdownNow();
        總結一下:ThreadPoolExecutor在執行execute()及shutdown()時的調用關系,流程圖如下:

       線程池可以通過Executors來進行不同類型的創建,具體分為四種不同的類型,如下:

       可緩存線程池:不固定線程數量,且支持最大為Integer.MAX_VALUE的線程數量:

       1、線程數無限制
       2、有空閑線程則復用空閑線程,若無空閑線程則新建線程
       3、一定程度上減少頻繁創建/銷毀線程,減少系統開銷

       固定線程數量的線程池:定長線程池

       1、可控制線程最大並發數(同時執行的線程數)
       2、超出的線程會在隊列中等待。

       單線程化的線程池:可以理解為線程數量為1的FixedThreadPool

       1、有且僅有一個工作線程執行任務
       2、所有任務按照指定順序執行,即遵循隊列的入隊出隊規則

       定時以指定周期循環執行任務

       一般來說,等待隊列 BlockingQueue 有: ArrayBlockingQueue 、 LinkedBlockingQueue 與 SynchronousQueue 。
       假設向線程池提交任務時,核心線程都被佔用的情況下:
        ArrayBlockingQueue :基於數組的阻塞隊列,初始化需要指定固定大小。
       當使用此隊列時,向線程池提交任務,會首先加入到等待隊列中,當等待隊列滿了之後,再次提交任務,嘗試加入隊列就會失敗,這時就會檢查如果當前線程池中的線程數未達到最大線程,則會新建線程執行新提交的任務。所以最終可能出現後提交的任務先執行,而先提交的任務一直在等待。
        LinkedBlockingQueue :基於鏈表實現的阻塞隊列,初始化可以指定大小,也可以不指定。
       當指定大小後,行為就和 ArrayBlockingQueue一致。而如果未指定大小,則會使用默認的 Integer.MAX_VALUE 作為隊列大小。這時候就會出現線程池的最大線程數參數無用,因為無論如何,向線程池提交任務加入等待隊列都會成功。最終意味著所有任務都是在核心線程執行。如果核心線程一直被占,那就一直等待。
        SynchronousQueue :無容量的隊列。
       使用此隊列意味著希望獲得最大並發量。因為無論如何,向線程池提交任務,往隊列提交任務都會失敗。而失敗後如果沒有空閑的非核心線程,就會檢查如果當前線程池中的線程數未達到最大線程,則會新建線程執行新提交的任務。完全沒有任何等待,唯一制約它的就是最大線程數的個數。因此一般配合Integer.MAX_VALUE就實現了真正的無等待。
       但是需要注意的是, 進程的內存是存在限制的,而每一個線程都需要分配一定的內存。所以線程並不能無限個。

『陸』 Android中的線程池

 線程池的好處

1、重用線程池中的線程,避免線程的創建與銷毀帶來的性能開銷

2、能有效控制線程池的最大並發數,避免大量線程因搶占資源而導致的阻塞

3、能對線程進行簡單的管理,提供定時或者指定間隔時間、循環執行等操作

線程池的概率來自於java的Executor介面,實現類是ThreadPoolExecutor, 它提供一系列的參數來配置線程池,以此構建不同的線程池。Android的線程池分4類,都是通過Executors所提供的工廠方法來得到。

ThreadPoolExecutor有四個構造函數,下面這個是最常用的

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnnable> workQueue, ThreadFactory threadFactory)

corePoolSize

線程池中的核心線程數,默認情況下核心線程會在線程池中一直存活,即使他們處於閑置狀態。如果設置ThreadPoolExecutor 中的allowCoreThreadTimeOut = true, 核心線程在等待新任務到來時有超時機制,時間超過keepAliveTime所指定的時間後,核心線程會終止。

maximumPoolSize

最大線程數

keepAliveTime

非核心線程閑置的超時時間,超過這個時間,非核心線程會被回收。核心線程則要看allowCoreThreadTimeOut屬性的值。

unit

時間單位

workQueue

線程池中的工作隊列

threadFactory

線程工廠,為線程池提供創建新線程的功能。

舉個例子,我們常用的okhttp內部也是使用了線程池,它的ThreadPoolExecutor主要是定義在Dispatcher類裡面。 使用的是CachedThreadPool。

executorService = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS, SynchronousQueue(), ThreadFactory("okhttp Dispatcher", false))

1、FixedThreadPool

通過Executors的newFixedThreadPool()創建,這是一個線程數量固定的線程池,裡面所有的線程都是核心線程。

public static ExecutorService newFixedThreadPool(int nThreads){

return new ThreadPoolExecutor(nThreads, nThreads, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

}

2、CachedThreadPool

通過Executors的newCacheThreadPool()創建,這是一個線程數量不定的線程池,裡面所有的線程都是非核心線程。最大線程數是無限大,當線程池中的線程都處於活動狀態時,新的task會創建新的線程來處理,否則就使用空閑的線程處理,所有的線程都是60s的超時時間,超時後會自動回收。

public static ExecutorService newFixedThreadPool(){

return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())

}

3、ScheledThreadPool

通過Executors的newScheledThreadPool()創建, 核心線程固定,非核心線程無限大,當非核心線程空閑時,會立即被回收。適合做定時任務或者固定周期的重復任務。

public static ExecutorService newScheledThreadPool(int corePoolSize){

return new ThreadPoolExecutor(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.SECONDS, new DelayedWorkQueue())

}

4、SingleThreadExcecutor

通過Executors的newSingleThreadPool()創建,內部只有一個核心線程。

public static ExecutorService newFixedThreadPool(){

return new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())

}

課外知識:LinkedBlockingQueue

LinkedBlockingQueue是由鏈表組成的阻塞隊列,內部head 指向隊列第一個元素,last指向最後一個元素。入隊和出隊都會加鎖阻塞,都是使用了不同的鎖。

DelayedWorkQueue

延時隊列,隊內元素必須是Delayed的實現類。對內元素會按照Delayed時間進行排序,對內元素只有在delayed時間過期了才能出隊。

入隊的時候不阻塞隊列,出隊的時候,如果隊列為空或者隊列里所有元素都等待時間都沒有到期,則該線程進入阻塞狀態。

『柒』 安卓開發線程和進程講解


本教程為大家介紹安卓開發中的線程和進程,安卓平台中當首次啟動運行一個組件的時候,Android會相應的啟動了一個進程。默認的,所有的組件和程序運行在這個進程和線程中,也可以安排組件在其他的進程或者線程中運行。
進程:組件運行的進程由manifest file控制。組件的節點activity, service, receiver, 和 provider 都包含一個 process 屬性。這個屬性可以設置組件運行的進程:可以配置組件在一個獨立進程運行,或者多個組件在同一個進程運行。甚至可以多個程序在一個進程中運行——如果這些程序共享一個User ID並給定同樣的許可權。 節點也包含 process 屬性,用來設置程序中所有組件的默認進程。
所有的組件在此進程的主線程中實例化,系統對這些組件的調用從主線程中分離。並非每個對象都會從主線程中分離。一般來說,響應例如View.onKeyDown()用戶操作的方法和通知的方法也在主線程中運行。這就表示,組件被系統調用的時候不應該長時間運行或者阻塞操作(如網路操作或者計算大量數據),因為這樣會阻塞進程中的其他組件。可以把這類操作從主線程中分離。
當更加常用的進程無法獲取足夠內存,Android可能會關閉不常用的進程。下次啟動程序的時候會重新啟動進程。
當決定哪個進程需要被關閉的時候, Android會考慮哪個對用戶更加有用。如Android會傾向於關閉一個長期不顯示在界面的旦頌殲進程來支持一個經常顯示在界面的進程。
線程:即使為組件分配了不同的進程,有時候也需要再分配線程。比如用戶界面需要很快對用戶進行響應,因此某些費時的操作,如網路連接、下載或者非常佔用伺服器時間的操作應該放到其他線程。
線程通過java的標准對象Thread 創建. Android 提供了很多方便的管理線程的方法:— Looper 在線程中運行一個消息循環; Handler 傳遞一個消息; HandlerThread 創建一個帶有消息循環的線程。
遠程調用Remote procere calls
Android有一個遠程調用(RPCs) 的輕量級機制— 通過這個機制,方法可以在本地調用,在遠程執行(在其他進程執行),還可以返回一個值。要實現這個需求,必須分解方法調用,並且所有要傳遞的數據必須是操作系統可以訪問的級別。從本地的進程和內存地址傳送到遠程的進程和內存地櫻正址並在遠程處理和返回。返回值必須向相反的方向傳遞。Android提供了做以上操作的代碼,所以開發者可以專注於實現RPC的介面。
一個RPC介面只能包含方法。所有的方法都是同步執行的(直到遠程方法返回,本地方法才結束阻塞),沒有返回值的時候也是如此。
簡單來說,這個機制是這樣的:使用IDL (interface definition language)定義你想要實現的介面, aidl 工具可以生成用於java的介面定義,本地和遠程都要使用這個定義。它包含2個類,
inner類包含了所有的管理遠程程序(符合IDL描述的介面)所需要的代碼。所有的inner類實現了IBinder 介面.其中一個在本地使用,可以不管它的代碼;另外一個叫做Stub繼承了 Binder 類。為了實現遠程調用,這個類包含RPC介面。開發者可以繼承Stub類來實現需要的方法。
一般來說,遠程進程會被一個service管理(因為service可以通知操作系統這個進程的信息並和其他進程通信),它也會包含aidl 工具產生的介面文件,Stub類實現了遠處那個方法。服務的客戶端只需要aidl 工具產生的介面文件。
以下是如何連接服務和客戶端調用:
·服務的客戶端(本地)會實現onServiceConnected() 和onServiceDisconnected() 方法,這樣,當客戶端連接或者斷開連接的時候可以獲取到通知。通過 bindService() 獲取到服務的連接。
· 服務的 onBind() 方法中可以接收或者拒絕連接,取決它收到的intent (intent通過 bindService()方法連接到服務). 如果服務接收了連接,會返回一個Stub類的實例.
· 如果服務接受了連接,Android會調用客戶端的onServiceConnected() 方法,模沖並傳遞一個Ibinder對象(系統管理的Stub類的代理),通過這個代理,客戶端可以連接遠程的服務。
以上的描述省略很多RPC的機制。請參見Designing a Remote Interface Using AIDL 和 IBinder 類。
線程安全的方法
在某些情況下,方法可能調用不止一個的線程,因此需要注意方法的線程安全。
對於可以遠程調用的方法,也要注意這點。當一個調用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在Ibinder的進程中執行。但是,如果調用者發起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調用onBind() 方法,onBind() 返回的對象(如實現了RPC的Stub子類)中的方法會被從線程池中調用。因為一個服務可能有多個客戶端請求,不止一個線程池會在同一時間調用IBinder的方法。因此IBinder必須線程安全。
簡單來說,這個機制是這樣的:使用IDL (interface definition language)定義你想要實現的介面, aidl 工具可以生成用於java的介面定義,本地和遠程都要使用這個定義。它包含2個類,
inner類包含了所有的管理遠程程序(符合IDL描述的介面)所需要的代碼。所有的inner類實現了IBinder 介面.其中一個在本地使用,可以不管它的代碼;另外一個叫做Stub繼承了 Binder 類。為了實現遠程調用,這個類包含RPC介面。開發者可以繼承Stub類來實現需要的方法。
一般來說,遠程進程會被一個service管理(因為service可以通知操作系統這個進程的信息並和其他進程通信),它也會包含aidl 工具產生的介面文件,Stub類實現了遠處那個方法。服務的客戶端只需要aidl 工具產生的介面文件。
以下是如何連接服務和客戶端調用:
·服務的客戶端(本地)會實現onServiceConnected() 和onServiceDisconnected() 方法,這樣,當客戶端連接或者斷開連接的時候可以獲取到通知。通過 bindService() 獲取到服務的連接。
· 服務的 onBind() 方法中可以接收或者拒絕連接,取決它收到的intent (intent通過 bindService()方法連接到服務). 如果服務接收了連接,會返回一個Stub類的實例.
· 如果服務接受了連接,Android會調用客戶端的onServiceConnected() 方法,並傳遞一個Ibinder對象(系統管理的Stub類的代理),通過這個代理,客戶端可以連接遠程的服務。
線程安全的方法
在某些情況下,方法可能調用不止一個的線程,因此需要注意方法的線程安全。
對於可以遠程調用的方法,也要注意這點。當一個調用在Ibinder對象中的方法的程序啟動了和Ibinder對象相同的進程,方法就在Ibinder的進程中執行。但是,如果調用者發起另外一個進程,方法在另外一個線程中運行,這個線程在和IBinder對象在一個線程池中;它不會在進程的主線程中運行。例如,一個service從主線程被調用onBind() 方法,onBind() 返回的對象(如實現了RPC的Stub子類)中的方法會被從線程池中調用。因為一個服務可能有多個客戶端請求,不止一個線程池會在同一時間調用IBinder的方法。因此IBinder必須線程安全。
簡單來說,一個content provider 可以接收其他進程的數據請求。即使ContentResolver和ContentProvider類沒有隱藏了管理交互的細節,ContentProvider中響應這些請求的方法(query(), insert(), delete(), update(), and getType() )— 是在content provider的線程池中被調用的,而不是ContentProvider的本身進程。因為這些方法可能是同時從很多線程池運行的,所以這些方法必須要線程安全。

熱點內容
e盤亂碼文件夾 發布:2025-03-09 21:32:31 瀏覽:132
美圖手機如何解密碼開鎖 發布:2025-03-09 21:14:35 瀏覽:15
行車記錄儀安卓版如何使用 發布:2025-03-09 20:58:03 瀏覽:312
sql登陸不了 發布:2025-03-09 20:45:16 瀏覽:924
如何用本機做伺服器 發布:2025-03-09 20:43:54 瀏覽:44
新時達伺服器如何查故障 發布:2025-03-09 20:31:14 瀏覽:949
sql2005server 發布:2025-03-09 20:31:08 瀏覽:113
過濾sql注入 發布:2025-03-09 20:23:25 瀏覽:992
華為榮耀6大容量存儲 發布:2025-03-09 20:22:34 瀏覽:457
php流圖片 發布:2025-03-09 20:22:27 瀏覽:44