2013-03-17 29 views
7

Câu hỏi:
Làm cách nào tôi có thể quản lý (Kết nối, Đọc, Ghi, Ngắt kết nối) kết nối bluetooth tồn tại thông qua thay đổi cấu hình?Làm cách nào để quản lý kết nối Bluetooth trên Android thông qua các thay đổi cấu hình?

Ưu tiên các giải pháp tương thích với phiên bản thiết bị 2.2 "Froyo" sử dụng ActionBarSherlock.

vấn đề ...

  • Cả BluetoothDevice cũng không BluetoothSocket có thể được giữ lại trong onSaveState.

  • Để keep my app responsive, lệnh gọi chặn thứ hai là BluetoothSocket.connect() phải được thực hiện trên một chuỗi riêng biệt. Bắt đầu từ Runnable là cách được đề xuất để tạo chuỗi các tác vụ dài, nhưng đó là một cơn ác mộng đang cố khôi phục khi thay đổi cấu hình. Các tài liệu chính thức chỉ ra ba giải pháp khác nhau.

    • Sử dụng getLastNonConfigurationInstance(), không được dùng nữa (nghiêm túc ?!).

    • Đặt android:configChanges="keyboardHidden|orientation" như số BluetoothChat Sample. Tuy nhiên, điều này không tính đến tất cả các loại thay đổi cấu hình.

    • Hủy & các tác vụ khởi động lại như số Shelves Example. Trong trường hợp này, điều này có thể lãng phí thêm 12 giây nữa.

Cập nhật 1

  • Nghiên cứu sâu hơn dẫn tôi đến asyncTaskLoader, nhưng nó có vẻ như điều này chỉ có thể cập nhật giao diện người dùng trên hoàn thành, và không thể cung cấp thông tin cập nhật.

  • Mẫu BluetoothHDP sử dụng dịch vụ. Các dịch vụ dường như tập trung vào giao tiếp giữa các quá trình và sự cần thiết phải tồn tại vượt quá vòng đời hoạt động. Tôi không cần một trong các tính năng này.

Cập nhật 2

As pointed out by Reuben, Fragment.setRetainInstance(bool) đã thay thế phản getLastNonConfigurationInstance(). Tại thời điểm này, có vẻ như tùy chọn tốt nhất là tạo một đoạn không giao diện người dùng liên tục bằng cách sử dụng setRetainInstance(true).

Trả lời

1

Có một loạt giải pháp cho việc này. Nếu bạn không sử dụng Fragments thì tùy chọn đơn giản nhất là ghi đè lênRetainNonConfigurationInstance(). Đừng bận tâm rằng API không còn được dùng nữa, đó là chỉ vì họ muốn bạn sử dụng Fragments (ở đâu, công bằng, Fragment.setRetainInstance() làm cho toàn bộ vấn đề này không cần phải có). API này sẽ không diễn ra trong một thời gian dài.

Những gì tôi muốn làm là ghi đè onRetainNonConfiguration() để trở về 'này', tức là một tham chiếu đến dụ Hoạt động chết, và sau đó sao chép qua refs đối tượng bạn cần từ onCreate(), ví dụ:

Object obj = getLastNonConfigurationInstance(); 
if (obj != null) { 
    MyActivity deadActivity = (MyActivity)obj; 
    this.foo = deadActivity.foo; 
    this.bar = deadActivity.bar; 
    ... 
} 

Hoặc bạn có thể sử dụng Dịch vụ nhưng cá nhân tôi không thích chúng. Hữu ích cho việc thực hiện các công cụ xử lý chéo, không nghi ngờ gì, nhưng nếu không chúng là một giải pháp để tìm kiếm một vấn đề.

Cuối cùng, là một điểm chung để bạn có thể an toàn lưu dữ liệu 'toàn cầu' vào ngữ cảnh Ứng dụng của mình. Để làm điều này bạn phân lớp android.app.Application và sử dụng ứng dụng android: name = "MyApp" > trong tệp kê khai của bạn. Nó cũng hữu ích để giữ một ref cho đối tượng Application trong dữ liệu tĩnh toàn cầu ở đây, vì vậy AsyncTasks và các mã context-less khác luôn có thể tới ngữ cảnh ứng dụng mà không cần phải chuyển các tham số Context xung quanh mà không có lý do gì.

class MyApp extends Application { 
... 

    public static MyApp context; 
    ... 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     context = this; 

     ... set up global data here ... 
    } 
... 
} 
+0

