2

我的疑問是關於如何在另一個線程的服務中的API中運行一段代碼。在單獨的線程上運行一段代碼

我在我的服務中有一個API函數。只有這個API代碼的一部分是獨立的(2-3 LOC),我想將它移動到單獨的線程中,因爲這些代碼佔用了大量的時間,並且這些代碼行對UI線程沒有影響。這就是我所做的。

原代碼:

func(){ 
    subA(); 
    subB(); 
    subC(); 
} 

修改後的代碼:

Thread mThread = null; 
func(){ 
    subA(); 
    if(mThread == null){ 
     mThread = new Thread(){ 
      public void run(){ 
       subB(); 
       subC(); 
      } 
     } 
    } 
    mThread.start(); 
} 

在運行這段代碼,我得到一個例外「線程已經開始」

我沒有讀過關於這個的SO,已經啓動的線程不能再次重新啓動。我需要再次創建一個新線程並啓動它。但是我不想每次都創建一個新的線程對象,因爲這會導致UI線程的性能問題。有沒有其他辦法可以處理。

我發現了一些其他的方式來達到這個在android,如Handler,HandlerThread,AsyncTask等,但我不能解決我的想法是最好在這裏使用(我不想創建新的對象每次(thread/asynctask/handler/handlerthread),只需要創建線程對象一次,並重新使用它每次)。

如果有人曾經在此領域工作過,請幫忙!

+0

您最好使用異步任務或處理程序。從長遠來看,你會遇到許多問題,這些構造已經被制定出來並且培養你自己的解決方案也是需要創造的更多工作。只有在你想學習的時候纔去做線程。 – allprog

+0

@allprog你可以看看我自己的答案。任何評論,我可以避免每次創建新的可運行對象(我現在正在這樣做,因爲我需要每次將新的參數傳遞給subB()和subC()。我認爲只創建一次可運行對象會創建一個問題。) – superuser

回答

2

在進一步研究線程部分時,我設法發現使用ThreadHandler比使用線程+循環(因爲ThreadHandler默認情況下有一個活套附加到它並對其進行管理)更簡單。所以,這是我現在正在尋找的代碼。

HandlerThread mThread = null; 
Handler mHandler = null; 
func(){ 
    subA(); 
    if(mThread == null){ 
     mThread = new HandlerThread("mThread"); 
     mThread.start(); 
     mHandler = new Handler(mThread.getLooper()); 
    } 
    mHandler.post(new Runnable(){ 
    public void run(){ 
     subB(); 
     subC(); 
    }}); 
} 

但我發現這個代碼有一個問題,我仍然需要在每次調用func()時創建一個runnable的新對象。需要了解我如何避免這種情況。

+0

創建對象很便宜(大多數情況下)。對於Android來說,如果你開始將函數想象成可以像Javascript一樣傳遞的對象,那麼它會有很大的幫助。儘可能避免可變字段,儘可能使用final關鍵字。這些代碼正是在這些情況下需要完成的工作。如果併發執行subX不是問題,則使用AsyncTask而不是處理程序。做得好! – allprog

+1

還有一些注意事項:1.處理程序確保順序執行,Runnables逐個執行。 2.如果runnable沒有可變狀態並且它始終在相同的輸入數據上運行,那麼重用它可能是安全的。但是,只要它不會產生問題,我會保留原樣。目前是最安全的解決方案。 – allprog

+0

「,如果runnable沒有可變狀態並且它始終在相同的輸入數據上運行,那麼重用它可能是安全的。」 - 我做到了。現在我的代碼運行良好,並且每次都不創建任何新對象。 yey !! – superuser

1

您只能啓動一次線程,這就是您得到錯誤的原因。

簡單的修復方法是使用隊列。讓線程在無限循環中從隊列中讀取,並讓其他線程將「工作」放入隊列中。

這裏與你相似的例子(更新使用阻塞接口):

Thread mThread = null; 
void func(String dataToWorkWith) { 
    final BlockingQueue<String> q = new ArrayBlockingQueue<String>(1000); 
    subA(); 
    q.add("some data if you need it"); 
    if(mThread == null) { 
     mThread = new Thread() { 
      public void run() { 
       while(true) { 
        try { 
         final String dataToWorkWith = q.take(); 
         subB(dataToWorkWith); 
         subC(dataToWorkWith); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 

     }; 
     mThread.start(); 
    } 
} 

這是假設你想蘇巴在主線程中的每個呼叫和subB的和subC的在後臺線程。

1

if(mThread == null)塊內移動mThread.start();。隨後調用該方法時無條件地啓動相同的線程。

+0

如果我這樣做,subB()和subC()將只在第一次調用func()時運行。但是我希望它們每次都調用func(),並且每次都有新的參數。 – superuser

+0

看起來你真的可以使用'AsyncTask',然後爲每個調用創建一個執行它的新實例。 – laalto

+0

也許我可以做到這一點。但是我不想每次都創建任何東西的新對象,因爲這會將負載放在我的UI線程上。創建新對象需要很長時間,我們應該在關鍵的UI操作(AFAIK)期間避免這種情況。我想找到某種方式,比如,也許我可以創建一個AsyncTask的實例,以便第一次調用func(),並在每次後續調用func()時重新使用該對象。但是afaik,這對於AsyncTasks來說是不可能的?不確定Handler/HandlerThread。 – superuser

相關問題