Sử dụng lớp Ứng dụng Android để duy trì dữ liệu


112

Tôi đang làm việc trên một ứng dụng Android khá phức tạp đòi hỏi một lượng lớn dữ liệu về ứng dụng (tôi muốn nói tổng cộng khoảng 500KB - điều này có lớn đối với thiết bị di động không?). Từ những gì tôi có thể nói, bất kỳ thay đổi định hướng nào trong ứng dụng (chính xác hơn là trong hoạt động) đều gây ra sự phá hủy hoàn toàn và tái tạo lại hoạt động. Dựa trên những phát hiện của tôi, lớp Ứng dụng không có cùng một vòng đời (tức là, đối với tất cả các ý định và mục đích, luôn được khởi tạo). Lưu trữ thông tin trạng thái bên trong lớp ứng dụng và sau đó tham chiếu nó từ Activity có hợp lý không hay đó không phải là phương pháp "được chấp nhận" do hạn chế về bộ nhớ trên thiết bị di động? Tôi thực sự đánh giá cao bất kỳ lời khuyên nào về chủ đề này. Cảm ơn!


8
Chỉ cần lưu ý rằng dữ liệu trong Ứng dụng của bạn vẫn có thể bị xóa nếu ứng dụng của bạn ở chế độ nền, vì vậy đây không phải là giải pháp cho dữ liệu tồn tại mà bạn luôn muốn lấy lại. Nó chỉ phục vụ như một phương pháp không phải tạo lại các đối tượng đắt tiền như thường xuyên.
Cheryl Simon

2
Mayra; Tôi không nghĩ rằng ứng dụng "thường" bị xóa (mặc dù, như một người nào đó chỉ ra sau trong chủ đề này, nó "có thể"). Tôi có thể sẽ sử dụng một số loại phương pháp tiếp cận "kết hợp" là sử dụng ứng dụng để lưu trữ và tải dữ liệu, nhưng sau đó sử dụng thuộc tính "android: direction" trên hoạt động trong tệp kê khai để ghi đè hành vi bình thường của xé nhỏ và xây dựng lại hoạt động. Tất nhiên, tất cả điều này giả định rằng ứng dụng có thể xác định "khi nào" nó bị hủy để dữ liệu có thể được duy trì.
Dave

Câu trả lời:


134

Tôi không nghĩ 500kb sẽ là một vấn đề lớn.

Những gì bạn mô tả là chính xác cách tôi giải quyết vấn đề mất dữ liệu trong một hoạt động. Tôi đã tạo một singleton toàn cục trong lớp Ứng dụng và có thể truy cập nó từ các hoạt động tôi đã sử dụng.

Bạn có thể chuyển dữ liệu xung quanh trong Global Singleton nếu nó sẽ được sử dụng nhiều.

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

Sau đó, gọi nó trong bất kỳ hoạt động nào bằng cách:

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

Tôi thảo luận về nó ở đây trong bài đăng trên blog của tôi , trong phần "Global Singleton."


1
Rất tiếc, bài đăng trên blog được đề cập không còn ở địa chỉ đó nữa.
mikebabcock

1
Tôi đã di chuyển mọi thứ trên trang web của mình. Cho đến khi nó được sửa, bạn có thể tìm thấy nó trên archive.org tại đây: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny

1
Tôi biết đây là một bài viết cũ nhưng tôi vừa gặp một vấn đề mà điều này có thể giải quyết, tuy nhiên lớp này cần được khai báo trong tệp kê khai bằng cách nào đó, phải không? tôi không thể acsses lớp nên cảm giác như thế này là những gì tôi đang mất tích ...
Ziv Kesten

1
@ZivKesten Còn việc thêm thuộc tính name = vào thẻ ứng dụng bên trong tệp kê khai thì sao?
MikeC

@mgc cảm ơn bạn của nó được một thời gian, và có nghĩa là làm thế nào tôi cuối cùng đã làm việc nó ra, cũng có thể tôi tạo ra thể hiện của lớp mà bất cứ nơi nào tôi cần bằng cách cho nó trở thành getApplicationContext () với một dàn diễn viên đến lớp này
Ziv Kesten

57

