Android'de bir arka plan iş parçacığında nasıl kod çalıştırabilirim?


131

Arka planda sürekli olarak bazı kodların çalışmasını istiyorum. Bunu bir serviste yapmak istemiyorum. Mümkün olan başka bir yol var mı?

ThreadSınıfı aramaya çalıştım Activityama bir Activitysüre arka planda kaldım ve sonra durdu. ThreadSınıfı da çalışmayı durdurur.

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
Selam. Denediklerinize örnek olarak biraz kod yazabilir misiniz? Bir arka plan iş parçacığında kod çalıştırmanın farklı yolları vardır, ancak herhangi bir UI bileşenine erişiyorsanız, runOnUiThread()yöntemi kullanarak UI iş parçacığında bunlara erişmeniz gerektiğini hatırlamanız gerekir .
Alex Wiese

3
Hizmeti kullanmamanın belirli bir nedeni var mı
DeltaCap019

bu çok tavsiye edilmez. sürekli çalıştırmak cihazın pilini tüketir.
HelmiB

Kodu gönderdim.
user2082987

Hizmette kullanmayı denedim, ancak aynı kaydı birden çok kez gönderiyor.
user2082987

Yanıtlar:


379

Gerekirse:

  1. arka planda iş parçacığı üzerinde kod çalıştır

  2. UI'ye DOKUNMAYAN / GÜNCELLEŞTİRMEYEN kodu çalıştırın

  3. tamamlanması en fazla birkaç saniye sürecek olan (kısa) kodu çalıştırın

SONRA AsyncTask kullanan aşağıdaki temiz ve verimli modeli kullanın:

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

10
Not: API seviyesi 11 gerektirir
friederbluemle

