Làm cách nào tôi có thể chạy mã trên một luồng nền trên Android?


131

Tôi muốn một số mã để chạy trong nền liên tục. Tôi không muốn làm điều đó trong một dịch vụ. Có cách nào khác có thể?

Tôi đã cố gắng gọi Threadlớp trong tôi Activitynhưng Activityđôi khi tôi vẫn ở trong nền và sau đó nó dừng lại. Các Threadlớp cũng ngừng hoạt động.

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
Chào. Bạn có thể vui lòng gửi một số mã như một ví dụ về những gì bạn đã cố gắng? Có nhiều cách khác nhau để chạy mã trên luồng nền nhưng bạn phải nhớ nếu bạn đang truy cập bất kỳ thành phần UI nào, bạn phải truy cập chúng trên luồng UI bằng cách sử dụng runOnUiThread()phương thức.
Alex Wiese

3
Có bất kỳ lý do cụ thể nào cho việc không sử dụng Dịch vụ
DeltaCap019

điều này không được khuyến khích chạy liên tục sẽ làm cạn kiệt pin thiết bị.
HelmiB

Tôi đã gửi mã.
dùng2082987

Tôi đã thử sử dụng nó trong dịch vụ nhưng nó gửi cùng một bản ghi nhiều lần.
dùng2082987

Câu trả lời:


379

Nếu bạn cần:

  1. thực thi mã trên một chủ đề nền

  2. thực thi mã KHÔNG chạm / cập nhật giao diện người dùng

  3. thực thi mã (ngắn) sẽ mất ít nhất vài giây để hoàn thành

THEN sử dụng mẫu sạch và hiệu quả sau sử dụng AsyncTask:

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

10
Lưu ý: Yêu cầu API cấp 11
Friederbluemle

