การใช้คลาสแอปพลิเคชัน Android เพื่อคงข้อมูล


112

ฉันกำลังทำงานกับแอปพลิเคชัน Android ที่ค่อนข้างซับซ้อนซึ่งต้องใช้ข้อมูลจำนวนมากเกี่ยวกับแอปพลิเคชัน (ฉันจะบอกว่าทั้งหมดประมาณ 500KB - ขนาดใหญ่สำหรับอุปกรณ์เคลื่อนที่หรือไม่) จากสิ่งที่ฉันบอกได้การเปลี่ยนแปลงทิศทางใด ๆ ในแอปพลิเคชัน (ในกิจกรรมเพื่อให้แม่นยำยิ่งขึ้น) ทำให้เกิดการทำลายและการพักผ่อนหย่อนใจของกิจกรรมโดยสิ้นเชิง จากการค้นพบของฉันคลาสแอปพลิเคชันไม่มีวงจรชีวิตที่เหมือนกัน (กล่าวคือสำหรับเจตนาและวัตถุประสงค์ทั้งหมดจะสร้างอินสแตนซ์เสมอ) การจัดเก็บข้อมูลสถานะภายในคลาสแอปพลิเคชันนั้นเหมาะสมหรือไม่แล้วอ้างอิงจากกิจกรรมหรือโดยทั่วไปแล้วจะไม่ใช่วิธีการที่ "ยอมรับได้" เนื่องจากข้อ จำกัด ของหน่วยความจำบนอุปกรณ์เคลื่อนที่ ฉันขอขอบคุณคำแนะนำใด ๆ เกี่ยวกับหัวข้อนี้ ขอบคุณ!


8
โปรดทราบว่าข้อมูลในแอปพลิเคชันของคุณยังคงสามารถลบได้หากแอปของคุณทำงานอยู่เบื้องหลังดังนั้นนี่ไม่ใช่วิธีแก้ปัญหาสำหรับข้อมูลที่มีอยู่ซึ่งคุณต้องการให้สามารถเรียกคืนได้เสมอ เป็นเพียงวิธีการที่ไม่ต้องสร้างวัตถุราคาแพงขึ้นมาใหม่บ่อยๆ
Cheryl Simon

2
มัยรา; ฉันไม่คิดว่าแอปจะ "มักจะ" ถูกลบ (แม้ว่าจะมีคนชี้ให้เห็นในภายหลังในชุดข้อความนี้ว่า "สามารถ" ได้) ฉันอาจจะใช้วิธี "ไฮบริด" บางประเภทในการใช้แอปพลิเคชันเพื่อจัดเก็บและโหลดข้อมูล แต่จากนั้นใช้แอตทริบิวต์ "android: orientation" กับกิจกรรมในไฟล์รายการเพื่อแทนที่พฤติกรรมปกติของ ฉีกและสร้างกิจกรรมใหม่ แน่นอนว่าทั้งหมดนี้ถือว่าแอปพลิเคชันสามารถระบุได้ว่า "เมื่อ" ถูกทำลายเพื่อให้ข้อมูลยังคงอยู่ได้
Dave

คำตอบ:


134

ฉันไม่คิดว่า 500kb จะเป็นเรื่องใหญ่ขนาดนี้

สิ่งที่คุณอธิบายคือวิธีที่ฉันจัดการกับปัญหาการสูญเสียข้อมูลในกิจกรรม ฉันสร้างโกลบอลซิงเกิลในคลาสแอปพลิเคชันและสามารถเข้าถึงได้จากกิจกรรมที่ฉันใช้

คุณสามารถส่งผ่านข้อมูลใน Global Singleton ได้หากมีการใช้งานเป็นจำนวนมาก

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

จากนั้นเรียกใช้ในกิจกรรมใด ๆ โดย:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

ฉันพูดถึงเรื่องนี้ในบล็อกโพสต์ใต้หัวข้อ "Global Singleton"


1
ขออภัยบล็อกโพสต์ที่เป็นปัญหาไม่สามารถใช้ได้ในที่อยู่นั้นอีกต่อไป
mikebabcock

1
ฉันได้ย้ายสิ่งต่างๆไปรอบ ๆ ไซต์ของฉัน จนกว่าจะได้รับการแก้ไขคุณสามารถค้นหาได้ใน archive.org ที่นี่: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny

1
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ฉันเพิ่งเจอปัญหาที่อาจแก้ได้ แต่คลาสนี้จะต้องถูกปฏิเสธในรายการอย่างใดไม่? ฉันไม่สามารถเข้าเรียนในชั้นเรียนได้ดังนั้นรู้สึกว่านี่คือสิ่งที่ฉันขาดหายไป ...
Ziv Kesten

1
@ZivKesten วิธีการเพิ่มชื่อ = แอตทริบิวต์ลงในแท็กแอปพลิเคชันภายในรายการ
MikeC

@mgc ขอบคุณที่ผ่านมาสักพักแล้วและใช่นั่นคือวิธีที่ฉันทำมันออกมาในที่สุดฉันก็สร้างอินสแตนซ์ของคลาสนั้นทุกที่ที่ฉันต้องการโดยให้ getApplicationContext () พร้อมกับแคสต์ในคลาสนี้
Ziv Kesten

