จัดการ Background Services ใน Android O ด้วย Firebase JobDispatcher

Jirawatee
🔥Firebase Thailand
3 min readApr 19, 2017

--

จากที่ทีม Android ได้ปล่อย Android O Developer Preview 1 ออกมาแล้ว นอกจาก features ใหม่ๆแล้ว ในเวอร์ชันนี้ทีม Android ก็โฟกัสไปที่เรื่องของการปรับปรุง Performance เป็นพิเศษ ซึ่งเป็นสิ่งที่นักพัฒนาก็ต้องปรับปรุงแอพให้เข้ากับการทำงานของ Android O เช่นกัน และในบทความนี้จะมาพูดถึงเรื่อง Background Execution Limits โดยพุ่งเป้าไปที่ Service

แต่ผมแนะนำให้อ่านเรื่อง Background Execution Limits ที่บทความของพี่หนูเนยก่อนจะดีมาก

Service

Service เป็นส่วนประกอบหนึ่งใน Android โดยหน้าที่ของมันคือช่วยให้เราสามารถทำงานบางอย่างที่ต้องใช้เวลาใน background ได้(long-running background operations) ซึ่งแน่นอนว่าการทำงานใน background ก็จะต้องใช้ memory และ battery ควบคู่กันไป ในอุดมคติเมื่อแอพมี service ที่ทำงานใน background เสร็จก็ควรจะ stop service นั้นไป แต่ในความเป็นจริงบางแอพก็มีการทำงานใน background แบบไม่มีลิมิตชีวิตเกินร้อย และถ้าในเครื่องของเรามีแอพประเภทนี้หลายๆแอพ ก็ย่อมส่งผลต่อการใช้งานบน foreground(หน่วง, lack) ด้วยเช่นกัน และนั่นคือสาเหตุหนึ่งที่ทำให้ battery หมดไปก่อนวัยอันควร

Service ใน Android O

เพื่อยืดอายุ battery ดังนั้น service จะสามารถทำงานต่อไปได้ไม่กี่นาที(ไม่ได้ระบุจำนวนนาทีแน่ชัด) หลังจากแอพเข้าสู่สถานะ background คือหลังจากไม่กี่นาทีที่ว่า service ต่างๆจะถูก shutdown แบบอัตโนมัติ เหมือนการ Service.stopSelf()

Background Service Limitations จะเป็นผลเมื่อแอพ target ที่ Android level 26 เป็นต้นไป

ทางออกที่จะให้ service ทำงานต่อใน background

ทางออกแรก(ให้ออกทางเข้า)

ให้เอา service ใน background ขึ้นมาประมวลผลใน foreground แทน โดยใช้ ongoing notification ในการแสดงผลการทำงานให้ผู้ใช้ทราบ เช่น การอัพโหลด, ดาวน์โหลด หรือ การเล่นเพลง เป็นต้น

ทางออกที่สอง

การกำหนดเวลา(Scheduling)ให้ service ทำงาน หลักการคือจะรวม service จากแอพต่างๆมาทำงานพร้อมกันตามช่วงเวลา เพื่อลดการทำงานตลอดเวลาของเครื่องนั่นเอง โดยขอเสนอ 2 วิธี ซึ่งขึ้นอยู่กับ minSdkVersion ที่แอพเรารองรับ

  • Job Scheduler API รองรับ minSdkVersion ตั้งแต่ 21(Lollipop)
  • Firebase JobDispatcher รองรับ minSdkVersion ตั้งแต่ 9(Gingerbread)

Firebase JobDispatcher

ณ วันที่เขียนบทความ เชื่อว่าแอพส่วนมากยังรองรับ minSdkVersion ที่ต่ำกว่า 21 ดังนั้นเราจะมาทำความรู้จัก Firebase JobDispatcher กัน

Firebase JobDispatcher เป็น open-source library ที่ใช้กำหนดเวลาทำงานจาก Google Play Services API(ตามรอบการทำงานของ Google Play Services แค่นี้ก็ประหยัด battery ละ) ซึ่งถูกพัฒนาต่อมาจาก GCMNetworkManager

คราวนี้เรามาลองพัฒนากันดีกว่า เริ่มต้น New Project ใน Android Studio โดยกำหนด minSdkVersion ไม่ต่ำกว่า 9 จากนั้นก็ import dependency เข้ามาเลย

compile 'com.firebase:firebase-jobdispatcher:0.8.5'

ในกรณีที่ project มี dependency “com.google.android.gms:play-services-gcm” ตัวนี้ให้ import ตัวนี้แทน

compile 'com.firebase:firebase-jobdispatcher-with-gcm-dep:0.8.5'

แล้วก็ไปสร้าง class ขึ้นมา ตัวอย่างผมสร้าง class ชื่อ MyService แล้วให้ extend ด้วย JobService เมื่อ extend เรียบร้อย ให้ทำการ implement ตัว override method มา จะได้ onStartJob และ onStopJob ซึ่งในตัวอย่างนี้ผมได้แสดง date และ time ใน debug log ออกมา

import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService;
import java.text.DateFormat;
import java.util.Date;

public class MyService extends JobService{
@Override
public boolean onStartJob(JobParameters jobParameters) {
String currentDateTime = DateFormat.getDateTimeInstance().format(new Date());
Log.d("CURRENT", currentDateTime);
return false;
}

@Override
public boolean onStopJob(JobParameters jobParameters) {
return false;
}
}

เมื่อได้คลาส MyService มาแล้วก็ไปประกาศ service ใน AndroidManifest.xml ตามนี้

<service android:name=".MyService" android:exported="false">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
</intent-filter>
</service>

เอาหละ กลับมาที่ MainActivity.java กัน ใน onCreate ให้เราสร้าง object ของ FirebaseJobDispatcher ขึ้นมา

FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));

ถัดไปก็สร้าง Job โดยเราสามารถตั้งค่าต่างๆได้เพียบ

Job myJob = dispatcher.newJobBuilder()
// เลือก service ที่ต้องการให้ทำงาน
.setService(MyService.class)
// ตั้งค่า unique id ให้กับ job
.setTag("MyService")
// ให้ทำซ้ำเรื่อยๆ
.setRecurring(true)
// ให้เริ่มทำงานตั้งแต่ 0 ถึง 60 วินาที (คู่กับ setRecurring)
.setTrigger(Trigger.executionWindow(0, 60))
// จะให้ job นี้อยู่จนกว่าจะ boot เครื่องใหม่
.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
// ไม่ overwrite job ที่ชื่อ tag เดียวกัน
.setReplaceCurrent(false)
// จะทำงานต่อเมื่อเชื่อมต่อ network ได้
.setConstraints(Constraint.ON_ANY_NETWORK)
// retry เมื่อ fail
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)

.build();

สุดท้ายก็สั่ง schedule() หรือ mustSchedule() เพื่อเริ่มทำงาน ทั้งสองตัวต่างกันนิดเดียวตรงนี้ mustSchedule() จะทำงานได้ แม้พบ error ที่ไม่ร้ายแรง

dispatcher.mustSchedule(myJob);

เต็มๆ ประมาณนี้

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(this));

Job myJob = dispatcher.newJobBuilder()
.setService(MyService.class)
.setTag("MyService")
.setRecurring(true)
.setTrigger(Trigger.executionWindow(0, 60))
.build();

dispatcher.mustSchedule(myJob);
}
}
ตัวอย่าง debug log

สำหรับการยกเลิก Job แบบ manual นั้นสามารถทำได้ทั้งแบบ ยกเลิกด้วย tag และยกเลิก Job ทั้งหมด

// Cancel single job
dispatcher.cancel("MyService");

// Cancel all jobs
dispatcher.cancelAll();

ลองโหลด sample code ตัวอย่างไปเล่นกันดูนะครับ

Firebase Cloud Messaging(FCM) ใน Android O

สำหรับท่านที่ใช้ Data Messages ในการ Trigger ให้ทำงานบางอย่างใน background ผ่าน FCM Callbacks ทั้ง onMessageReceived() และ onTokenRefresh() เช่น sync database หรือ ดาวน์โหลดไฟล์ ใน Android O จะการันตีระยะเวลาที่ปล่อยให้ทำงานแค่ 10 วินาที ดังนั้นหากคุณพิจารณาแล้วว่างานที่ทำต้องใช้เวลาเกินกว่า 10 วินาที คุณสามารถใช้ Firebase JobDispatcher เพื่อการันตีความสำเร็จของงานได้(ขายของนิสนึง)

บทสรุป

สำหรับการ target Android O เรื่อง Background Execution Limits ทั้ง Background Service Limitations และ Broadcast Limitations น่าจะเป็นเรื่องใหญ่สำหรับนักพัฒนา Android และเมื่อคุณอ่านบทความเรื่อง Firebase JobDispatcher มาถึงตรงนี้ เพราะผมเชื่อว่าตอนนี้คุณก็มีทางออกให้กับงาน background ของคุณแล้ว หวังว่าสิ่งที่เอามาฝากจากการไปร่วมงาน Android O Partner Lab จะช่วยให้ทุกท่านพัฒนาแอพให้รองรับ Android O ก่อนการเปิดตัวอย่างเป็นทางการ แล้วพบกันใหม่ชาวพี่น้องชาวไทย

--

--

Jirawatee
🔥Firebase Thailand

Technology Evangelist at LINE Thailand / Google Developer Expert - 🔥Firebase