9
Tại sao bạn không sử dụng cái sau nhẹ hơn: Chủ đề mới (new Runnable () {@Override public void run () {// mã nền}}). Start ();
trao giải

3
Có khả năng này gây rò rỉ bộ nhớ?
Hilfritz

5
Một điều cần lưu ý là AsyncT task được qeued. Nếu bạn sử dụng điều này cho một loạt các cuộc gọi api của máy chủ, chúng sẽ không chạy song song.
Chase Roberts


45

Nhớ Chạy nền, Chạy liên tục là hai nhiệm vụ khác nhau.

Đối với các quy trình nền dài hạn, Chủ đề không tối ưu với Android. Tuy nhiên, đây là mã và tự chịu rủi ro ...

Ghi nhớ Dịch vụ hoặc Chủ đề sẽ chạy trong nền nhưng tác vụ của chúng tôi cần kích hoạt (gọi đi gọi lại) để nhận các bản cập nhật, tức là khi tác vụ hoàn thành, chúng tôi cần gọi lại chức năng cho lần cập nhật tiếp theo.

Hẹn giờ (kích hoạt định kỳ), Báo động (kích hoạt Timebase), Phát sóng (Kích hoạt cơ sở sự kiện), đệ quy sẽ đánh thức các chức năng của chúng tôi.

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();
}

Sử dụng Dịch vụ: Nếu bạn khởi chạy Dịch vụ, nó sẽ khởi động, Nó sẽ thực thi tác vụ và nó sẽ tự chấm dứt. sau khi thực hiện nhiệm vụ. chấm dứt cũng có thể được gây ra bởi ngoại lệ hoặc người dùng đã giết nó bằng tay từ cài đặt. START_STICKY (Dịch vụ dính) là tùy chọn được cung cấp bởi Android mà dịch vụ sẽ tự khởi động lại nếu dịch vụ bị chấm dứt.

Ghi nhớ sự khác biệt câu hỏi giữa đa xử lý và đa luồng? Dịch vụ là một quá trình nền (Giống như hoạt động không có UI), Giống như cách bạn khởi chạy luồng trong hoạt động để tránh tải trên luồng chính (luồng hoạt động), giống như cách bạn cần khởi chạy luồng (hoặc tác vụ không đồng bộ) trên dịch vụ để tránh tải về dịch vụ.

Trong một câu lệnh, nếu bạn muốn một tác vụ tiếp tục chạy nền, bạn cần khởi chạy một StickService và chạy chuỗi trong dịch vụ trên cơ sở sự kiện


Bạn có muốn giới thiệu phương pháp này để chạy SignalSt cườngListener tùy chỉnh trong nền trong trung bình 20 phút, trong khi lấy các giá trị từ trình nghe một lần mỗi giây để cập nhật luồng UI không? Đây là nhiều ngữ cảnh hơn: stackoverflow.com/questions/36167719/NH
JParks

Làm thế nào để quá trình chạy lại nếu bạn đặt 'isRecursionEnable = true'? Sau đó, bạn gọi bên trong phương thức 'run' cho 'runInBackground ()', làm thế nào nó không nhập câu lệnh if ở đầu hàm?
Mickey

23

Tôi muốn một số mã để chạy trong nền liên tục. Tôi không muốn làm điều đó trong một dịch vụ. Có cách nào khác có thể?

Nhiều khả năng cơ học mà bạn đang tìm kiếm là AsyncTask. Nó trực tiếp được chỉ định để thực hiện quá trình nền trên Chủ đề nền. Ngoài ra lợi ích chính của nó là cung cấp một vài phương thức chạy trên Main (UI) Thread và có thể cập nhật UI của bạn nếu bạn muốn thông báo cho người dùng về một số tiến trình trong nhiệm vụ hoặc cập nhật UI với dữ liệu được lấy từ quá trình nền.

Nếu bạn không biết làm thế nào để bắt đầu ở đây là hướng dẫn tốt đẹp:

Lưu ý: Cũng có khả năng sử dụng IntentServicevới ResultReceiverhoạt động đó là tốt.


@ user2082987 vậy bạn đã thử chưa?
Simon Dorociak 18/03/13

các tham số này của asyncTask rất khó hiểu
user2082987 18/03/13

Dù sao, AsyncTask chỉ là một trình bao bọc xung quanh Thread, vì vậy nó không giải quyết được vấn đề Android giết chết ứng dụng khi nó ở chế độ nền
Lassi Kinnunen

Xin chào @LassiKinnunen Tôi đã viết câu trả lời đó 5 năm trước. Bây giờ mọi thứ đã thay đổi và tôi hiện không sử dụng AsyncTask vì rò rỉ bộ nhớ của nó không an toàn.
Simon Dorociak

Vâng, tôi nhận ra điều đó nhưng mọi người vẫn sẽ tìm thấy điều này thông qua google và tôi đã thấy rất nhiều ý kiến ​​của mọi người khuyên bạn nên sử dụng trình bao bọc google ngay cả khi nó phục vụ rất ít mục đích, xin lỗi. Đối với câu hỏi ban đầu nếu ai đó đang tìm kiếm một số câu trả lời trong năm 2018, hãy tạo một dịch vụ và khởi chạy nó và đánh dấu nó ở phía trước với một thông báo nếu bạn muốn tối đa hóa cơ hội không bị giết. Quá trình chạy dài thực tế có thể được xử lý với các trình xử lý hoặc một luồng riêng biệt. Bạn đã không nhận ra rằng họ đã thực sự làm cho nó không bị rò rỉ bộ nhớ?
Lassi Kinnunen

16

3-lót đơn giản

Một cách đơn giản để làm điều này mà tôi đã tìm thấy như một nhận xét của @awardak trong câu trả lời của Brandon Rude :

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

Tôi không chắc nếu, hoặc làm thế nào, điều này tốt hơn so với việc sử dụng AsyncTask.executenhưng nó dường như hoạt động với chúng tôi. Bất kỳ ý kiến ​​về sự khác biệt sẽ được đánh giá cao.

Cảm ơn, @awardak !


chúng tôi sử dụng phương thức handler.post () để gửi lại chủ đề chính trong phương thức chạy của Thread.
androidXP

2

Một thay thế cho AsyncTask là robospice. https://github.com/octo-online/robospice .

Một số tính năng của robospice.

1. thực hiện các yêu cầu mạng không đồng bộ (trong nền AndroidService) (ví dụ: các yêu cầu REST sử dụng Spring Android). Thông báo cho ứng dụng của bạn, trên luồng UI, khi kết quả đã sẵn sàng.

2.is gõ mạnh mẽ! Bạn thực hiện các yêu cầu của mình bằng POJO và bạn nhận được POJO làm kết quả yêu cầu.

3. không buộc các ràng buộc nào đối với POJO được sử dụng cho các yêu cầu cũng như trên các lớp Activity mà bạn sử dụng trong các dự án của mình.

Kết quả 4.caches (trong Json với cả Jackson và Gson, hoặc Xml hoặc tệp văn bản phẳng hoặc tệp nhị phân, thậm chí sử dụng ORM Lite).

5. thông báo các hoạt động của bạn (hoặc bất kỳ bối cảnh nào khác) về kết quả của yêu cầu mạng khi và chỉ khi chúng vẫn còn sống

6. hoàn toàn không bị rò rỉ bộ nhớ, như Trình tải Android, không giống như Android AsyncT task thông báo cho các hoạt động của bạn trên Giao diện người dùng của họ.

7. sử dụng một mô hình xử lý ngoại lệ đơn giản nhưng mạnh mẽ.

Các mẫu để bắt đầu. https://github.com/octo-online/RoboSpice-samples .

Một mẫu của robospice tại https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result .


Làm thế nào để lưu trữ một mảng thu được từ mạng vào SQLite? Về cơ bản tôi muốn: lấy dữ liệu từ mạng VÀ lưu chúng vào SQLite của tôi - cả trong luồng nền, sau đó nhận UI của tôi được thông báo để làm mới ListView. Tôi thường làm điều đó với IntentService, nhưng RoboSpice thì ít gõ hơn.
Yar

@yar bạn có thể sử dụng một dịch vụ có ý định nếu hoạt động lâu dài. Ngoài ra, bạn có thể sử dụng asynctask nhưng chỉ khi nó trong một thời gian ngắn. Bạn có thể tạo một chủ đề và làm tất cả công cụ của bạn ở đó. Tôi đã không sử dụng robospice trong một thời gian dài bây giờ. Có những thư viện mạng khác như bóng chuyền ...
Raghunandan

Được rồi cảm ơn. Tôi đã nghĩ về việc sử dụng Robospice, nhưng có vẻ như nó không quá tốt (linh hoạt) cho nhu cầu của tôi. Tôi sử dụng IntentService trong một thời gian dài với thành công.
Yar

2
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;
    }
}

5
Chào mừng bạn đến với StackOverflow. Câu trả lời chỉ có mã trong đó có xu hướng bị gắn cờ để xóa vì chúng "chất lượng thấp". Vui lòng đọc phần trợ giúp về trả lời câu hỏi sau đó xem xét thêm một số bình luận vào Câu trả lời của bạn.
Graham

0

Nếu bạn cần chạy luồng tiền với các mã khác nhau ở đây là ví dụ:

Thính giả:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

Lớp học chủ đề

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;
    }
}

Chạy các mã khác nhau:

  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();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.