2015-01-07 14 views
14

Tôi đã xác định một phiên bản SharedPreferences được sử dụng ở chế độ đa xử lý.Sử dụng SharedPreferences trên chế độ đa xử lý

public class Prefs { 

    private static SharedPreferences prefs; 
    private static SharedPreferences.Editor editor; 

    private static void init(Context context) { 

     prefs = context.getSharedPreferences("alaki", 
       Context.MODE_MULTI_PROCESS); 
     editor = prefs.edit(); 
    } 

// static methods to set and get preferences 
} 

Bây giờ tôi đang sử dụng lớp này trên dịch vụ với quy trình riêng và cũng trong quy trình đăng ký chính của tôi theo cách tĩnh.
Mọi thứ đang diễn ra tốt đẹp, nhưng đôi khi tất cả dữ liệu được lưu trữ trên phiên bản SharedPreferences đã bị xóa!
Làm cách nào để giải quyết vấn đề này?

Chỉnh sửa: Cuối cùng tôi đã giải quyết được sự cố của mình bằng IPC.

+0

Bạn có đang gọi editor.commit sau khi thực hiện thay đổi không? – jjm

+0

@jjm Có, tôi có. –

+0

Hmm. Ý của bạn là gì khi bạn nói rằng tất cả dữ liệu đã bị xóa? Là một quá trình sửa đổi các prefs và khác không nhìn thấy những thay đổi? – jjm

Trả lời

24

Hiện không có cách nào để truy cập an toàn SharedPreferences trên nhiều quy trình, như được mô tả trong documentation.

Lưu ý: Lớp này không hỗ trợ sử dụng trên nhiều quy trình.

Sau khi thử nghiệm rất nhiều với MODE_MULTI_PROCESS, tôi đã ba thử nghiệm để chia sẻ:

1- Khởi tạo SharedPreferences một lần trong mỗi quá trình và sử dụng nó nhiều lần.

Sự cố: Giá trị không được phản ánh trong mỗi quá trình như mong đợi. Vì vậy, mỗi quá trình có giá trị riêng của SharedPreferences.

2- Khởi tạo SharedPreferences trong mỗi lần đặt hoặc nhận.

Điều này thực sự hoạt động và giá trị hiện có thể thay đổi giữa các quy trình.

Vấn đề: đôi khi sau khi tích cực truy cập vào sharedpref, các ưu đãi file chia sẻ đã bị xóa với tất cả các nội dung của nó, như được mô tả trong issue này, và tôi nhận được cảnh báo này trong nhật ký:

W/FileUtils﹕ Failed to chmod(/data/data/com.hegazy.multiprocesssharedpref/shared_prefs/myprefs.xml): android.system.ErrnoException: chmod failed: ENOENT (No such file or directory) 

Bạn có thể tìm thấy lý do tại sao điều này xảy ra trong vấn đề.

3- Sử dụng đồng bộ hóa để khóa các phương pháp đặt và nhận các giá trị trong số SharedPreferences.

Điều này hoàn toàn sai; đồng bộ hóa không hoạt động trên các quy trình. SharedPreferences thực sự đang sử dụng đồng bộ hóa trong quá trình triển khai, nhưng điều đó chỉ đảm bảo an toàn luồng, không xử lý an toàn. Điều này được mô tả rất tốt here.

+0

Cảm ơn câu trả lời được nghiên cứu kỹ lưỡng này! Tôi thấy nó hơi khó hiểu, vì vậy tôi đã chỉnh sửa nó để dọn dẹp tiếng Anh để dễ theo dõi hơn. Hy vọng rằng tôi đã bảo tồn ý nghĩa ban đầu của bạn. – Sam

+0

Thực ra nó là một chỉnh sửa đẹp. Cảm ơn :) –

+0

@AhmedHegazy Câu trả lời của bạn khá nguy hiểm, tôi nghĩ bạn nên cân nhắc gửi giá trị hoặc đối tượng đến dịch vụ hoặc thông minh mỗi lần lưu trữ giá trị hoặc đối tượng thay đổi tùy chọn bạn gửi tin nhắn đến dịch vụ với giá trị được cập nhật.Đó là những gì tôi làm, tôi chỉ đọc hoặc lưu trữ các giá trị trong sở thích từ một trong hai quy trình. – AlexSanchez