Có đáng để tạo một đoạn duy nhất cho hoạt động này chỉ vì vậy tôi có thể sử dụng 'setRetainInstance'? Đoạn "được giữ lại" có thể xoay và tự thay đổi kích thước của nó trên một thay đổi định hướng không? Ngoài ra, [câu hỏi SO này] (http://stackoverflow.com/questions/4585627) đã dạy tôi rằng một phân lớp của ứng dụng KHÔNG phải là cách an toàn để lưu trữ các hình ảnh toàn cầu. Trong thực tế, nó có thể dẫn đến lỗi gần như không thể tái tạo. – firyice

+0

Re. Mảnh vỡ, vâng. Đó là giá trị nắm lấy cách mảnh vỡ của việc làm sớm hơn là sau này. Re phân lớp ứng dụng, một người nào đó bối rối. Có trạng thái nhiệm vụ có thể bị đóng băng bởi hệ điều hành trong khi quá trình bị giết, nhưng vậy thì sao? Application.onCreate() vẫn chạy khi quá trình/nhiệm vụ khởi động lại/tiếp tục. –

+0

Vì vậy, những gì? Nếu quá trình khởi động lại và Application.onCreate() được gọi, bạn đã mất dữ liệu trong các biến toàn cầu đó. Cách duy nhất có thể ổn là hằng số. – firyice

8

tôi sẽ giải quyết vấn đề này bằng cách sử dụng một Service rằng sẽ xử lý kết nối bluetooth của bạn, và làm cho rằng dịch vụ nói chuyện trở lại hoạt động của bạn như được mô tả trong this answer.

Sau đó, bạn có thể sử dụng AsyncTask chỉ đơn giản là hiển thị/ẩn một hộp thoại và hủy/khởi động lại ASyncTasks khi xoay vòng, được thực hiện bởi Shelves Example như bạn đã đề cập.

Dịch vụ không thực sự kinh khủng và có thể là công cụ tốt nhất cho vấn đề của bạn.

+0

Điều này có vẻ như một giải pháp an toàn. Tuy nhiên, điều này cũng đánh tôi như là tương đương với lái xe trong một móng tay với một cái búa khoan. Dịch vụ thực sự có vẻ như họ đang có nghĩa là để giao tiếp với nhiều quy trình. Có, chúng có thể được sử dụng cho một số nhiệm vụ đơn giản trong một quá trình, nhưng có vẻ như quá nhiều việc nâng hạng nặng cho một thứ tương đối đơn giản. – firyice

+4

Tôi không đồng ý. Tôi muốn ứng dụng của mình xử lý việc sao lưu nền cho máy chủ - một IntentService 20 dòng đơn giản là giải pháp đơn giản nhất mà tôi có thể tìm thấy. – Axarydax

2

Bạn có thể thử với số singleton pattern có thể xử lý mọi thứ và gọi cho hoạt động chính khi cần thiết.

Vì vậy, đó là một phương pháp tĩnh để có được một thể hiện của đối tượng MySingleton, cùng một ví dụ mỗi khi bạn gọi getInstance. Bạn có thể "lưu trữ" tất cả các đối tượng bluetooth trong đó, nó sẽ không bị phá hủy và có thể truy cập được từ mỗi hoạt động.

public class MySingleton { 
    private static MySingleton instance; 
    public static MySingleton getInstance() { 
     if (null == instance) { 
      instance = new MySingleton(); 
     } 
    return instance; 
} 

    private MySingleton() { 
    } 
} 
+0

Đó là sự hiểu biết của tôi rằng lớp Ứng dụng, là một singleton được cung cấp bởi android cho mọi ứng dụng, có vòng đời của riêng nó. Nó cũng vậy, trong những trường hợp hiếm hoi, có thể bị phá hủy mà không có toàn bộ ứng dụng bị phá hủy. Bạn có nghĩa là một lớp singleton riêng biệt? Bạn có thể cung cấp một ví dụ mã về những gì bạn đang nói về ở đây không? – firyice

+0

Tôi đã không thực sự thử nó cho kết nối Bluetooth, nhưng một lớp singleton không nên bị phá hủy. Xin lỗi vì định dạng, tôi không phải là một SO xuất khẩu, nhưng nó chỉ là một lớp singleton thường xuyên, trong đó bạn sẽ có tất cả mọi thứ liên quan đến kết nối bluetooth. ' lớp công khai Singleton { trường hợp Singleton tĩnh riêng tư; publicleton Singleton getInstance() { if (null == instance) { instance = new Singleton(); } bản sao trả về; } riêng Singleton() { } } ' –

+0

Cảm ơn bạn đã giải thích! Bạn có thể cập nhật câu trả lời của mình bằng mã không. Bạn có thể thụt lề tất cả các dòng với 4 dấu cách để làm cho nó được định dạng như mã. – firyice

4

Không bao giờ đặt Mô hình ứng dụng (logic hoặc dữ liệu) trong Visual/UI components. Như bạn thấy, họ đến và đi, và thay đổi.

Places để giữ những thứ không liên quan đến giao diện người dùng giống như các bộ sưu tập dữ liệu, kết nối trực tiếp, chủ đề vv:

  • Lớp Application. Phong bì tất cả các vòng đời của thành phần khác. Hầu như giống như một singleton toàn cầu. Bạn có thể sử dụng điều này để lưu trữ tạm thời.

dụ:

public class App extends Application { 

    private static Beer sBeer; 

    public static void brbHoldMyBeer(Beer b){ 
    sBeer = b; 
    } 

    public static Beer imBackWheresMyBeer(){ 
    return sBeer; 
    } 

} 

Ngoài ra, có một dịch vụ chủ đề Executor tĩnh trong lớp ứng dụng, sẽ giúp duy trì nhiệm vụ chạy.

  • Dịch vụ nền đang chạy. Những hoạt động nào, các mảnh vỡ vv có thể ràng buộc/hủy liên kết và gửi các lệnh/yêu cầu. Đây là nơi được đề xuất cho các quy trình và dữ liệu chạy ứng dụng rộng.

  • Phân đoạn không trực quan với setRetainInstance(true). Không trực quan ở đây có nghĩa là đoạn giả của nó được gắn với Hoạt động nhưng không hiển thị bất kỳ chế độ xem nào. Nó chỉ được sử dụng như một người giữ đối tượng có thể giữ lại cho một Hoạt động. Điều này được đề xuất cho các quy trình và dữ liệu rộng của Hoạt động.

+0

drink = imBackWheresMyBeer(); – Luis

+0

[Tài liệu Android gợi ý giữ lại các đối tượng trong quá trình thay đổi cấu hình bằng cách đính kèm chúng vào một đoạn không hoàn toàn bị lỗi.] (Http://developer.android.com/guide/topics/resources/runtime-changes.html#RetainingAnObject) (Chỉ cần chồng chất về tài liệu tham khảo.) –

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