2011-01-25 31 views
23

Tôi có một ứng dụng có một số biến tĩnh. Các biến này được lưu trữ trong một Lớp độc lập có tên là DataContext. Các biến này được khởi tạo từ các tệp thô khi khởi động ứng dụng (một phương thức có tên DataContext.initConstant() được gọi trong onCreate() của MyApplication mở rộng Ứng dụng).Android: Biến tĩnh null trên bộ nhớ thấp

(EDIT: phương thức initConstant sử dụng AsyncTask để tải dữ liệu này từ tệp).

Khi ứng dụng của tôi đến nền trong một thời gian nhất định hoặc khi ứng dụng của tôi sử dụng nhiều bộ nhớ, các biến tĩnh này trở thành rỗng.

  1. Làm cách nào để ngăn chặn?

  2. Nếu không phải tôi nên làm gì với các biến tĩnh của mình?

    Tôi có dữ liệu khác được lưu trữ trong các biến tĩnh được sử dụng trên các hoạt động khác nhau, nhưng tôi xóa chúng hoặc chuyển chúng sang giá trị rỗng trong số onLowMemory() của MyApplication.

  3. Cách tốt nhất để giữ cho một số dữ liệu có thể truy cập được giữa các hoạt động nếu các dữ liệu này quá lớn để được đăng trong Intent, không thể sử dụng cơ sở dữ liệu (vì lý do nào) và không thể lưu trữ tập tin thông qua serialization hoặc?

+2

Bạn có thể giải thích tại sao cơ sở dữ liệu hoặc tệp được tuần tự hóa không hoạt động không? – sargas

+0

Tôi có rất nhiều thông tin và thay đổi cách tôi truy cập ngay bây giờ vì tôi thiếu thời gian và chúng tôi chỉ tìm ra vấn đề. – MathieuC

+0

@MathieuC: Hãy chia sẻ giải pháp, tôi cũng phải đối mặt với cùng một vấn đề từ rất lâu. –

Trả lời

4
  1. Bạn không thể. Android cần phải giải phóng bộ nhớ theo thời gian. Hãy tưởng tượng nếu tất cả các ứng dụng có một tấn dữ liệu tĩnh được cho là sẽ tồn tại mãi mãi - bạn sẽ phù hợp như thế nào trong bộ nhớ? Đó là một chiếc điện thoại di động. Nó không có bộ nhớ ảo.

  2. (và 3): Bất kỳ thứ gì có ý định lưu giữ liên tục cần phải được lưu trữ, thông qua SharedPreferences, cơ sở dữ liệu Sqlite hoặc tệp.

+0

Ok cảm ơn, nhưng tôi không thể thay đổi cách ứng dụng của tôi hiện đang hoạt động.Nhưng tôi chắc chắn sẽ thay đổi nó nếu tôi có thể. – MathieuC

5

Rất có thể sự cố là ứng dụng của bạn đang bị giết khi đang ở chế độ nền và sau đó được tạo lại khi bạn quay lại. Xem tài liệu Activity Lifecycle về thời điểm điều này có thể xảy ra cho một hoạt động. Bạn cần phải chắc chắn rằng bạn di chuyển bất cứ thứ gì được lưu trữ trong bộ nhớ để lưu trữ lâu dài hơn vào đúng thời điểm để tránh mất thông tin đó nếu ứng dụng bị giết.

Tôi không chắc chắn chính xác những gì bạn đang lưu trữ, nhưng có vẻ như việc sử dụng Tùy chọn được chia sẻ có thể hoạt động tốt. Trang này trên Data Storage giải thích một số cách lưu trữ dữ liệu vĩnh viễn khác nhau, bao gồm Tùy chọn được chia sẻ.

+1

Ứng dụng này không bị giết vì nếu biến tĩnh của tôi sẽ được tái tạo vì nếu ứng dụng bị hủy, thì khi nó được tạo lại, phương thức onCreate() của MyApplication sẽ được gọi. – MathieuC

1

Tôi lưu trữ một đối tượng User và đối tượng Client trong phạm vi tĩnh của tôi. Tôi đã nhận thấy theo thời gian tham chiếu trở thành null. Vì vậy, bây giờ trong getters của tôi, tôi kiểm tra xem nếu giá trị này là null và nếu như vậy tôi khởi động lại ứng dụng.

Intent i = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); 
       i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
       context.startActivity(i); 

Tôi cũng có thể chọn tải lại ứng dụng vì tôi lưu mã thông báo truy cập trong prefs tuy nhiên tôi khởi tạo quá nhiều nên tôi quyết định khởi động lại ứng dụng là ý tưởng hay nhất.

+0

Cảm ơn, nhưng điều đó có nghĩa là nếu người dùng có một thiết bị rất cũ, ứng dụng có thể khởi động lại rất thường xuyên, phải không? – MathieuC

+0