57

ผู้ที่นับApplicationอินสแตนซ์ผิด ในตอนแรกอาจดูเหมือนว่าApplicationมีอยู่ตราบเท่าที่กระบวนการแอปทั้งหมดยังคงมีอยู่ แต่นี่เป็นข้อสันนิษฐานที่ไม่ถูกต้อง

ระบบปฏิบัติการอาจฆ่ากระบวนการตามความจำเป็น กระบวนการทั้งหมดแบ่งออกเป็น 5 ระดับของ "ความสามารถในการฆ่า" ที่ระบุไว้ในเอกสารที่ระบุไว้ในเอกสาร

ตัวอย่างเช่นหากแอปของคุณทำงานอยู่เบื้องหลังเนื่องจากผู้ใช้รับสายเรียกเข้าระบบปฏิบัติการอาจ (หรืออาจไม่) ฆ่ากระบวนการของคุณ (ทำลายApplicationอินสแตนซ์ในกระบวนการ) ทั้งนี้ขึ้นอยู่กับสถานะของ RAM .

ฉันคิดว่าวิธีที่ดีกว่าคือการเก็บข้อมูลของคุณไว้ในไฟล์ที่เก็บข้อมูลภายในแล้วอ่านเมื่อกิจกรรมของคุณดำเนินต่อ

อัพเดท:

ฉันได้รับการตอบรับเชิงลบมากมายดังนั้นจึงถึงเวลาเพิ่มคำชี้แจง :) ตอนแรกฉันใช้สมมติฐานที่ผิดว่าสถานะมีความสำคัญมากสำหรับแอป แต่ถ้าแอปของคุณตกลงว่าบางครั้งรัฐจะหายไป (มันอาจจะเป็นภาพบางอย่างที่จะเป็นเพียง reread / redownloaded) Applicationแล้วมันจะตกลงอย่างเต็มที่ที่จะให้มันเป็นสมาชิกของ


14
ถ้าแอพพลิเคชั่นถูกฆ่าใครจะสนล่ะ? แอปพลิเคชันหายไป ตามที่ฉันเข้าใจ Android จะเรียกคืนกระบวนการที่มีหน่วยความจำเช่นกิจกรรม หากกระบวนการที่มีแอปพลิเคชันถูกฆ่า (หาก Android จะทำเช่นนั้น?) นั่นก็เหมือนกับการฆ่าแอป ผู้ใช้จะต้องเปิดแอปอีกครั้งและเมื่อถึงจุดนั้นใครจะสน เป็นอินสแตนซ์ใหม่ของแอปพลิเคชัน
Andrew

14
นี่เป็นเรื่องแปลกใจสำหรับเราในการผลิต เชื่อฉันว่า Android ฆ่ากระบวนการ แต่ขึ้นอยู่กับสถานะ RAM และปัจจัยอื่น ๆ ที่อธิบายไว้ในเอกสารประกอบ มันเป็นฝันร้ายสำหรับเราดังนั้นฉันจึงแบ่งปันประสบการณ์จริงของฉัน เราไม่ได้มีสิ่งนี้ในอีมูเลเตอร์ แต่ในโลกแห่งความเป็นจริงอุปกรณ์บางอย่างมีแอพ 'โอเวอร์โหลด' ดังนั้นการฆ่ากระบวนการเบื้องหลังจึงเป็นสถานการณ์ปกติ ใช่หากผู้ใช้ตัดสินใจที่จะนำแอปขึ้นสู่เบื้องหน้า - ระบบปฏิบัติการจะกู้คืนสแต็กรวมถึงApplicationอินสแตนซ์อย่างไรก็ตามจะไม่มีข้อมูลคงที่ที่คุณไว้วางใจเว้นแต่คุณจะยังคงยืนยัน
Vit Khudenko

2
ฉันคิดว่าฉันอาจจะใช้แนวทางแบบผสมผสาน ฉันรู้แล้วเกี่ยวกับเคล็ดลับรายการเพื่อลบล้างการเปลี่ยนแปลงการวางแนว (ซึ่งมีประโยชน์อื่น ๆ ) เนื่องจากแอปพลิเคชันเป็นเกมฉันไม่แน่ใจว่าการคงข้อมูลระหว่างการเปิดตัวนั้น "สำคัญ" เพียงพอ แม้ว่ามันอาจจะไม่ยากมากนักเนื่องจากข้อมูลส่วนใหญ่สามารถต่ออนุกรมกันได้ (แม้ว่าฉันจะไม่ต้องการทำให้เป็นอนุกรมและไม่ระบุหมายเลขระหว่างการเปลี่ยนทิศทางทุกครั้ง) ฉันขอขอบคุณข้อมูลนี้อย่างแน่นอน ฉันจะไม่บอกว่าสิ่งที่ขึ้นอยู่กับอินสแตนซ์ของแอปนั้น "ผิด" มากขึ้นอยู่กับแอพ :)
Dave