9
Neden daha hafif olan aşağıdakini kullanmayasınız: new Thread (new Runnable () {@Override public void run () {// background code}}). Start ();
Awardak

3
Bunun bellek sızıntısına neden olma olasılığı var mı?
Hilfritz

5
Unutulmaması gereken bir şey, AsyncTasks'ın qeued olmasıdır. Bunu bir dizi sunucu api çağrısı için kullanırsanız, paralel olarak çalışmazlar.
Chase Roberts


45

Unutmayın Arka Plan Çalıştırmak, Sürekli çalıştırmak iki farklı görevdir.

Uzun vadeli arka plan işlemleri için, Threads Android ile uygun değildir. Ancak, işte kod ve bunu kendi sorumluluğunuzda yapın ...

Unutmayın, Service veya Thread arka planda çalışacaktır, ancak görevimizin güncellemeleri almak için tetikleme yapması (tekrar tekrar arama) gerekir, yani görev tamamlandığında bir sonraki güncelleme için işlevi geri çağırmamız gerekir.

Zamanlayıcı (periyodik tetik), Alarm (Zaman tabanı tetikleyici), Yayın (Olay temel Tetikleyici), özyineleme, işlevlerimizi uyandıracaktır.

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

Hizmeti Kullanma: Bir Hizmet başlatırsanız başlayacak, görevi yerine getirecek ve kendisini sonlandıracaktır. görevin yürütülmesinden sonra. sonlandırılması da istisnadan kaynaklanıyor olabilir veya kullanıcı ayarlardan manuel olarak öldürmüş olabilir. START_STICKY (Yapışkan Hizmet), hizmet sonlandırılırsa hizmetin kendini yeniden başlatacağı, android tarafından verilen seçenektir.

Çoklu işlem ve çoklu okuma arasındaki soru farkını hatırlıyor musunuz? Hizmet bir arka plan işlemidir (UI'sız etkinlik gibi), Ana iş parçacığına (Etkinlik iş parçacığı) yükten kaçınmak için etkinlikte iş parçacığını nasıl başlattığınız gibi, hizmette iş parçacıklarını (veya zaman uyumsuz görevleri) başlatmanızla aynı şekilde hizmette yükten kaçınmak için.

Tek bir ifadede, arka planda devam eden bir görevi çalıştırmak istiyorsanız, bir StickyService başlatmanız ve olay tabanındaki hizmetteki iş parçacığını çalıştırmanız gerekir.


UI iş parçacığını güncellemek için dinleyiciden değerleri saniyede bir alırken arka planda özel bir SignalStrengthListener çalıştırırken ortalama 20 dakika boyunca bu yöntemi önerir misiniz? İşte daha fazla bağlam: stackoverflow.com/questions/36167719/…
JParks

'İsRecursionEnable = true' ayarlarsanız işlem nasıl yeniden çalışır? Daha sonra 'runInBackground ()' için 'run' yöntemini çağırırsınız, işlevin başında if ifadesini nasıl girmez?
Mickey

23

Arka planda sürekli olarak bazı kodların çalışmasını istiyorum. Bunu bir serviste yapmak istemiyorum. Mümkün olan başka bir yol var mı?

Büyük olasılıkla aradığınız mekanizma AsyncTask. Arka planda iş parçacığı üzerinde arka plan işlemi gerçekleştirmek için doğrudan atanmıştır. Ayrıca ana faydası, Ana (UI) İş Parçacığı üzerinde çalışan birkaç yöntem sunması ve kullanıcıyı görevdeki bazı ilerlemeler hakkında bilgilendirmek veya arka plan işleminden alınan verilerle kullanıcı arayüzünü güncellemek istiyorsanız kullanıcı arayüzünüzü güncellemenizi mümkün kılmasıdır.

Nasıl başlayacağınızı bilmiyorsanız, güzel bir öğretici:

Not: Ayrıca bununla IntentServicebirlikte kullanma imkanı da vardır ResultReceiver.


@ user2082987 yani denedin mi?
Simon Dorociak

asyncTask'ın bu parametreleri kafa karıştırıcı
user2082987

AsyncTask, zaten iş parçacığının etrafındaki bir sarmalayıcıdır, bu nedenle Android'in uygulamayı arka
plandayken

Merhaba @LassiKinnunen Bu cevabı 5 yıl önce yazdım. Şimdi her şey değişti ve şu anda AsyncTask kullanmıyorum çünkü bellek sızıntısı güvenli değil.
Simon Dorociak

Evet, bunun farkındayım ama insanlar bunu yine de google aracılığıyla bulacaklar ve çok az amaca hizmet etse de veya hiç işe yaramasa bile google sarmalayıcıları kullanmanızı tavsiye eden çok sayıda insan yorumu gördüm, üzgünüm. Orijinal soruya gelince, biri 2018'de bazı cevaplar arıyorsa, bir hizmet oluşturun ve başlatın ve ölmeme şansını en üst düzeye çıkarmak istiyorsanız bir bildirimle ön planda olarak işaretleyin. Gerçek uzun süren süreç, işleyicilerle veya ayrı bir iş parçacığı ile gerçekleştirilebilir. Yine de bellek sızıntısını güvenli hale getirmediklerini fark etmediler mi?
Lassi Kinnunen

16

Basit 3-Astar

Bunu yapmanın basit bir yolu, @awardak tarafından Brandon Rude'un cevabında bir yorum olarak buldum :

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

Bunun kullanmaktan daha iyi olup olmadığından veya nasıl olduğundan emin değilim AsyncTask.execute ama bizim için işe yarıyor gibi görünüyor. Farkla ilgili her türlü yorum memnuniyetle karşılanacaktır.

Teşekkürler @awardak !


Handler.post () yöntemini, Thread'ın çalıştırma yöntemi içindeki ana iş parçacığına geri göndermek için kullanıyoruz.
androidXP

2

AsyncTask'a Alternatif Robospice'dir. https://github.com/octo-online/robospice .

Robospice'in bazı özellikleri.

1. eşzamansız olarak (bir arka planda AndroidService) ağ isteklerini yürütür (ör: Spring Android kullanarak REST istekleri). Sonuç hazır olduğunda, UI iş parçacığında size uygulamayı bildirir.

2. türü kuvvetle belirlenmiş! Taleplerinizi POJO'ları kullanarak yaparsınız ve POJO'ları istek sonucu olarak alırsınız.

3. Ne istekler için kullanılan POJO'larda ne de projelerinizde kullandığınız Activity sınıflarında hiçbir kısıtlama uygulamayın.

4. sonuçları önbelleğe alır (Json'da hem Jackson hem de Gson ile veya Xml veya düz metin dosyaları veya ikili dosyalar, ORM Lite kullanılarak bile).

5. faaliyetlerinizi (veya başka herhangi bir bağlamı) ağ talebinin sonucuyla ilgili olarak ancak ve ancak hala hayattaysa bildirir

6.Android Yükleyiciler gibi hiçbir bellek sızıntısı yok, Android AsyncTasks, etkinliklerinizi UI Thread üzerinden bildiriyor.

7. basit ama sağlam bir istisna işleme modeli kullanır.

Başlamak için örnekler. https://github.com/octo-online/RoboSpice-samples .

Https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result adresinde bir robospice örneği .


Ağdan elde edilen bir dizi SQLite'a nasıl saklanır? Temel olarak şunu istiyorum: ağdan veri almak VE bunları SQLite'ime kaydetmek - her ikisi de arka planda iş parçacığında, ardından kullanıcı arabirimi ListView'ü yenilemek için bilgilendirilsin. Bunu genellikle IntentService ile yapıyorum, ancak RoboSpice daha az yazıyor.
Yar

@yar uzun süren bir işlemse amaç hizmetini kullanabilirsiniz. Ayrıca asynctask kullanabilirsiniz, ancak yalnızca kısa bir süre için. Bir iş parçacığı oluşturabilir ve tüm işlerinizi orada yapabilirsiniz. Uzun süredir robospice kullanmıyorum. Volley gibi başka ağ kitaplıkları da var ...
Raghunandan

Tamam teşekkürler. Robospice kullanmayı düşündüm, ancak ihtiyaçlarım için çok iyi (esnek) değil gibi görünüyor. IntentService'i uzun süre başarıyla kullanıyorum.
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
StackOverflow'a hoş geldiniz. İçlerinde yalnızca kod bulunan yanıtlar, "düşük kaliteli" oldukları için silinmek üzere işaretlenme eğilimindedir. Lütfen soruları cevaplamak için yardım bölümünü okuyun ve ardından Cevabınıza yorum eklemeyi düşünün.
Graham

0

İpliği önceden farklı kodlarla çalıştırmanız gerekiyorsa, işte örnek:

dinleyici:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

Konu Sınıfı

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

Farklı kodlar çalıştırın:

  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();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.