-1

Nếu hai quá trình ghi dữ liệu vào SharedPreferences, thì có thể tất cả SharedPreferences được đặt lại về giá trị mặc định.

Ngoài ra bạn có thể thử để gọi clear() vào trình soạn thảo trước khi lưu trữ val

SharedPreferences.Editor sp = settings.edit(); 
sp.clear(); 
sp.putString("Name", "YourName"); 
sp.commit(); 
+0

'clear()' trả về tất cả dữ liệu về giá trị mặc định. nhưng @Mousa không muốn xóa dữ liệu đột ngột. –

2

Sử dụng các cửa hàng commit() phương pháp thay đổi về lưu trữ liên tục, do đó nó là chậm và sẽ làm cho cuộc xung đột trên nhiều cuộc gọi từ các quá trình khác.

Tuy nhiên, có một phương án thay thế cho phương pháp này, bạn nên gọi phương thức apply(), phương pháp này lưu trữ các thay đổi trong bộ nhớ và sau đó lưu trữ trên đĩa một cách không đồng bộ, vì vậy nó đáng tin cậy hơn.

+0

Tại sao bạn nghĩ rằng việc ghi tập tin tùy chọn không đồng bộ sẽ làm giảm xung đột với các quá trình khác? Tôi chỉ cần kiểm tra lại mã nguồn 'SharedPreferencesImpl', và cả hai đều sử dụng cùng một mã (' enqueueDiskWrite') để ghi tệp tùy chọn. – Sam

1

nhớ lại rằng việc sử dụng bối cảnh các đối tượng lĩnh vực như tĩnh, bạn có nguy cơ bị rò rỉ của bối cảnh vì không khai báo các đối tượng trong lớp ứng dụng

public class CustomApplication extends Application{ 
    private Prefs prefs; 

    public void onCreate(){ 
      prefs = new Prefs(this); 
    } 

    public Prefs getPrefs(){ 
     return prefs; 
    } 
} 

Từ bất kỳ bối cảnh mà bạn có thể nhận được prefs

((MyApplication)context.getApplicationContext()).getPrefs(); 
4

SharedPreferences chính nó không phải là quá trình an toàn. Đó có thể là lý do tại sao SharedPreferences documentation nói

Lưu ý: hiện tại lớp này không hỗ trợ sử dụng trên nhiều quy trình. Điều này sẽ được thêm vào sau.

+0

Tôi đã xem mã nguồn và xác nhận điều này. – Sam

2

Tôi đã làm việc này bằng cách kết hợp:

  • Cung cấp mỗi quá trình truy cập lẫn nhau độc quyền để các tập tin SharedPreferences (chẳng hạn như bằng cách sử dụng a socket-based locking mechanism)
  • Re-initialising các SharedPreferences với MODE_MULTI_PROCESS cờ mỗi thời gian bạn muốn sử dụng để bỏ qua bộ nhớ đệm trong bộ nhớ

Điều này có vẻ ổn nhưng chưa được kiểm tra kỹ lưỡng trong thế giới thực, vì vậy tôi không biết hoàn toàn đáng tin cậy.

Bạn có thể xem ví dụ hoạt động tôi đã viết here.

Cảnh báo: Có vẻ như MODE_MULTI_PROCESS đã không được chấp nhận trong Android M. Ứng dụng có thể ngừng hoạt động trong tương lai.

+1

nỗ lực của bạn để giải quyết vấn đề với các phương pháp sáng tạo là đáng ngưỡng mộ –

0

Sử dụng Nhà cung cấp nội dung sử dụng SharedPreferences. Ví dụ xem tại đây: https://github.com/hamsterksu/MultiprocessPreferences

+0

Tôi đã sử dụng kỹ thuật này trong sản xuất trong một thời gian dài. Nó thường hoạt động nhưng cũng có nhiều vấn đề thường xuyên mà dường như là lỗi trong Android liên quan đến các nhà cung cấp nội dung. – Sam

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