Hmm không chính xác. Tôi thực sự đặt các biến tĩnh trong lớp Ứng dụng của ứng dụng Android của tôi. Những vars hầu như không bao giờ trở thành null trừ khi toàn bộ ứng dụng được gỡ bỏ. Tôi nhận thấy thời gian duy nhất này trở thành null là khi ai đó sử dụng nhiệm vụ kẻ giết người để ngăn chặn các ứng dụng nhưng hoạt động hiện tại vẫn còn sống. Vì vậy, đó là lý do tại sao tôi nghĩ đây là một dịp hiếm hoi mà tôi sẽ chỉ khởi động lại ứng dụng. –

+0

Bạn thêm mã này ở đâu? – neteinstein

2

Nếu bạn không sử dụng tệp thô, tôi khuyên bạn nên khởi tạo khi lớp được tải.

Ví dụ,

public static Map<?,?> myStaticMap = new HashMap<?,?>(); 
static { //fill myStaticMap } 

Bạn có một số mối quan tâm lớn hơn để lo lắng về việc nếu bạn đang tải file theo cách đó. Ví dụ, những gì về lỗi I/O, hoặc các vấn đề độ trễ? Bạn sẽ nhận được cảnh báo trong gingerbread (nếu bạn kích hoạt chúng) để làm I/O trong chủ đề chính của bạn. Có lẽ bạn nên có một đối tượng để lấy các giá trị này thay vì một lớp với các trường tĩnh. (có lẽ với bộ nhớ cache tĩnh, mặc dù bạn nên đồng bộ hóa trên bộ nhớ cache trước khi kiểm tra/thay đổi)

+0

Đừng lo lắng quá trình tải của tôi không nằm trong chủ đề chính (tôi sử dụng AsyncTask để thực hiện công việc trong phương thức initConstant của mình) – MathieuC

+1

Nếu DataContext.initConstant() được gọi trong AsyncTask, thì khi ứng dụng của bạn bị phá hủy và khởi động lại bởi hệ thống, sẽ có một khoảng thời gian giữa Hoạt động của bạn được tạo và mong đợi DataContext được điền và thời gian thực sự được điền. Có thể lý do tại sao bạn thấy nó là rỗng - chưa được tạo lại, nhưng một số Hoạt động của bạn mong đợi nó sẽ được khởi tạo hoàn toàn vào thời điểm chúng chạy. – Kai

0

Thay vì sử dụng biến tĩnh u có thể sử dụng tùy chọn được chia sẻ để lưu trữ giá trị.

Lưu ý: đối với tùy chọn được chia sẻ, bạn cũng không nên tải nặng.

Tôi đã giải quyết vấn đề này bằng cách có lớp siêu với hàm getter và setter để lưu trữ và truy lục biến tùy chọn được chia sẻ.

Tất cả các lớp trong ứng dụng của tôi đã mở rộng lớp học siêu thay vì hoạt động.

1

Trong phương thức onResume() của bạn, bạn có thể truy vấn dữ liệu tĩnh để xem liệu nó có hiện diện hay không và tải lại.

2

Tôi cho rằng đây là sự cố bộ nhớ cache dữ liệu.

Lưu trữ dữ liệu trong lớp tĩnh không được đảm bảo hoạt động khi người dùng trao đổi ứng dụng thường xuyên. Hệ thống Android sẽ lấy lại bất kỳ hoạt động nền nào khi bộ nhớ yếu. Lớp tĩnh chắc chắn nằm trong danh mục này.

Cách thích hợp để thực hiện việc này là sử dụng sharedPreference để lưu dữ liệu bộ nhớ cache.

Bạn có thể tạo bộ thu thập và thiết lập riêng của dữ liệu bạn muốn và bọc nó xung quanh đối tượng sharedPreference. Khi bạn truy cập bằng cách sử dụng getter, bạn nên luôn kiểm tra xem giá trị có trống hay hết hạn không. Bạn có thể lưu trữ update_time khi sử dụng setter.

Để biết dữ liệu hoạt động cụ thể, bạn chỉ có thể sử dụng getPreference(permission), nếu bạn muốn chia sẻ dữ liệu giữa các hoạt động và các thành phần ứng dụng khác, bạn có thể sử dụng getSharedPreference(name, permission).

Thông thường, quyền sẽ là MODE_PRIVATE sao cho dữ liệu chỉ có thể được truy cập trong ứng dụng của bạn.

Bạn nên nhóm dữ liệu và lưu trữ trong đối tượng chia sẻ đối tượng khác biệt. Đây là thực hành tốt bởi vì khi bạn muốn vô hiệu hóa nhóm dữ liệu đó, nó chỉ là vấn đề của một lớp lót.

editor.clear(); editor.commit()

Nếu bạn muốn cache đối tượng phức tạp, bạn nên serialize nó. Tôi thích định dạng JSON. Vì vậy, bạn cần một số cơ chế chuyển đổi tại chỗ. Để làm điều này, tôi sẽ tạo lớp đối tượng dữ liệu mở rộng lớp JSONable của mình. Lớp JSONable sẽ có phương thức toJSON()readFromJSON(). Điều này thuận tiện khi khôi phục và tuần tự hóa dữ liệu.

Các vấn đề liên quan