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
안녕하세요. 시도한 것의 예로 코드를 게시 할 수 있습니까? 백그라운드 스레드에서 코드를 실행하는 방법은 여러 가지가 있지만 UI 구성 요소에 액세스하는 경우 runOnUiThread()메서드 를 사용하여 UI 스레드에서 액세스해야합니다 .
Alex Wiese

3
서비스를 사용하지 않는 특별한 이유가 있습니까
DeltaCap019

이것은 권장되지 않습니다. 계속 작동하면 장치 배터리가 방전됩니다.
HelmiB

코드를 보냈습니다.
user2082987

나는 그것을 서비스에서 사용하려고 시도했지만 동일한 레코드를 여러 번 보냅니다.
user2082987

답변:


379

필요한 경우 :

  1. 백그라운드 스레드에서 코드 실행

  2. UI를 터치 / 업데이트하지 않는 코드 실행

  3. 완료하는 데 최대 몇 초가 걸리는 (짧은) 코드를 실행하십시오.

그런 다음 AsyncTask를 사용하는 다음의 깨끗하고 효율적인 패턴을 사용하십시오.

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

10
참고 : API 레벨 11이 필요
friederbluemle

9
왜 더 가벼운 다음을 사용하지 않겠습니까? new Thread (new Runnable () {@Override public void run () {// background code}}). start ();
수상 경력 :

3
메모리 누수가 발생할 가능성이 있습니까?
Hilfritz

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)는 서비스가 종료되면 서비스가 자동으로 다시 시작되도록 Android에서 제공하는 옵션입니다.

멀티 프로세싱과 멀티 스레딩의 차이점을 기억 하십니까? 서비스는 백그라운드 프로세스입니다. 서비스로드를 피하기 위해.

단일 명령문에서 백그라운드 계속 작업을 실행하려면 StickyService를 시작하고 이벤트 기반의 서비스에서 스레드를 실행해야합니다.


UI 스레드를 업데이트하기 위해 초당 리스너의 값을 가져 오는 동안 백그라운드에서 사용자 정의 SignalStrengthListener를 평균 20 분 동안 실행하는 데이 방법을 사용 하시겠습니까? 더 자세한 내용은 다음과 같습니다. stackoverflow.com/questions/36167719/…
JParks 2016 년

'isRecursionEnable = true'를 설정하면 프로세스가 어떻게 다시 실행됩니까? 그런 다음 'runInBackground ()'에 대한 'run'메소드 내부를 호출하면 함수 시작 부분에 if 문이 어떻게 입력되지 않습니까?
미키

23

백그라운드에서 지속적으로 일부 코드를 실행하고 싶습니다. 나는 서비스에서 그것을하고 싶지 않습니다. 다른 방법이 있습니까?

당신이 찾고있는 대부분의 메커니즘은 AsyncTask입니다. 백그라운드 스레드에서 백그라운드 프로세스를 수행하도록 직접 지정되었습니다. 또한 주요 이점은 Main (UI) Thread에서 실행되는 몇 가지 방법을 제공하여 작업 진행 상황에 대해 사용자에게 알리거나 백그라운드 프로세스에서 가져온 데이터로 UI를 업데이트하려는 경우 UI를 업데이트 할 수 있다는 것입니다.

여기서 시작하는 방법을 모르는 경우 훌륭한 자습서가 있습니다.

참고 : 또한 그 IntentService와 함께 사용할 수도 ResultReceiver있습니다.


@ user2082987 그래서 시도 했습니까?
Simon Dorociak

asyncTask의 이러한 매개 변수는 혼동됩니다.
user2082987

AsyncTask는 쓰레드를 둘러싼 래퍼 일 뿐이므로 백그라운드에서 애플리케이션을 죽이는 안드로이드 문제를 해결하지 못합니다
Lassi Kinnunen

안녕하세요 @LassiKinnunen 5 년 전 그 답변을 썼습니다. 이제 모든 것이 변경되었으며 메모리 누수가 안전하지 않기 때문에 현재 AsyncTask를 사용하고 있지 않습니다.
Simon Dorociak

예, 나는 사람들이 여전히 구글을 통해 이것을 발견 할 것이라는 것을 알고 있으며 목적이 거의 없거나 전혀없는 경우에도 구글 래퍼를 사용하도록 권장하는 사람들에 대한 많은 의견을 보았습니다. 죄송합니다. 누군가가 2018 년에 답변을 찾고 있다면 원래 질문에 관해서는 서비스를 생성하고 시작하여 사망하지 않을 가능성을 최대화하려는 경우 알림을 사용하여 포 그라운드로 표시하십시오. 실제 장기 실행 프로세스는 처리기 또는 별도의 스레드로 처리 할 수 ​​있습니다. 그들이 실제로 메모리 누수를 안전하게 만들지 않았다는 것을 몰랐습니까?
Lassi Kinnunen

16

간단한 3 라이너

Brandon Rude의 답변 에서 @awardak 의 의견으로 찾은 간단한 방법 :

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

이것이 사용 AsyncTask.execute하는 것 보다 낫거나 어떻게 사용되는지 잘 모르겠지만 우리에게는 효과가있는 것 같습니다. 차이점에 대한 의견을 부탁드립니다.

감사합니다, @awardak !


우리는 handler.post () 메소드를 사용하여 Thread의 run 메소드 내부의 메인 스레드에 다시 게시합니다.
androidXP

2

AsyncTask의 대안은 robospice입니다. https://github.com/octo-online/robospice .

robospice의 특징 중 일부.

1. 백그라운드 백그라운드에서 비동기 적으로 네트워크 요청을 실행합니다 (예 : Spring Android를 사용하는 REST 요청). 결과가 준비되면 UI 스레드에서 앱에 알림을 보냅니다.

2. 강력하게 입력됩니다! POJO를 사용하여 요청하고 요청 결과로 POJO를 얻습니다.

3. 요청에 사용 된 POJO 나 프로젝트에서 사용하는 활동 클래스에 대한 제한이 없습니다.

4. 결과를 캐시합니다 (JSON에서 Jackson과 Gson, Xml 또는 일반 텍스트 파일 또는 ORM Lite를 사용하는 바이너리 파일).

5. 네트워크 요청 결과가 활동중인 경우에만 활동 (또는 기타 상황)에 알립니다.

6. Android AsyncTasks가 UI 스레드에서 활동을 알리는 것과 달리 Android 로더와 같이 메모리 누수가 전혀 없습니다.

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를 새로 고치도록 UI에 알립니다. 나는 보통 IntentService를 사용하지만 RoboSpice는 타이핑이 적습니다.
Yar

@yar는 오래 작동하는 경우 인 텐트 서비스를 사용할 수 있습니다. 또한 asynctask는 짧은 기간 동안 만 사용할 수 있습니다. 스레드를 작성하고 모든 작업을 수행 할 수 있습니다. 나는 오랫동안 robospice를 사용하지 않았습니다. 발리와 같은 다른 네트워킹 라이브러리가 있습니다 ...
Raghunandan

알았어 고마워. Robospice 사용에 대해 생각했지만 내 요구에 너무 유연하지 않은 것 같습니다. 나는 IntentService를 오랫동안 성공으로 사용합니다.
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에 오신 것을 환영합니다. 코드 만있는 답변은 "품질이 낮으므로"삭제 된 것으로 표시되는 경향이 있습니다. 질문에 대한 답변 섹션을 읽고 답변에 해설을 추가하십시오.
Graham

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();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.