簡體   English   中英

如何在 Android 的后台線程上運行代碼?

[英]How can I run code on a background thread on Android?

我希望一些代碼在后台連續運行。 我不想在服務中這樣做。 有沒有其他可能的方法?

我曾嘗試在我的Activity中調用Thread類,但我的Activity會在后台停留一段時間然后停止。 Thread類也停止工作。

class testThread implements Runnable {
        @Override
        public void run() {
            File file = new File( Environment.getExternalStorageDirectory(), "/BPCLTracker/gpsdata.txt" );
            int i = 0;

            RandomAccessFile in = null;

            try {
                in = new RandomAccessFile( file, "rw" );
            } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            }
//String line =null;
            while ( true ) {
                HttpEntity entity = null;
                try {
                    if ( isInternetOn() ) {
                        while ( ( line = in.readLine() ) != null ) {

                            HttpClient client = new DefaultHttpClient();
                            String url = "some url";
                            HttpPost request = new HttpPost( url );
                            StringEntity se = new StringEntity( line );
                            se.setContentEncoding( "UTF-8" );
                            se.setContentEncoding( new BasicHeader( HTTP.CONTENT_TYPE, "application/json" ) );
                            entity = se;
                            request.setEntity( entity );
                            HttpResponse response = client.execute( request );
                            entity = response.getEntity();
                            i++;
                        }
                        if ( ( line = in.readLine() ) == null && entity != null ) {
                            file.delete();
                            testThread t = new testThread();
                            Thread t1 = new Thread( t );
                            t1.start();
                        }


                    } else {
                        Thread.sleep( 60000 );
                    } // end of else

                } catch (NullPointerException e1) {
                    e1.printStackTrace();
                } catch (InterruptedException e2) {
                    e2.printStackTrace();
                } catch (IOException e1) {
// TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }// end of while
        }// end of run

    }

如果你需要:

  1. 在后台線程上執行代碼

  2. 執行不接觸/更新 UI 的代碼

  3. 執行(短)代碼,最多需要幾秒鍾才能完成

然后使用以下使用 AsyncTask 的簡潔高效的模式:

AsyncTask.execute(new Runnable() {
   @Override
   public void run() {
      //TODO your background code
   }
});

記住運行背景,連續運行是兩個不同的任務。

對於長期后台進程,線程不是 Android 的最佳選擇。 但是,這是代碼,請自行承擔風險。

要以正確的方式處理它,您需要首先啟動服務,在服務內部,您需要啟動需要可運行的線程/異步任務。

請記住,Service 和 Thread 將在后台運行,但我們的任務需要觸發(一次又一次調用)以獲取更新,即一旦任務完成,我們需要調用函數以進行下一次更新。

Timer(周期性觸發),Alarm(時基觸發),Broadcast(事件基觸發),遞歸會喚醒我們的函數。

public static boolean isRecursionEnable = true;

void runInBackground() {
    if (!isRecursionEnable)
        // Handle not to start multiple parallel threads
        return;

    // isRecursionEnable = false; when u want to stop
    // on exception on thread make it true again  
    new Thread(new Runnable() {
        @Override
        public void run() {
            // DO your work here
            // get the data
            if (activity_is_not_in_background) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // update UI
                        runInBackground();
                    }
                });
            } else {
                runInBackground();
            }
        }
    }).start();
}

使用服務:如果你啟動一個服務,它會啟動,它會執行任務,如果服務不是 STICKY,它會在任務執行后自行終止。 此服務終止也可能是由代碼中的異常或用戶從設置中手動終止的。

START_STICKY(粘性服務)是 Android 提供的選項,如果服務終止,服務將自行重啟。

還記得多處理和多線程之間的問題區別嗎? Service 是一個后台進程(就像沒有 UI 的活動一樣),與您在活動中啟動線程以避免負載在 MainThread(活動/UI 線程)上的方式相同,您需要在服務上啟動線程以避免負載的方式相同服務。

在單個語句中,如果要運行后台繼續任務,則需要啟動 StickyService 並在事件庫的服務中運行線程

簡單的 3 線

我發現了一種簡單的方法,這是@awardakBrandon Rude 的回答中的評論:

new Thread( new Runnable() { @Override public void run() { 
  // Run whatever background code you want here.
} } ).start();

我不確定這是否或如何比使用AsyncTask.execute更好,但它似乎對我們有用。 任何關於差異的評論將不勝感激。

謝謝, @awardak

我希望一些代碼在后台連續運行。 我不想在服務中這樣做。 有沒有其他可能的方法?

