Android에서 되풀이 작업 예약 서버로 보내는 채팅 기반

앱이 포 그라운드에있는 한 전용 서버로 프레즌스를 보내는 반복적 인 작업이있는 앱을 디자인하고 있습니다.

웹 검색에서 몇 가지 다른 접근 방식을 보았고이를 수행하는 가장 좋은 방법이 무엇인지 알고 싶었습니다.

서버 호출을 예약하는 가장 좋은 방법은 무엇입니까?

내가 본 옵션은 다음과 같습니다.

  1. 타이머 .

  2. ScheduledThreadPoolExecutor .

  3. 서비스 .

  4. AlarmManager가있는 BroadcastReciever .

당신의 의견은 무엇입니까?

편집 :
이것이 필요한 이유는 모든 사용자 작업을 원격 서버로 보내는 채팅 기반 앱 때문입니다.
즉, 사용자가 메시지를 입력하고, 사용자가 메시지를 읽고, 사용자가 온라인 상태이며, 사용자가 오프라인 상태입니다.

이것은 매 간격마다 내가하고있는 일을 서버에 보내야한다는 것을 의미합니다. 다른 사람들과 대화방을 열었 기 때문에 그들은 내가하고있는 일을 알아야합니다.

whatsapp 메시지 피드백 메커니즘과 유사합니다.
메시지가 전달 된 것 같습니다.

수정 # 2 : Android 교육 의 vitals 섹션 에서 읽을 수있는 것처럼 배터리 소모 문제를 방지하기 위해
거의 항상 JobSchedulerAPI (또는 FirebaseJobDispatcher하위 API)를 통해 반복 작업을 예약해야합니다.

수정 # 3 :
FirebaseJobDispatcher는 더 이상 사용되지 않으며 JobScheduler의 기능도 통합 하는 Workmanager 로 대체되었습니다 .



답변

확실하지는 않지만 내 지식에 따라 내 의견을 공유합니다. 내가 틀렸다면 항상 최선의 대답을 받아들입니다.

알람 관리자

알람 관리자는 알람 수신기의 onReceive()방법이 실행 되는 동안 CPU wake lock을 유지합니다 . 이렇게하면 방송 처리를 마칠 때까지 전화기가 잠들지 않습니다. 일단 onReceive()반환, 알람 Manager는이 웨이크 잠금을 해제합니다. 이것은 경우에 따라 onReceive()방법이 완료 되는 즉시 전화기가 절전 모드로 전환됨을 의미합니다 . 알람 수신기가를 호출 Context.startService()하면 요청한 서비스가 시작되기 전에 전화기가 절전 모드로 전환 될 수 있습니다. 이를 방지하려면 BroadcastReceiverService서비스를 사용할 수있을 때까지 전화가 계속 실행되도록하기 위해 별도의 웨이크 잠금 정책을 구현해야합니다.

참고 : 알람 관리자는 애플리케이션이 현재 실행되고 있지 않더라도 특정 시간에 애플리케이션 코드를 실행하려는 경우를위한 것입니다. 정상적인 타이밍 작업 (틱, 타임 아웃 등)의 경우 Handler를 사용하는 것이 더 쉽고 효율적입니다.

시간제 노동자

timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {

        synchronized public void run() {

            \\ here your todo;
            }

        }}, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1));

Timer에 의해 해결되는 몇 가지 단점이 있습니다 ScheduledThreadPoolExecutor. 그래서 최선의 선택이 아닙니다

ScheduledThreadPoolExecutor .

java.util.Timer또는 ScheduledThreadPoolExecutor(선호)를 사용 하여 백그라운드 스레드에서 정기적으로 발생하는 작업을 예약 할 수 있습니다.

후자를 사용한 샘플은 다음과 같습니다.

ScheduledExecutorService scheduler =
    Executors.newSingleThreadScheduledExecutor();

scheduler.scheduleAtFixedRate
      (new Runnable() {
         public void run() {
            // call service
         }
      }, 0, 10, TimeUnit.MINUTES);

그래서 나는 선호했다 ScheduledExecutorService

그러나 응용 프로그램이 실행되는 동안 업데이트가 발생하면 Timer다른 답변에서 제안한 것처럼를 사용할 수 있거나 최신 ScheduledThreadPoolExecutor. 응용 프로그램이 실행 중이 아닌데도 업데이트되는 경우 AlarmManager.

알람 관리자는 애플리케이션이 현재 실행되고 있지 않더라도 특정 시간에 애플리케이션 코드를 실행하려는 경우를위한 것입니다.

응용 프로그램이 꺼져있을 때 업데이트 할 계획이라면 10 분마다 한 번 씩은 매우 자주 발생하므로 전력을 너무 많이 소비 할 수 있습니다.


답변

시간제 노동자

javadocs 에서 언급했듯이 ScheduledThreadPoolExecutor를 사용하는 것이 좋습니다.

ScheduledThreadPoolExecutor

사용 사례에 여러 작업자 스레드가 필요하고 휴면 간격이 작은 경우이 클래스를 사용합니다. 얼마나 작습니까? 글쎄요, 15 분 정도입니다. AlarmManager시작이 시간 간격을 예약하고 작은 수면 간격이 클래스를 사용할 수 있음을 시사하는 것으로 보인다. 마지막 진술을 뒷받침 할 데이터가 없습니다. 직감입니다.

