Як я можу запустити код на фоновому потоці на Android?


131

Я хочу, щоб якийсь код постійно працював у фоновому режимі. Я не хочу робити це в сервісі. Чи можливий інший спосіб?

Я спробував зателефонувати в Threadклас, Activityале мої 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
Привіт. Чи можете ви надіслати будь-який код як приклад того, що ви спробували? Існують різні способи запуску коду на фоновому потоці, але ви повинні пам'ятати, якщо ви звертаєтесь до будь-яких компонентів інтерфейсу, ви повинні отримати доступ до них у потоці інтерфейсу користувача, використовуючи runOnUiThread()метод.
Алекс Візе

3
Чи є якась конкретна причина не використовувати Сервіс
DeltaCap019

це не так рекомендується. Безперервна робота буде виснажувати батарею пристрою
HelmiB

Я надіслав код.
користувач2082987

Я намагався використовувати його в сервісі, але він надсилав один і той же запис кілька разів.
користувач2082987

Відповіді:


379

ЯКЩО вам потрібно:

  1. виконати код на тлі теми

  2. виконати код, який НЕ торкається / не оновлює інтерфейс користувача

  3. виконати (короткий) код, на виконання якого піде не більше декількох секунд

ТОГО використовуйте таку чисту та ефективну схему, яка використовує AsyncTask:

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

10
Примітка: Потрібен рівень 11 API
friederbluemle