1
@ คุณกำลังสรุปคำตอบของคุณมากเกินไป และแนะนำแนวทางแคบ ๆ ตามสมมติฐานของคุณ ข้อสันนิษฐานที่เป็นเท็จ: ข้อมูลที่เก็บไว้ในตัวแปรคงต้องคงอยู่ตลอดเซสชันของแอป อาจมีกรณีการใช้งานมากมายที่ข้อมูลไม่สำคัญและไม่จำเป็นต้องถูกเก็บรักษาในทันที
Mandar Limaye

2
ฉันมีข้อมูลประมาณ 1mb ที่มีโครงสร้างซับซ้อน Serialize / deserialize อาจทำให้ฉันเสียเวลาถึง 2-3 วินาทีเมื่ออุปกรณ์ทำงานหนักเกินไป แนวคิดในการบันทึก / โหลดระหว่างกิจกรรมทำให้เสียเวลามากเกินไป ฉันใช้แอปพลิเคชันเป็นที่เก็บข้อมูล แน่นอนชั้นข้อมูลของฉันที่เก็บไว้ในแอปพลิเคชันได้ตรวจสอบทุก metod - ข้อมูลยังมีชีวิตอยู่หรือต้องโหลด ดังนั้น Dave ต้อง: 1. ให้โหลด / บันทึก finctions 2. เก็บข้อมูลในแอปพลิเคชัน 3. ตรวจสอบตรรกะสามครั้งสำหรับการเข้าถึงข้อมูล
Kostadin

6

หากคุณต้องการเข้าถึง "Global Singleton" นอกกิจกรรมและคุณไม่ต้องการส่งContextผ่านวัตถุที่เกี่ยวข้องทั้งหมดเพื่อรับซิงเกิลตันคุณสามารถกำหนดแอตทริบิวต์แบบคงที่ในคลาสแอปพลิเคชันของคุณซึ่งมีการอ้างอิงถึง ตัวเอง เพียงแค่เริ่มต้นแอตทริบิวต์ในonCreate()วิธีการ

ตัวอย่างเช่น:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

เนื่องจากคลาสย่อยของApplicationยังสามารถรับทรัพยากรได้คุณจึงสามารถเข้าถึงได้ง่ายๆเมื่อคุณกำหนดวิธีการแบบคงที่ซึ่งจะส่งคืนพวกเขาเช่น:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

แต่ต้องระวังมากเมื่อผ่านรอบอ้างอิงบริบทที่จะหลีกเลี่ยงการรั่วไหลของหน่วยความจำ


6
คุณลืมทราบว่าคุณต้องเพิ่ม android: name = ". ApplicationController" แอตทริบิวต์ xml แท็กแอปพลิเคชันในไฟล์ Manifest ของคุณสำหรับคลาสที่จะสร้างอินสแตนซ์
eggie5

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

2

เดฟมันเป็นข้อมูลประเภทไหน? หากเป็นข้อมูลทั่วไปที่เกี่ยวข้องกับแอปพลิเคชันโดยรวม (เช่นข้อมูลผู้ใช้) ให้ขยายคลาสแอปพลิเคชันและเก็บไว้ที่นั่น หากข้อมูลเกี่ยวข้องกับกิจกรรมคุณควรใช้ตัวจัดการ onSaveInstanceState และ onRestoreInstanceState เพื่อคงข้อมูลในการหมุนหน้าจอ


จะเกิดอะไรขึ้นถ้าข้อมูลมีขนาดใหญ่มากที่จะจัดเก็บในพัสดุ? นี่คือสิ่งที่ฉันได้รับ: android.os.TransactionTooLargeException: ขนาดพัสดุข้อมูล 838396 ไบต์
Arjun Issar

1

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


16
คุณสามารถทำสิ่งต่างๆมากมาย ไม่ได้หมายความว่าเป็นความคิดที่ดี นี่ไม่ใช่ความคิดที่ดี
แอนดรู

การทดสอบโดยเปลี่ยนการวางแนวหน้าจอเป็นวิธีที่ง่ายที่สุดในการตรวจสอบว่าแอปของคุณทำในสิ่งที่ Android คิดว่าจะทำ
18446744073709551615

0

คุณสามารถสร้างคลาสแอปพลิเคชันและบันทึกข้อมูลทั้งหมดของคุณใน calss นั้นเพื่อใช้งานได้ทุกที่ในแอปพลิเคชันของคุณ


0

ฉันรู้ว่านี่เป็นคำถามที่เก่ามาก แต่การใช้ViewModel จากส่วนประกอบ jetpackเป็นวิธีที่ดีที่สุดในการเก็บรักษาข้อมูลระหว่างการหมุนกิจกรรม

คลาส ViewModel ได้รับการออกแบบมาเพื่อจัดเก็บและจัดการข้อมูลที่เกี่ยวข้องกับ UI โดยคำนึงถึงวงจรชีวิต คลาส ViewModel อนุญาตให้ข้อมูลอยู่รอดจากการเปลี่ยนแปลงคอนฟิกูเรชันเช่นการหมุนหน้าจอ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.