Những người tin tưởng Application ví dụ là sai. Lúc đầu, có vẻ như nó Applicationtồn tại miễn là toàn bộ quy trình ứng dụng tồn tại nhưng đây là một giả định không chính xác.

Hệ điều hành có thể hủy các quy trình khi cần thiết. Tất cả các quy trình được chia thành 5 cấp độ "khả năng tiêu diệt" được chỉ định trong tài liệu .

Vì vậy, ví dụ: nếu ứng dụng của bạn chạy ở chế độ nền do người dùng trả lời cuộc gọi đến, thì tùy thuộc vào trạng thái của RAM, hệ điều hành có thể (hoặc có thể không) giết quá trình của bạn (hủy Applicationphiên bản trong quá trình) .

Tôi nghĩ rằng một cách tiếp cận tốt hơn sẽ là duy trì dữ liệu của bạn vào tệp lưu trữ nội bộ và sau đó đọc nó khi hoạt động của bạn tiếp tục.

CẬP NHẬT:

Tôi đã nhận được nhiều phản hồi tiêu cực, vì vậy đã đến lúc phải bổ sung làm rõ. :) Chà, ban đầu tôi thực sự đã sử dụng một giả định sai lầm rằng trạng thái thực sự quan trọng đối với ứng dụng. Tuy nhiên, nếu ứng dụng của bạn vẫn ổn nhưng đôi khi trạng thái bị mất (có thể là một số hình ảnh sẽ chỉ được đọc lại / tải xuống lại), thì bạn hoàn toàn có thể giữ nó làm thành viên của Application.


14
Nếu Application bị khai tử thì ai quan tâm đúng không? Ứng dụng đã biến mất. Theo tôi hiểu, Android sẽ lấy lại các quy trình chứa bộ nhớ như Hoạt động. Nếu quá trình chứa Ứng dụng bị giết (nếu Android thậm chí sẽ làm điều đó?), Điều đó về cơ bản giống như giết ứng dụng. Người dùng sẽ cần khởi chạy lại ứng dụng và tại thời điểm đó, ai quan tâm? Đây là một phiên bản mới của ứng dụng.
Andrew

14
Đây là một bất ngờ không nhỏ đối với chúng tôi trong quá trình sản xuất. Hãy tin tôi rằng Android giết chết các quy trình, nó chỉ phụ thuộc vào trạng thái RAM và các yếu tố khác được mô tả trong tài liệu. Đó là một cơn ác mộng đối với chúng tôi nên tôi chỉ chia sẻ kinh nghiệm thực tế của mình. Chà, chúng tôi không có điều này trên trình giả lập, nhưng trong thế giới thực, một số thiết bị bị 'quá tải' với các ứng dụng, vì vậy việc giết một quy trình nền là một tình huống bình thường. Có, nếu sau đó người dùng quyết định đưa ứng dụng lên nền trước - hệ điều hành sẽ khôi phục ngăn xếp của nó bao gồm cả Applicationphiên bản, tuy nhiên, sẽ không có dữ liệu tĩnh của bạn mà bạn tin tưởng trừ khi bạn duy trì nó.
Vit Khudenko

2
Tôi nghĩ có lẽ tôi sẽ sử dụng một phương pháp kết hợp. Tôi đã biết về thủ thuật tệp kê khai để ghi đè thay đổi hướng (có những lợi ích khác). Vì ứng dụng là một trò chơi, tôi không chắc việc duy trì dữ liệu giữa các lần khởi chạy là đủ "quan trọng"; mặc dù nó có lẽ sẽ không quá khó vì hầu hết dữ liệu có thể được tuần tự hóa (mặc dù tôi không muốn tuần tự hóa và hủy số hóa giữa mỗi lần thay đổi hướng). Tôi chắc chắn đánh giá cao đầu vào. Tôi sẽ không nói những thứ phụ thuộc vào phiên bản Ứng dụng là "sai". Rất nhiều phụ thuộc vào ứng dụng :).
Dave

1
@Arhimed bạn đang khái quát câu trả lời của mình quá nhiều. Và đề xuất một cách tiếp cận hẹp dựa trên giả định của bạn. Giả định sai: Dữ liệu được giữ trong các biến tĩnh cần được duy trì trong các phiên của ứng dụng. Có thể có nhiều trường hợp sử dụng trong đó dữ liệu là nhỏ và không cần phải duy trì ngay lập tức.
Mandar Limaye