서비스

서비스는 VM에 의해 언제든지 종료 될 수 있습니다. 반복 작업에 서비스를 사용하지 마십시오. 반복되는 작업은 서비스를 시작할 수 있으며 이는 완전히 다른 문제입니다.

AlarmManager가있는 BroadcastReciever

더 긴 수면 간격 (> 15 분)의 경우 이것이 갈 길입니다. AlarmManager이미 일정 AlarmManager.INTERVAL_DAY이 잡힌 후 며칠 후에 작업을 트리거 할 수 있음을 나타내는 상수 ( )가 있습니다. 또한 코드를 실행하기 위해 CPU를 깨울 수도 있습니다.

타이밍 및 작업자 스레드 요구 사항에 따라 이러한 솔루션 중 하나를 사용해야합니다.


답변

나는 이것이 오래된 질문이며 답변을 받았지만 누군가에게 도움이 될 수 있음을 알고 있습니다. 당신의activity

private ScheduledExecutorService scheduleTaskExecutor;

onCreate

  scheduleTaskExecutor = Executors.newScheduledThreadPool(5);

    //Schedule a task to run every 5 seconds (or however long you want)
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            // Do stuff here!

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Do stuff to update UI here!
                    Toast.makeText(MainActivity.this, "Its been 5 seconds", Toast.LENGTH_SHORT).show();
                }
            });

        }
    }, 0, 5, TimeUnit.SECONDS); // or .MINUTES, .HOURS etc.

답변

인용 일정 반복 알람 – 무역 오프의 이해 문서를 :

앱 수명 이외의 작업을 트리거하는 일반적인 시나리오는 데이터를 서버와 동기화하는 것입니다. 반복 알람을 사용하고 싶을 수있는 경우입니다. 그러나 앱의 데이터를 호스팅하는 서버를 소유하고있는 경우 동기화 어댑터와 함께 Google 클라우드 메시징 (GCM)을 사용하는 것이 AlarmManager보다 나은 솔루션입니다. 동기화 어댑터는 AlarmManager와 동일한 예약 옵션을 모두 제공하지만 훨씬 더 많은 유연성을 제공합니다.

따라서이를 기반으로 서버 호출을 예약하는 가장 좋은 방법은 동기화 어댑터 와 함께 Google 클라우드 메시징 (GCM)사용하는 것 입니다.


답변

사용자가 반복하고 싶은 작업을 시간 작업에 생성하고 Custom TimeTask run () 메서드를 추가합니다. 성공적으로 되풀이됩니다.

 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Timer;
 import java.util.TimerTask;

 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.TextView;
 import android.app.Activity;
 import android.content.Intent;

 public class MainActivity extends Activity {

     CheckBox optSingleShot;
     Button btnStart, btnCancel;
     TextView textCounter;

     Timer timer;
     MyTimerTask myTimerTask;

     int tobeShown = 0  ;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    optSingleShot = (CheckBox)findViewById(R.id.singleshot);
    btnStart = (Button)findViewById(R.id.start);
    btnCancel = (Button)findViewById(R.id.cancel);
    textCounter = (TextView)findViewById(R.id.counter);
    tobeShown = 1;

    if(timer != null){
        timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
        //singleshot delay 1000 ms
        timer.schedule(myTimerTask, 1000);
    }else{
        //delay 1000ms, repeat in 5000ms
        timer.schedule(myTimerTask, 1000, 1000);
    }

    btnStart.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View arg0) {


            Intent i = new Intent(MainActivity.this, ActivityB.class);
            startActivity(i);

            /*if(timer != null){
                timer.cancel();
            }

            //re-schedule timer here
            //otherwise, IllegalStateException of
            //"TimerTask is scheduled already"
            //will be thrown
            timer = new Timer();
            myTimerTask = new MyTimerTask();

            if(optSingleShot.isChecked()){
                //singleshot delay 1000 ms
                timer.schedule(myTimerTask, 1000);
            }else{
                //delay 1000ms, repeat in 5000ms
                timer.schedule(myTimerTask, 1000, 1000);
            }*/
        }});

    btnCancel.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
            if (timer!=null){
                timer.cancel();
                timer = null;
            }
        }
    });

}

@Override
protected void onResume() {
    super.onResume();

    if(timer != null){
        timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
        //singleshot delay 1000 ms
        timer.schedule(myTimerTask, 1000);
    }else{
        //delay 1000ms, repeat in 5000ms
        timer.schedule(myTimerTask, 1000, 1000);
    }
}


@Override
protected void onPause() {
    super.onPause();

    if (timer!=null){
        timer.cancel();
        timer = null;
    }

}

@Override
protected void onStop() {
    super.onStop();

    if (timer!=null){
        timer.cancel();
        timer = null;
    }

}

class MyTimerTask extends TimerTask {

    @Override
    public void run() {

        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat =
                new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
        final String strDate = simpleDateFormat.format(calendar.getTime());

        runOnUiThread(new Runnable(){

            @Override
            public void run() {
                textCounter.setText(strDate);
            }});
    }
}

}