9
Чому б вам не скористатись такою легкішою: нова нитка (нова Runnable () {@Override public void run () {// фон коду}}). Start ();
awardak

3
Чи існує можливість цього спричинити витік пам'яті?
Гільфріц

5
Варто відзначити, що AsyncTasks ставлять у чергу. Якщо ви використовуєте це для купки дзвінків api-сервера, вони не працюватимуть паралельно.
Чейз Робертс


45

Пам’ятайте про запуск фону, безперервний біг - це два різних завдання.

Для тривалих фонових процесів потоки не є оптимальними для Android. Однак ось код і робіть це на свій страх і ризик ...

Пам'ятайте, що служба або нитка працюватимуть у фоновому режимі, але для отримання оновлень нам потрібно зробити триггер (дзвонити знову і знову), тобто після завершення завдання нам потрібно буде відкликати функцію для наступного оновлення.

Таймер (періодичний тригер), сигнал тривоги (тригер бази часу), трансляція (тригер бази подій), рекурсія буде будити наші функції.

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

Використання служби: Якщо ви запустили службу, вона запуститься, вона виконає завдання, і вона припинить себе. після виконання завдання. припинення може також бути викликане винятком, або користувач убив його вручну з налаштувань. START_STICKY (Sticky Service) - це опція, надана андроїдом, що служба перезапуститься, якщо служба припиниться.

Пам'ятаєте різницю між питаннями багатопроцесорної та багатопоточної? Сервіс - це фоновий процес (так само, як діяльність без користувальницького інтерфейсу). Так само, як ви запускаєте потік у діяльності, щоб уникнути навантаження на основний потік (потоку діяльності), так само, як вам потрібно запустити потоки (або завдання асинхронізації) в сервісі щоб уникнути навантаження на службу.

У одному заяві, якщо ви хочете, щоб запуск фонового завдання продовжувалося, вам потрібно запустити StickyService і запустити потік у службі на базі подій


Чи рекомендуєте ви цей метод для запуску користувальницького SignalStrengthListener у фоновому режимі в середньому 20 хвилин, одночасно захоплюючи значення слухача раз на секунду для оновлення потоку інтерфейсу користувача? Ось ще контекст: stackoverflow.com/questions/36167719 / ...
JParks

Як процес знову запускається, якщо встановити "isRecursionEnable = true"? Потім ви зателефонуєте всередину методу 'run' для 'runInBackground ()', як би він не вводив оператор if на початку функції?
Міккі

23

Я хочу, щоб якийсь код постійно працював у фоновому режимі. Я не хочу робити це в сервісі. Чи можливий інший спосіб?

Швидше за все, ви шукаєте механізм, який ви шукаєте AsyncTask. Він безпосередньо призначений для виконання фонового процесу на фоновій нитці. Також його головна перевага полягає в тому, що пропонується декілька методів, які працюють на Main (UI) Thread і дозволяють оновити інтерфейс користувача, якщо ви хочете повідомити користувача про деякий прогрес у виконанні завдання або оновити інтерфейс користувача, отриманий з фонового процесу.

Якщо ви не знаєте, як почати тут, приємний підручник:

Примітка. Також є можливість використання IntentServiceз цим, ResultReceiverщо працює.


@ user2082987 так ви це спробували?
Саймон Дорочак

ці параметри asyncTask заплутані
user2082987

AsyncTask - це просто обгортка навколо теми, так що вона не вирішує проблему вбивства Android за допомогою програми, коли вона знаходиться у фоновому режимі
Лассі Кіннунен

Привіт @LassiKinnunen Я написав цю відповідь 5 років тому. Тепер все змінилося, і я зараз не використовую AsyncTask, оскільки його протікання пам'яті не є безпечним.
Симон Дорочак

Так, я розумію, що, але люди все одно знайдуть це через Google, і я побачив так багато коментарів людей, які рекомендують використовувати обгортки google, навіть коли це мало корисно для будь-якої мети, вибачте. Що стосується початкового запитання, якщо хтось шукає відповіді у 2018 році, створіть службу та запустіть її та позначте її як передній план із повідомленням, якщо ви хочете максимально збільшити шанси на те, що вона не буде вбита. Справжній тривалий процес можна обробити обробниками або окремою ниткою. Хіба не зрозуміли, що їм вдалося насправді зробити це не витоком пам’яті безпечним?
Лассі Кіннунен

16

Простий 3-Liner

Простий спосіб зробити це я знайшов як коментар @awardak у відповіді Брендона Руда :

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

Я не впевнений, чи це, чи як, це краще, ніж використовувати, AsyncTask.executeале, здається, це працює для нас. Будь-які коментарі щодо різниці будуть вдячні.

Дякую, @awardak !


ми використовуємо метод handler.post (), щоб розмістити його на головній темі всередині методу запуску теми.
androidXP

2

Альтернативою AsyncTask є robospice. https://github.com/octo-online/robospice .

Деякі особливості robospice.

1.виконує асинхронно (у фоновому режимі AndroidService) запити мережі (наприклад: REST-запити за допомогою Spring Android). Повідомте про додаток у потоці інтерфейсу користувача, коли результат буде готовий.

2.сильно набрано! Ви робите свої запити, використовуючи POJO, і ви отримуєте POJO як результати запиту.

3.enforce жодних обмежень, ні для POJO, які використовуються для запитів, ні класів активності, які ви використовуєте у своїх проектах.

4. кеш-результати (в Json як з Джексоном, так і з Gson, або Xml, або плоскі текстові файли, або двійкові файли, навіть використовуючи ORM Lite).

5. повідомляє про вашу діяльність (або будь-який інший контекст) результату мережевого запиту, якщо і лише якщо вони ще живі

6.не протікання пам’яті взагалі, як Android-навантажувачі, на відміну від Android AsyncTasks сповіщає про вашу діяльність на їх потоці інтерфейсу користувача.

7.використовує просту, але надійну модель оброблення виключень.

Зразки для початку. https://github.com/octo-online/RoboSpice-samples .

Зразок robospice за адресою https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result .


Як зберігати масив, отриманий від мережі до SQLite? В основному я хотів би: отримати дані з мережі та зберегти їх у моєму SQLite - як у фоновому потоці, так і сповістити мій інтерфейс, щоб оновити ListView. Я зазвичай роблю це з IntentService, але RoboSpice менше друкує.
Яр

@yar ви можете використовувати службу намірів, якщо це тривала операція. Також ви можете використовувати asynctask, але тільки якщо його короткий час. Ви можете створити нитку і зробити всі свої речі там. Я вже давно не використовую robospice. Є й інші мережеві бібліотеки, такі як волейбол ...
Рагунандан

Добре, дякую. Я думав про використання Robospice, але, схоже, це не надто добре (гнучко) для моїх потреб. Я довго використовую IntentService з успіхом.
Яр

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
Ласкаво просимо до StackOverflow. Відповіді, що містять лише код, мають тенденцію до видалення, оскільки вони "низької якості". Будь ласка, прочитайте розділ довідки щодо відповіді на запитання, а потім подумайте, як додати свій коментар до своєї відповіді.
Грем

0

Якщо вам потрібно запускати нитку попередньо з різними кодами, ось приклад:

Слухач:

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();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.