2
Tôi có khoảng 1mb dữ liệu với cấu trúc phức tạp. Serialize / deserialize có thể khiến tôi mất đến 2-3 giây khi thiết bị quá tải với công việc. Ý tưởng tiết kiệm / tải giữa các hoạt động tốn quá nhiều thời gian. Tôi sử dụng ứng dụng làm nơi lưu trữ. Tất nhiên lớp dữ liệu của tôi được lưu trữ trong phiên bản ứng dụng sẽ kiểm tra mọi siêu dữ liệu - dữ liệu vẫn còn sống hay phải được tải. Vì vậy Dave phải: 1. cung cấp tải / lưu phần mềm 2. lưu giữ dữ liệu trong ứng dụng. 3. Kiểm tra ba lần logic để cộng dồn dữ liệu.
Kostadin

6

Nếu bạn muốn truy cập "Global Singleton" bên ngoài một hoạt động và bạn không muốn chuyển Contextqua tất cả các đối tượng liên quan để lấy singleton, bạn chỉ có thể xác định một thuộc tính static trong lớp ứng dụng của mình, thuộc tính này chứa tham chiếu đến chinh no. Chỉ cần khởi tạo thuộc tính trongonCreate() phương thức.

Ví dụ:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

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

Bởi vì các lớp con của Applicationcũng có thể lấy được Tài nguyên, bạn có thể truy cập chúng đơn giản khi bạn xác định một phương thức tĩnh, phương thức này trả về chúng, như:

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

Nhưng hãy rất cẩn thận khi chuyển xung quanh các tham chiếu Ngữ cảnh để tránh rò rỉ bộ nhớ .


6
Bạn quên lưu ý rằng bạn phải thêm thuộc tính xml android: name = ". ApplicationController" vào thẻ ứng dụng trong tệp kê khai của bạn để lớp được khởi tạo.
eggie 5

Bạn thực sự không cần phải mở rộng Applicationđể làm điều này. Bạn có thể khai báo một biến thành viên tĩnh trong bất kỳ lớp nào để thực hiện việc này.
David Wasser

2

Dave, nó là loại dữ liệu gì? Nếu đó là dữ liệu chung liên quan đến toàn bộ ứng dụng (ví dụ: dữ liệu người dùng), thì hãy mở rộng lớp Ứng dụng và lưu trữ nó ở đó. Nếu dữ liệu liên quan đến Hoạt động, bạn nên sử dụng trình xử lý onSaveInstanceState và onRestoreInstanceState để duy trì dữ liệu khi xoay màn hình.


Điều gì sẽ xảy ra nếu dữ liệu thực sự lớn để lưu trữ trong một Bưu kiện? Đây là những gì im nhận: android.os.TransactionTooLargeException: dữ liệu kích thước lô đất 838.396 byte
Arjun Issar

1

Bạn thực sự có thể ghi đè chức năng định hướng để đảm bảo rằng hoạt động của bạn không bị phá hủy và được tạo lại. Nhìn đây .


16
Bạn có thể làm rất nhiều thứ. Nó không có nghĩa là chúng là những ý tưởng hay. Đây không phải là ý tưởng tốt.
Andrew

Kiểm tra bằng cách thay đổi hướng màn hình là cách dễ nhất để đảm bảo ứng dụng của bạn thực hiện những gì Android giả định.
18446744073709551615

0

Bạn có thể tạo lớp Ứng dụng và lưu tất cả dữ liệu của mình trên lớp đó để sử dụng ở bất kỳ đâu trong ứng dụng của bạn.


0

Tôi biết đây là câu hỏi rất cũ nhưng sử dụng ViewModel từ các thành phần jetpack là cách tốt nhất để bảo toàn dữ liệu giữa các vòng quay Hoạt động.

Lớp ViewModel được thiết kế để lưu trữ và quản lý dữ liệu liên quan đến giao diện người dùng theo cách có ý thức về vòng đời. Lớp ViewModel cho phép dữ liệu tồn tại qua các thay đổi cấu hình như xoay màn hình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.