您正在尋找的最有可能的機制是AsyncTask 它直接指定在后台線程上執行后台進程。 此外,它的主要好處是提供了一些在主(UI)線程上運行的方法,如果您想向用戶通知任務的某些進展或使用從后台進程檢索的數據更新 UI,則可以更新您的 UI。

如果您不知道如何從這里開始,這里有很好的教程:

注意:也有可能將IntentServiceResultReceiver一起使用。

今天我正在尋找這個,布蘭登魯德先生給出了一個很好的答案 不幸的是, AsyncTask現在已棄用 你仍然可以使用它,但它會給你一個警告,這很煩人。 因此,另一種選擇是使用這樣的Executors (在kotlin中):


        Executors.newSingleThreadExecutor().execute(Runnable {
            // todo: do your background tasks
            runOnUiThread{
                // update ui if you are in an activity
            }
            /*
            requireActivity().runOnUiThread {
               // update views / ui if you are in a fragment
            }
            */
        })

java中它看起來像這樣:


        Executors.newSingleThreadExecutor().execute(() -> {
            // todo: background tasks
            runOnUiThread(() -> {
                // todo: update your ui / view in activity
            });

            /*
            requireActivity().runOnUiThread((Runnable) () -> {
                // todo: update your ui / view in Fragment
            });
            */
        });

AsyncTask 的替代方案是 robospice。 https://github.com/octo-online/robospice

robospice 的一些特性。

1. 異步執行(在后台 AndroidService 中)網絡請求(例如:使用 Spring Android 的 REST 請求)。當結果准備好時,在 UI 線程上通知您的應用程序。

2.強類型! 您使用 POJO 提出請求,並獲得 POJO 作為請求結果。

3. 對用於請求的 POJO 和您在項目中使用的 Activity 類均不實施任何限制。

4.caches 結果(在 Json 中同時包含 Jackson 和 Gson,或 Xml,或純文本文件,或二進制文件,甚至使用 ORM Lite)。

5.當且僅當它們仍然存在時,通知您的活動(或任何其他上下文)網絡請求的結果

6. 完全沒有內存泄漏,就像 Android Loaders 一樣,不像 Android AsyncTasks 在他們的 UI 線程上通知你的活動。

7.使用簡單但健壯的異常處理模型。

樣品開始。 https://github.com/octo-online/RoboSpice-samples

https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result上的 robospice 示例。

更新:以上是答案不再有效。 使用 kotlin 協程進行后台線程。

class Background implements Runnable {
    private CountDownLatch latch = new CountDownLatch(1);
    private  Handler handler;

    Background() {
        Thread thread = new Thread(this);
        thread.start();
        try {
            latch.await();
        } catch (InterruptedException e) {
           /// e.printStackTrace();
        }
    }

    @Override
    public void run() {
        Looper.prepare();
        handler = new Handler();
        latch.countDown();
        Looper.loop();
    }

    public Handler getHandler() {
        return handler;
    }
}

如果您需要使用不同的代碼預先運行線程,這里是示例:

聽眾:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

線程類

public class ESLThread extends AsyncTask<Void, Void, List> {


    private ESLThreadListener mListener;

    public ESLThread() {

        if(mListener != null){

            mListener.onBackground();
        }
    }

    @Override
    protected List doInBackground(Void... params) {

        if(mListener != null){

            List list = mListener.onBackground();

            return list;
        }

        return null;
    }

    @Override
    protected void onPostExecute(List t) {
        if(mListener != null){

            if ( t != null) {
                mListener.onPostExecute(t);
            }
        }

    }


    public void setListener(ESLThreadListener mListener){

        this.mListener = mListener;
    }
}

運行不同的代碼:

  ESLThread thread = new ESLThread();
                        thread.setListener(new ESLThreadListener() {
                            @Override
                            public List onBackground() {
                                List<EntityShoppingListItems>  data = RoomDB.getDatabase(context).sliDAO().getSL(fId);

                                return data;

                            }

                            @Override
                            public void onPostExecute(List t) {

                                List<EntityShoppingListItems> data = (List<EntityShoppingListItems>)t;
                                adapter.setList(data);
                            }
                        });

                        thread.execute();

//對我來說准確無誤

new Thread( () -> {
        //run code on background thread 
        
        activity.runOnUiThread(()->{
            //update the UI on main thread
        });

        //here activity is the reference of activity 
    
            
    }).start();

//或者

 new Thread(new Runnable() {
        @Override
        public void run() {
            //run code on background thread 
        
        activity.runOnUiThread(()->{
            //update the UI on main thread
        });

        //here activity is the reference of activity 
        }
    })

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM