Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> ระบบ >> Android

Android Proto DataStore:คุ้มค่าที่จะเปลี่ยนจาก SharedPreferences หรือไม่

Android Proto DataStore:คุ้มค่าที่จะเปลี่ยนจาก SharedPreferences หรือไม่

เมื่อไม่กี่ปีก่อน Google ได้ประกาศ DataStore ซึ่งมาแทนที่ SharedPreferences ที่พยายามและเป็นจริง

หากคุณใช้หรือเคยใช้ SharedPreferences ในแอปพลิเคชันของคุณ คุณอาจกำลังคิดที่จะเปลี่ยน แต่เช่นเดียวกับทุกสิ่งทุกอย่าง คำถามหลักก็คือ:ต้นทุนในการพัฒนาจะเป็นอย่างไร

การใช้ DataStore มีประโยชน์มากมาย แต่จะมีเฉพาะ Proto DataStore เท่านั้น ช่วยให้คุณสามารถบันทึกวัตถุในขณะที่ให้ความปลอดภัยประเภท

หากคุณดูเอกสารประกอบของ Proto DataStore คุณจะพบว่าเอกสารนี้ค่อนข้างล้าสมัยและขาดขั้นตอนสำคัญบางประการเมื่อใช้งาน นั่นคือเหตุผลว่าทำไมในบทความนี้ เราจะอธิบายวิธีการรวม Proto DataStore เข้ากับแอปพลิเคชันของคุณ และแสดงให้เห็นว่าการใช้งานมันไม่ยุ่งยากมากนัก

DataStore คืออะไร

Jetpack DataStore มีสองรูปแบบ:

  • การตั้งค่า DataStore
  • โปรโตดาต้าสโตร์

เราจะไม่พูดถึงเรื่องแรก เนื่องจากมีความคล้ายคลึงกับ SharedPreferences และข้อเท็จจริงที่ได้รับการกล่าวถึงอย่างกว้างขวาง ตอนนี้เรามาทำความเข้าใจว่า Proto ใน Proto DataStore หมายถึงอะไร

Proto คือชื่อที่ Google เลือกให้เป็นตัวแทน Protocol Buffers สิ่งเหล่านี้เป็นกลไก (ของ Google) ที่ช่วยคุณจัดเรียงข้อมูลที่มีโครงสร้างเป็นอนุกรม ไม่ใช่การเขียนโค้ดเฉพาะภาษา และโดยทั่วไป คุณจะกำหนดประเภทของข้อมูลที่คุณต้องการใช้งาน จากนั้นโค้ดจะถูกสร้างขึ้นเพื่อช่วยให้คุณอ่านและเขียนข้อมูลของคุณ

✋ เราจะใช้เวอร์ชัน Proto 3 ในบทความนี้

คำจำกัดความนั้นมีลักษณะอย่างไร

message MyItem {
 string itemName = 1;
 int32 itemId = 2;
}

ขั้นแรก คุณกำหนดออบเจ็กต์ด้วยคีย์เวิร์ดข้อความ ภายในนั้น คุณจะแสดงรายการฟิลด์ที่เกี่ยวข้องกับออบเจ็กต์นั้น ตัวเลขที่ท้ายแต่ละฟิลด์ใช้เพื่อระบุฟิลด์นั้น และ ไม่สามารถเปลี่ยนแปลงได้เมื่อตั้งค่าแล้วและมีการใช้ออบเจ็กต์ .

แต่จะเกิดอะไรขึ้นถ้าเราต้องการให้มีหลายอ็อบเจ็กต์ในไฟล์ .proto ของเรา? สมมติว่าวัตถุมีความสัมพันธ์กัน คุณสามารถทำได้โดยการเพิ่มวัตถุข้อความเพิ่มเติม:

message MyItem {
 string itemName = 1;
 int32 itemId = 2;
}
message MyListOfItems {
 repeated MyItem items = 1;
}

โปรดสังเกตว่าด้านบนเราได้เพิ่มวัตถุข้อความอื่นที่อาศัยวัตถุ MyItem ที่กำหนดไว้ข้างต้น หากคุณต้องการกำหนดรายการวัตถุ คุณต้องใช้ ซ้ำ คำสำคัญ.

วิธีการตั้งค่า Proto DataStore

ในการเริ่มต้น คุณจะต้องเพิ่มการขึ้นต่อกันต่อไปนี้ให้กับ build.gradle ระดับแอปพลิเคชันของคุณ:

 implementation "androidx.datastore:datastore-preferences:1.0.0"
 implementation "com.google.protobuf:protobuf-javalite:3.18.0"

จากนั้น คุณจะต้องสร้างไดเร็กทอรีโปรโตภายในโปรเจ็กต์ของคุณ ไดเร็กทอรีนี้จำเป็นต้องเป็นไดเร็กทอรีพี่น้องของโฟลเดอร์ Java ในโครงสร้างโปรเจ็กต์ของคุณ

ภายในไดเร็กทอรี proto คุณจะต้องสร้างไฟล์ .proto ไฟล์นี้มีหน้าที่สร้างประเภทข้อมูลที่คุณต้องการเก็บไว้ใน Proto DataStore

Android Proto DataStore:คุ้มค่าที่จะเปลี่ยนจาก SharedPreferences หรือไม่

ภายในไดเร็กทอรี proto ให้สร้างไฟล์ที่มีนามสกุล .proto ไฟล์ .proto ของเราจะเก็บวัตถุที่แสดงรายการสิ่งที่ต้องทำ (อะไรอีก) ดังนั้นเราจะเรียกไฟล์ของเราว่า todo.proto และจะมีลักษณะดังนี้:

syntax = "proto3";
option java_package = "com.yourPackageName.todo";
option java_multiple_files = true;
message TodoItem {
 string itemId = 1;
 string itemDescription = 2;
}
message TodoItems {
 repeated TodoItem items = 1;
}

โปรดสังเกตว่าเรากำหนดวัตถุข้อความสองรายการอย่างไร:

  1. TodoItem – ที่กำหนดรายการสิ่งที่ต้องทำ
  2. TodoItems – ที่กำหนดรายการของออบเจ็กต์ TodoItem

ถัดไป สร้างโปรเจ็กต์เพื่อให้คลาสถูกสร้างขึ้นสำหรับ TodoItem และ TodoItems

หลังจากที่วัตถุข้อมูลของเราถูกกำหนดแล้ว เราจำเป็นต้องสร้างคลาสเพื่อทำให้เป็นอนุกรม คลาสนี้จะบอก DataStore ถึงวิธีการอ่าน/เขียนอ็อบเจ็กต์ของเรา

// 1
object TodoItemSerializer: Serializer<TodoItems> {
 // 2
 override val defaultValue: TodoItems = TodoItems.getDefaultInstance()
 // 3
 override suspend fun readFrom(input: InputStream): TodoItems {
 try {
 return TodoItems.parseFrom(input)
 } catch (exception: InvalidProtocolBufferException) {
 throw CorruptionException("Cannot read proto.", exception)
 }
 }
 // 3
 override suspend fun writeTo(
 t: TodoItems,
 output: OutputStream
 ) = t.writeTo(output)
}

มาทบทวนสิ่งที่เรามีในชั้นเรียนนี้:

  1. เมื่อเราประกาศคลาส เราจำเป็นต้องใช้ Serializer เชื่อมต่อกับวัตถุของเราเป็นประเภท (T)
  2. เรากำหนดค่าเริ่มต้นสำหรับซีเรียลไลเซอร์ในกรณีที่ไฟล์ไม่ได้ถูกสร้างขึ้น
  3. เราแทนที่เมธอด readFrom/writeTo และเราตรวจสอบให้แน่ใจว่าออบเจ็กต์ของเราเป็นประเภทข้อมูลอยู่ที่นั่น

เรามีไฟล์ .proto พร้อมด้วยประเภทข้อมูลและซีเรียลไลเซอร์ ดังนั้นขั้นตอนต่อไปคือการสร้างอินสแตนซ์ DataStore เราทำสิ่งนี้โดยใช้ตัวแทนคุณสมบัติที่สร้างโดย dataStore ซึ่งจำเป็นต้องระบุชื่อไฟล์ที่จะบันทึกข้อมูลของเราและคลาสซีเรียลไลเซอร์ของเรา (ซึ่งเรากำหนดไว้ข้างต้น)

private const val DATA_STORE_FILE_NAME = "todo.pb"
private val Context.todoItemDatastore: DataStore<TodoItems> by dataStore(
 fileName = DATA_STORE_FILE_NAME,
 serializer = TodoItemSerializer,
)

โค้ดชิ้นนี้จะต้องอยู่ที่ด้านบนของคลาสที่คุณเลือก เหนือคำจำกัดความของคลาสนั้น นั่นคือ:

private const val DATA_STORE_FILE_NAME = "todo.pb"
private val Context.todoItemDatastore: DataStore<TodoItems> by dataStore(
 fileName = DATA_STORE_FILE_NAME,
 serializer = TodoItemSerializer,
)
class YourClassName {
}

เพื่อเข้าถึงวัตถุนี้ในส่วนที่เหลือของแอปพลิเคชันของเรา เราจำเป็นต้องใช้บริบท ตัวอย่างคือการใช้บริบทของแอปพลิเคชันในคลาส viewmodel ของคุณ:

class MyViewModel(application: Application): AndroidViewModel(application) {
 val todoDataStore = application.todoItemDataStore
 //...
}

วิธีใช้ Kotlin Flow

ตอนนี้เราได้ผ่านการตั้งค่าทุกสิ่งที่เราต้องการสำหรับ DataStore ของเราแล้ว เราจะหารือกันว่าเราจะโต้ตอบกับมันอย่างไร เราจะต้องการอ่านและเขียนข้อมูลไปยัง/จากข้อมูลนั้น แต่วิธีที่เราสามารถทำได้นั้นแตกต่างไปจากสิ่งที่คุณอาจคุ้นเคยจาก SharedPreferences

DataStore ที่เรากำหนดไว้ข้างต้นมีฟิลด์ข้อมูลที่เปิดเผยโฟลว์สำหรับคุณสมบัติที่เรากำหนดไว้ใน DataStore ของเรา

🚰 หากคุณไม่คุ้นเคยกับกระแส นี่เป็นจุดเริ่มต้นที่ดี

val todoItemFlow: Flow<TodoItems> = todoItemDataStore.data
 .catch { exception ->
 if (exception is IOException) {
 emit(TodoItems.getDefaultInstance())
 } else {
 throw exception
 }
 }

โค้ดด้านบนแสดงวิธีที่คุณสามารถกำหนด Flow ที่รวบรวมข้อมูลจาก Proto DataStore มีการเพิ่ม catch block ในกรณีที่มีข้อยกเว้นเกิดขึ้น คุณสามารถวางตรรกะนี้ในคลาสที่คุณกำหนด DataStore ของคุณและใช้มันเช่นนั้นในโมเดลมุมมองของคุณ:

val todoItemsFlow: LiveData<TodoItems> = todoItemsRepository.todoItemFlow.asLiveData()

สังเกตว่าเราแปลง Flow เป็น LiveData อย่างไร เราทำสิ่งนี้ด้วยเหตุผลสองประการ:

  1. โฟลว์สามารถคงความเคลื่อนไหวได้โดยไม่คำนึงถึงกิจกรรม/ส่วนที่ใช้งาน
  2. LiveData เป็นสิ่งที่นักพัฒนาหลายคนคุ้นเคย และฉันต้องการทำให้ตัวอย่างนี้เข้าถึงได้ง่ายที่สุด

เพื่อให้สามารถทำเช่นนี้ได้ คุณจะต้องเพิ่มการพึ่งพาต่อไปนี้ให้กับไฟล์ build.gradle ของคุณ:

implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"

ในคลาสกิจกรรม/แฟรกเมนต์ของคุณ คุณสามารถสังเกตข้อมูลสดนี้ได้ดังนี้:

myViewModel.todoItemFlow.observe(LocalLifecycleOwner.current) { todoItems ->
 // Logic to access data from DataStore
 }

ทำไมและเมื่อใดจึงควรใช้ DataStore

หลังจากรีวิวทุกอย่างแล้ว ก็ถึงเวลามาพูดถึงช้างในห้องกัน คุณควรใช้ DataStore (เช่น Preferences หรือ Proto) ในโปรเจ็กต์ที่มีอยู่หรือโปรเจ็กต์ถัดไปไหม

ในความคิดของฉัน คำตอบควรเป็น ใช่ . นอกเหนือจากข้อเท็จจริงที่ว่า Google กำลังย้ายออกจาก SharedPreferences แล้ว DataStore ยังมอบสิทธิประโยชน์มากมายที่จะช่วยให้คุณมุ่งเน้นไปที่แอปพลิเคชันของคุณ ไม่ใช่ความคงอยู่ของข้อมูลของคุณ

ปลอดภัยในการโต้ตอบกับ DataStore จากเธรด UI (เนื่องจากจะย้ายงานไปที่ I/O โดยอัตโนมัติ) และจะบังคับให้คุณใช้ Flow (หากคุณยังไม่ได้ทำ) และเพลิดเพลินกับสิทธิประโยชน์ทั้งหมดภายใน นอกจากนี้ยังมีตัวเลือกในการโยกย้ายจาก SharedPreferences ไปยัง Preferences DataStore ได้อย่างง่ายดาย

หากคุณกำลังใคร่ครวญที่จะใช้ Room แทน Proto DataStore นั่นก็ขึ้นอยู่กับกรณีการใช้งานของคุณ หากปริมาณข้อมูลที่คุณจะบันทึก (หรือคงอยู่) ค่อนข้างน้อยและไม่จำเป็นต้องอัปเดตบางส่วน Proto DataStore คือคำตอบที่เหมาะสม หากคุณมีชุดข้อมูลขนาดใหญ่หรือชุดที่อาจซับซ้อน คุณควรเลือกใช้ห้องแทน

หากคุณต้องการดูว่าโค้ดทั้งหมดนี้มีลักษณะอย่างไรในแอปพลิเคชัน คุณสามารถดูได้ที่นี่:

หากคุณต้องการอ่านบทความอื่นๆ ที่ฉันเขียน คุณสามารถดูได้ที่นี่:

ขอบคุณสำหรับการอ่าน!

อ้างอิง:

  • เอกสารบัฟเฟอร์โปรโตคอล (โปรโตคอล 3)
  • การทำงานกับ Proto DataStore Codelab
  • เอกสาร DataStore

เรียนรู้การเขียนโค้ดฟรี หลักสูตรโอเพ่นซอร์สของ freeCodeCamp ช่วยให้ผู้คนมากกว่า 40,000 คนได้งานในตำแหน่งนักพัฒนา เริ่มต้น