1page.title=Dịch vụ Gắn kết
2parent.title=Dịch vụ
3parent.link=services.html
4@jd:body
5
6
7<div id="qv-wrapper">
8<ol id="qv">
9<h2>Trong tài liệu này</h2>
10<ol>
11  <li><a href="#Basics">Nội dung Cơ bản</a></li>
12  <li><a href="#Creating">Tạo một Dịch vụ Gắn kết</a>
13    <ol>
14      <li><a href="#Binder">Mở rộng lớp Trình gắn kết</a></li>
15      <li><a href="#Messenger">Sử dụng một Hàm nhắn tin</a></li>
16    </ol>
17  </li>
18  <li><a href="#Binding">Gắn kết với một Dịch vụ</a></li>
19  <li><a href="#Lifecycle">Quản lý Vòng đời của một Dịch vụ Gắn kết</a></li>
20</ol>
21
22<h2>Lớp khóa</h2>
23<ol>
24  <li>{@link android.app.Service}</li>
25  <li>{@link android.content.ServiceConnection}</li>
26  <li>{@link android.os.IBinder}</li>
27</ol>
28
29<h2>Mẫu</h2>
30<ol>
31  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
32      RemoteService}</a></li>
33  <li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
34      LocalService}</a></li>
35</ol>
36
37<h2>Xem thêm</h2>
38<ol>
39  <li><a href="{@docRoot}guide/components/services.html">Dịch vụ</a></li>
40</ol>
41</div>
42
43
44<p>Dịch vụ gắn kết là máy chủ trong một giao diện máy khách-máy chủ. Dịch vụ gắn kết cho phép các thành phần
45(chẳng hạn như các hoạt động) gắn kết với dịch vụ, gửi yêu cầu, nhận phản hồi, và thậm chí thực hiện
46truyền thông liên tiến trình (IPC). Dịch vụ gắn kết thường chỉ hoạt động khi nó phục vụ một thành phần
47ứng dụng khác và không chạy ngầm mãi liên tục.</p>
48
49<p>Tài liệu này cho bạn biết cách tạo một dịch vụ gắn kết, bao gồm cách gắn kết
50với dịch vụ từ các thành phần ứng dụng khác. Tuy nhiên, bạn cũng nên tham khảo tài liệu <a href="{@docRoot}guide/components/services.html">Dịch vụ</a> để biết thêm thông tin
51về các dịch vụ nói chung, chẳng hạn như cách gửi thông báo từ một dịch vụ, đặt
52dịch vụ để chạy trong tiền cảnh, và nhiều nội dung khác.</p>
53
54
55<h2 id="Basics">Nội dung Cơ bản</h2>
56
57<p>Dịch vụ gắn kết là một sự triển khai lớp {@link android.app.Service} cho phép
58các ứng dụng khác gắn kết và tương tác với nó. Để thực hiện gắn kết cho một
59dịch vụ, bạn phải triển khai phương pháp gọi lại {@link android.app.Service#onBind onBind()}. Phương pháp này
60trả về một đối tượng {@link android.os.IBinder} định nghĩa giao diện lập trình mà
61các máy khách có thể sử dụng để tương tác với dịch vụ.</p>
62
63<div class="sidebox-wrapper">
64<div class="sidebox">
65  <h3>Gắn kết với một Dịch vụ được Bắt đầu</h3>
66
67<p>Như đã đề cập trong tài liệu <a href="{@docRoot}guide/components/services.html">Dịch vụ</a>
68, bạn có thể tạo một dịch vụ được bắt đầu và gắn kết. Cụ thể, dịch vụ có thể được
69bắt đầu bằng cách gọi {@link android.content.Context#startService startService()}, nó cho phép dịch vụ
70chạy mãi, và cũng cho phép một máy khách gắn kết với dịch vụ bằng cách gọi {@link
71android.content.Context#bindService bindService()}.
72  <p>Nếu bạn có cho phép dịch vụ của mình được bắt đầu và gắn kết, thì khi dịch vụ đã được
73bắt đầu, hệ thống sẽ <em>không</em> hủy dịch vụ đó khi tất cả máy khách bỏ gắn kết. Thay vào đó, bạn phải
74dừng dịch vụ một cách rõ ràng bằng cách gọi {@link android.app.Service#stopSelf stopSelf()} hoặc {@link
75android.content.Context#stopService stopService()}.</p>
76
77<p>Mặc dù bạn nên thường xuyên triển khai hoặc {@link android.app.Service#onBind onBind()}
78<em>hoặc</em> {@link android.app.Service#onStartCommand onStartCommand()}, đôi khi cần phải
79triển khai cả hai. Ví dụ, một trình chơi nhạc có thể cho rằng nên cho phép dịch vụ của nó chạy
80mãi và cũng thực hiện gắn kết. Bằng cách này, một hoạt động có thể bắt đầu dịch vụ để chơi vài
81bản nhạc và nhạc tiếp tục chơi ngay cả khi người dùng rời khỏi ứng dụng. Lúc đó, khi người dùng
82trở lại ứng dụng, hoạt động có thể gắn kết với dịch vụ để giành lại quyền kiểm soát phát lại.</p>
83
84<p>Đảm bảo đọc phần về <a href="#Lifecycle">Quản lý Vòng đời của một Dịch vụ
85Gắn kết</a> để biết thêm thông tin về vòng đời của dịch vụ khi thêm gắn kết vào một
86dịch vụ được bắt đầu.</p>
87</div>
88</div>
89
90<p>Một máy khách có thể gắn kết với dịch vụ bằng cách gọi {@link android.content.Context#bindService
91bindService()}. Khi làm vậy, nó phải cung cấp việc triển khai {@link
92android.content.ServiceConnection}, có chức năng theo dõi kết nối với dịch vụ. Phương pháp {@link
93android.content.Context#bindService bindService()} trả về ngay lập tức mà không có giá trị, nhưng
94khi hệ thống Android tạo kết nối giữa
95máy khách và dịch vụ, nó gọi {@link
96android.content.ServiceConnection#onServiceConnected onServiceConnected()} trên {@link
97android.content.ServiceConnection}, để giao {@link android.os.IBinder} mà
98máy khách có thể sử dụng để giao tiếp với dịch vụ.</p>
99
100<p>Nhiều máy khách có thể kết nối với dịch vụ đồng thời. Tuy nhiên, hệ thống sẽ gọi phương pháp
101{@link android.app.Service#onBind onBind()} của dịch vụ của bạn để truy xuất {@link android.os.IBinder} chỉ
102khi máy khách đầu tiên gắn kết. Sau đó, hệ thống sẽ giao cùng một {@link android.os.IBinder} đó cho bất kỳ
103máy khách bổ sung nào có gắn kết mà không gọi lại {@link android.app.Service#onBind onBind()}.</p>
104
105<p>Khi máy khách cuối cùng bỏ gắn kết với dịch vụ, hệ thống sẽ hủy dịch vụ (trừ khi dịch vụ
106cũng được bắt đầu bởi {@link android.content.Context#startService startService()}).</p>
107
108<p>Khi bạn triển khai dịch vụ gắn kết của mình, phần quan trọng nhất là định nghĩa giao diện
109mà phương pháp gọi lại {@link android.app.Service#onBind onBind()} của bạn sẽ trả về. Có một vài
110cách khác nhau mà bạn có thể định nghĩa giao diện {@link android.os.IBinder} của dịch vụ của mình và phần
111sau đây sẽ bàn về từng kỹ thuật.</p>
112
113
114
115<h2 id="Creating">Tạo một Dịch vụ Gắn kết</h2>
116
117<p>Khi tạo một dịch vụ thực hiện gắn kết, bạn phải nêu một {@link android.os.IBinder}
118cung cấp giao diện lập trình mà các máy khách có thể sử dụng để tương tác với dịch vụ. Có
119ba cách bạn có thể định nghĩa giao diện:</p>
120
121<dl>
122  <dt><a href="#Binder">Mở rộng lớp Trình gắn kết</a></dt>
123  <dd>Nếu dịch vụ của bạn chỉ riêng cho ứng dụng của chính bạn và chạy trong cùng tiến trình như máy khách
124(điều này thường hay gặp), bạn nên tạo giao diện của mình bằng cách mở rộng lớp {@link android.os.Binder}
125và trả về một thực thể của nó từ
126{@link android.app.Service#onBind onBind()}. Máy khách nhận được {@link android.os.Binder} và
127có thể sử dụng nó để trực tiếp truy cập các phương pháp công khai có sẵn trong triển khai {@link android.os.Binder}
128hoặc thậm chí trong {@link android.app.Service}.
129  <p>Nên áp dụng kỹ thuật này khi dịch vụ của bạn chỉ là một trình thực hiện chạy ngầm cho ứng dụng
130của chính bạn. Lý do duy nhất bạn không nên tạo giao diện của mình bằng cách này đó là
131dịch vụ của bạn được sử dụng bởi các ứng dụng khác hoặc giữa những tiến trình khác nhau.</dd>
132
133  <dt><a href="#Messenger">Sử dụng một Hàm nhắn tin</a></dt>
134  <dd>Nếu bạn cần giao diện của mình thực hiện các tiến trình khác nhau, bạn có thể tạo
135một giao diện cho dịch vụ bằng {@link android.os.Messenger}. Bằng cách này, dịch vụ
136định nghĩa một {@link android.os.Handler} phản hồi các loại đối tượng {@link
137android.os.Message} khác nhau. {@link android.os.Handler}
138này là cơ sở cho một {@link android.os.Messenger} mà sau đó có thể chia sẻ một {@link android.os.IBinder}
139với máy khách, cho phép máy khách gửi lệnh tới dịch vụ bằng cách sử dụng các đối tượng {@link
140android.os.Message}. Ngoài ra, máy khách có thể định nghĩa {@link android.os.Messenger} của
141chính nó để dịch vụ có thể gửi lại thông báo.
142  <p>Đây là cách đơn giản nhất để thực hiện truyền thông liên tiến trình (IPC), vì {@link
143android.os.Messenger} xếp hàng tất cả yêu cầu thành một luồng duy nhất sao cho bạn không phải thiết kế
144dịch vụ của mình an toàn với luồng.</p>
145  </dd>
146
147  <dt>Sử dụng AIDL</dt>
148  <dd>AIDL (Ngôn ngữ Định nghĩa Giao diện Android) thực hiện tất cả công việc để phân tách đối tượng thành
149các phần tử mà hệ điều hành có thể hiểu được và ghép nối chúng qua các tiến trình để thực hiện
150IPC. Bằng cách sử dụng {@link android.os.Messenger}, kỹ thuật trước đó thực tế được dựa trên AIDL như là
151cấu trúc cơ bản của nó. Như đã đề cập bên trên, {@link android.os.Messenger} tạo một hàng chờ
152gồm tất cả yêu cầu của máy khách trong một luồng duy nhất, vì thế dịch vụ nhận được từng yêu cầu một. Tuy nhiên, nếu
153bạn muốn dịch vụ xử lý nhiều yêu cầu đồng thời, bạn có thể sử dụng AIDL
154trực tiếp. Trong trường hợp này, dịch vụ của bạn phải có khả năng tạo đa luồng và được xây dựng an toàn với luồng.
155  <p>Để sử dụng AIDL trực tiếp, bạn phải
156tạo một tệp {@code .aidl} định nghĩa giao diện lập trình. Các công cụ SDK Android sử dụng tệp
157này để khởi tạo một lớp tóm tắt (abstract class) nhằm triển khai giao diện và xử lý IPC, mà sau đó
158bạn có thể mở rộng trong dịch vụ của mình.</p>
159  </dd>
160</dl>
161
162  <p class="note"><strong>Lưu ý:</strong> Hầu hết ứng dụng <strong>không nên</strong> sử dụng AIDL để
163tạo một dịch vụ gắn kết, vì nó có thể yêu cầu khả năng tạo đa luồng và
164có thể dẫn đến việc triển khai phức tạp hơn. Như vậy, AIDL không phù hợp với hầu hết ứng dụng
165và tài liệu này không bàn về cách sử dụng nó cho dịch vụ của bạn. Nếu bạn chắc chắn rằng mình cần
166sử dụng AIDL trực tiếp, hãy xem tài liệu <a href="{@docRoot}guide/components/aidl.html">AIDL</a>
167.</p>
168
169
170
171
172<h3 id="Binder">Mở rộng lớp Trình gắn kết</h3>
173
174<p>Nếu dịch vụ của bạn chỉ được sử dụng bởi ứng dụng cục bộ và không cần làm việc qua nhiều tiến trình,
175khi đó bạn có thể triển khai lớp {@link android.os.Binder} của chính mình để cung cấp quyền truy cập
176trực tiếp cho máy khách của bạn để truy nhập các phương pháp công khai trong dịch vụ.</p>
177
178<p class="note"><strong>Lưu ý:</strong> Cách này chỉ có tác dụng nếu máy khách và dịch vụ nằm trong cùng
179ứng dụng và tiến trình, là trường hợp phổ biến nhất. Ví dụ, cách này sẽ hoạt động tốt đối với một ứng dụng
180nhạc cần gắn kết một hoạt động với dịch vụ của chính nó đang phát nhạc
181chạy ngầm.</p>
182
183<p>Sau đây là cách thiết lập:</p>
184<ol>
185  <li>Trong dịch vụ của bạn, hãy tạo một thực thể {@link android.os.Binder} mà hoặc:
186    <ul>
187      <li>chứa các phương pháp công khai mà máy khách có thể gọi</li>
188      <li>trả về thực thể {@link android.app.Service} hiện tại, trong đó có các phương pháp công khai mà
189máy khách có thể gọi</li>
190      <li>hoặc, trả về một thực thể của một lớp khác được lưu trữ bởi dịch vụ bằng các phương pháp công khai mà
191máy khách có thể gọi</li>
192    </ul>
193  <li>Trả về thực thể {@link android.os.Binder} này từ phương pháp gọi lại {@link
194android.app.Service#onBind onBind()}.</li>
195  <li>Trong máy khách, nhận {@link android.os.Binder} từ phương pháp gọi lại {@link
196android.content.ServiceConnection#onServiceConnected onServiceConnected()} và
197thực hiện gọi tới dịch vụ gắn kết bằng cách sử dụng các phương pháp đã nêu.</li>
198</ol>
199
200<p class="note"><strong>Lưu ý:</strong> Lý do dịch vụ và máy khách phải ở trong cùng
201ứng dụng đó là máy khách có thể đổi kiểu đối tượng được trả về và gọi các API của nó một cách phù hợp. Dịch vụ
202và máy khách cũng phải ở trong cùng tiến trình, vì kỹ thuật này không thực hiện bất kỳ thao tác
203ghép nối qua các tiến trình nào.</p>
204
205<p>Ví dụ, sau đây là một dịch vụ cung cấp cho máy khách quyền truy cập các phương pháp trong dịch vụ thông qua
206việc triển khai {@link android.os.Binder}:</p>
207
208<pre>
209public class LocalService extends Service {
210    // Binder given to clients
211    private final IBinder mBinder = new LocalBinder();
212    // Random number generator
213    private final Random mGenerator = new Random();
214
215    /**
216     * Class used for the client Binder.  Because we know this service always
217     * runs in the same process as its clients, we don't need to deal with IPC.
218     */
219    public class LocalBinder extends Binder {
220        LocalService getService() {
221            // Return this instance of LocalService so clients can call public methods
222            return LocalService.this;
223        }
224    }
225
226    &#64;Override
227    public IBinder onBind(Intent intent) {
228        return mBinder;
229    }
230
231    /** method for clients */
232    public int getRandomNumber() {
233      return mGenerator.nextInt(100);
234    }
235}
236</pre>
237
238<p>{@code LocalBinder} cung cấp phương pháp {@code getService()} cho máy khách để truy xuất
239thực thể hiện tại của {@code LocalService}. Điều này cho phép máy khách gọi các phương pháp công khai trong
240dịch vụ. Ví dụ, máy khách có thể gọi {@code getRandomNumber()} từ dịch vụ.</p>
241
242<p>Sau đây là một hoạt động gắn kết với {@code LocalService} và sẽ gọi {@code getRandomNumber()}
243khi nhấp vào nút:</p>
244
245<pre>
246public class BindingActivity extends Activity {
247    LocalService mService;
248    boolean mBound = false;
249
250    &#64;Override
251    protected void onCreate(Bundle savedInstanceState) {
252        super.onCreate(savedInstanceState);
253        setContentView(R.layout.main);
254    }
255
256    &#64;Override
257    protected void onStart() {
258        super.onStart();
259        // Bind to LocalService
260        Intent intent = new Intent(this, LocalService.class);
261        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
262    }
263
264    &#64;Override
265    protected void onStop() {
266        super.onStop();
267        // Unbind from the service
268        if (mBound) {
269            unbindService(mConnection);
270            mBound = false;
271        }
272    }
273
274    /** Called when a button is clicked (the button in the layout file attaches to
275      * this method with the android:onClick attribute) */
276    public void onButtonClick(View v) {
277        if (mBound) {
278            // Call a method from the LocalService.
279            // However, if this call were something that might hang, then this request should
280            // occur in a separate thread to avoid slowing down the activity performance.
281            int num = mService.getRandomNumber();
282            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
283        }
284    }
285
286    /** Defines callbacks for service binding, passed to bindService() */
287    private ServiceConnection mConnection = new ServiceConnection() {
288
289        &#64;Override
290        public void onServiceConnected(ComponentName className,
291                IBinder service) {
292            // We've bound to LocalService, cast the IBinder and get LocalService instance
293            LocalBinder binder = (LocalBinder) service;
294            mService = binder.getService();
295            mBound = true;
296        }
297
298        &#64;Override
299        public void onServiceDisconnected(ComponentName arg0) {
300            mBound = false;
301        }
302    };
303}
304</pre>
305
306<p>Mẫu trên cho thấy cách mà máy khách gắn kết với dịch vụ bằng cách sử dụng triển khai
307{@link android.content.ServiceConnection} và gọi lại {@link
308android.content.ServiceConnection#onServiceConnected onServiceConnected()}. Phần tiếp theo
309cung cấp thêm thông tin về tiến trình gắn kết này với dịch vụ.</p>
310
311<p class="note"><strong>Lưu ý:</strong> Ví dụ trên không công khai bỏ gắn kết khỏi dịch vụ,
312nhưng tất cả máy khách cần bỏ gắn kết tại một thời điểm phù hợp (chẳng hạn như khi hoạt động tạm dừng).</p>
313
314<p>Để biết thêm mã ví dụ, hãy xem lớp <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalService.html">{@code
315LocalService.java}</a> và lớp <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.html">{@code
316LocalServiceActivities.java}</a> trong <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
317
318
319
320
321
322<h3 id="Messenger">Sử dụng một Hàm nhắn tin</h3>
323
324<div class="sidebox-wrapper">
325<div class="sidebox">
326  <h4>So sánh với AIDL</h4>
327  <p>Khi bạn cần thực hiện IPC, việc sử dụng một {@link android.os.Messenger} cho giao diện của bạn
328sẽ đơn giản hơn so với việc triển khai nó bằng AIDL, vì {@link android.os.Messenger} xếp hàng
329tất cả lệnh gọi đối với dịch vụ, trong khi đó, giao diện AIDL thuần túy sẽ gửi các yêu cầu đồng thời tới
330dịch vụ, sau đó dịch vụ phải xử lý tạo đa luồng.</p>
331  <p>Đối với hầu hết ứng dụng, dịch vụ không cần thực hiện tạo đa luồng, vì vậy sử dụng một {@link
332android.os.Messenger} sẽ cho phép dịch vụ xử lý từng lệnh gọi tại một thời điểm. Nếu quan trọng là
333dịch vụ của bạn phải được tạo đa luồng, khi đó bạn nên sử dụng <a href="{@docRoot}guide/components/aidl.html">AIDL</a> để định nghĩa giao diện của mình.</p>
334</div>
335</div>
336
337<p>Nếu bạn cần dịch vụ của mình giao tiếp với các tiến trình từ xa, khi đó bạn có thể sử dụng một
338{@link android.os.Messenger} để cung cấp giao diện cho dịch vụ của mình. Kỹ thuật này cho phép
339bạn thực hiện truyền thông liên tiến trình (IPC) mà không cần sử dụng AIDL.</p>
340
341<p>Sau đây là tóm tắt cách sử dụng {@link android.os.Messenger}:</p>
342
343<ul>
344  <li>Dịch vụ triển khai {@link android.os.Handler} để nhận lệnh gọi lại cho mỗi
345lệnh gọi từ một máy khách.</li>
346  <li>{@link android.os.Handler} được sử dụng để tạo một đối tượng {@link android.os.Messenger}
347(là một tham chiếu tới {@link android.os.Handler}).</li>
348  <li>{@link android.os.Messenger} tạo một {@link android.os.IBinder} mà dịch vụ
349trả về máy khách từ {@link android.app.Service#onBind onBind()}.</li>
350  <li>Máy khách sử dụng {@link android.os.IBinder} để khởi tạo {@link android.os.Messenger}
351(tham chiếu tới {@link android.os.Handler} của dịch vụ), mà máy khách sử dụng để gửi các đối tượng
352{@link android.os.Message} tới dịch vụ.</li>
353  <li>Dịch vụ nhận được từng {@link android.os.Message} trong {@link
354android.os.Handler} của mình&mdash;cụ thể là theo phương pháp {@link android.os.Handler#handleMessage
355handleMessage()}.</li>
356</ul>
357
358
359<p>Theo cách này, không có "phương pháp" nào để máy khách gọi đối với dịch vụ. Thay vào đó, máy khách
360gửi “thông báo” (đối tượng {@link android.os.Message}) mà dịch vụ nhận được trong
361{@link android.os.Handler} của mình.</p>
362
363<p>Sau đây là một dịch vụ ví dụ đơn giản sử dụng một giao diện {@link android.os.Messenger}:</p>
364
365<pre>
366public class MessengerService extends Service {
367    /** Command to the service to display a message */
368    static final int MSG_SAY_HELLO = 1;
369
370    /**
371     * Handler of incoming messages from clients.
372     */
373    class IncomingHandler extends Handler {
374        &#64;Override
375        public void handleMessage(Message msg) {
376            switch (msg.what) {
377                case MSG_SAY_HELLO:
378                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
379                    break;
380                default:
381                    super.handleMessage(msg);
382            }
383        }
384    }
385
386    /**
387     * Target we publish for clients to send messages to IncomingHandler.
388     */
389    final Messenger mMessenger = new Messenger(new IncomingHandler());
390
391    /**
392     * When binding to the service, we return an interface to our messenger
393     * for sending messages to the service.
394     */
395    &#64;Override
396    public IBinder onBind(Intent intent) {
397        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
398        return mMessenger.getBinder();
399    }
400}
401</pre>
402
403<p>Để ý rằng phương pháp {@link android.os.Handler#handleMessage handleMessage()} trong
404{@link android.os.Handler} là nơi dịch vụ nhận được {@link android.os.Message}
405đến và quyết định việc cần làm dựa trên thành viên {@link android.os.Message#what}.</p>
406
407<p>Tất cả việc mà một máy khách cần làm đó là tạo một {@link android.os.Messenger} dựa trên {@link
408android.os.IBinder} được dịch vụ trả về và gửi một thông báo bằng cách sử dụng {@link
409android.os.Messenger#send send()}. Ví dụ, sau đây là một hoạt động đơn giản gắn kết với dịch vụ
410và gửi tin nhắn {@code MSG_SAY_HELLO} cho dịch vụ:</p>
411
412<pre>
413public class ActivityMessenger extends Activity {
414    /** Messenger for communicating with the service. */
415    Messenger mService = null;
416
417    /** Flag indicating whether we have called bind on the service. */
418    boolean mBound;
419
420    /**
421     * Class for interacting with the main interface of the service.
422     */
423    private ServiceConnection mConnection = new ServiceConnection() {
424        public void onServiceConnected(ComponentName className, IBinder service) {
425            // This is called when the connection with the service has been
426            // established, giving us the object we can use to
427            // interact with the service.  We are communicating with the
428            // service using a Messenger, so here we get a client-side
429            // representation of that from the raw IBinder object.
430            mService = new Messenger(service);
431            mBound = true;
432        }
433
434        public void onServiceDisconnected(ComponentName className) {
435            // This is called when the connection with the service has been
436            // unexpectedly disconnected -- that is, its process crashed.
437            mService = null;
438            mBound = false;
439        }
440    };
441
442    public void sayHello(View v) {
443        if (!mBound) return;
444        // Create and send a message to the service, using a supported 'what' value
445        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
446        try {
447            mService.send(msg);
448        } catch (RemoteException e) {
449            e.printStackTrace();
450        }
451    }
452
453    &#64;Override
454    protected void onCreate(Bundle savedInstanceState) {
455        super.onCreate(savedInstanceState);
456        setContentView(R.layout.main);
457    }
458
459    &#64;Override
460    protected void onStart() {
461        super.onStart();
462        // Bind to the service
463        bindService(new Intent(this, MessengerService.class), mConnection,
464            Context.BIND_AUTO_CREATE);
465    }
466
467    &#64;Override
468    protected void onStop() {
469        super.onStop();
470        // Unbind from the service
471        if (mBound) {
472            unbindService(mConnection);
473            mBound = false;
474        }
475    }
476}
477</pre>
478
479<p>Để ý rằng ví dụ này không cho biết cách mà dịch vụ có thể phản hồi máy khách. Nếu bạn muốn dịch vụ
480phản hồi, khi đó bạn cũng cần tạo một {@link android.os.Messenger} trong máy khách. Sau đó
481khi máy khách nhận được lệnh gọi lại {@link android.content.ServiceConnection#onServiceConnected
482onServiceConnected()}, nó sẽ gửi một {@link android.os.Message} tới dịch vụ, trong đó bao gồm
483{@link android.os.Messenger} của máy khách trong tham số {@link android.os.Message#replyTo}
484của phương pháp {@link android.os.Messenger#send send()}.</p>
485
486<p>Bạn có thể xem một ví dụ về cách cung cấp tính năng nhắn tin hai chiều trong <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.html">{@code
487MessengerService.java}</a> (dịch vụ) và các mẫu <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.html">{@code
488MessengerServiceActivities.java}</a> (máy khách).</p>
489
490
491
492
493
494<h2 id="Binding">Gắn kết với một Dịch vụ</h2>
495
496<p>Các thành phần ứng dụng (máy khách) có thể gắn kết với một dịch vụ bằng cách gọi
497{@link android.content.Context#bindService bindService()}. Hệ thống Android
498khi đó sẽ gọi phương pháp {@link android.app.Service#onBind
499onBind()} của dịch vụ, nó trả về một {@link android.os.IBinder} để tương tác với dịch vụ.</p>
500
501<p>Việc gắn kết diễn ra không đồng bộ. {@link android.content.Context#bindService
502bindService()} trả về ngay lập tức và <em>không</em> trả {@link android.os.IBinder} về
503máy khách. Để nhận một {@link android.os.IBinder}, máy khách phải tạo một thực thể của {@link
504android.content.ServiceConnection} và chuyển nó cho {@link android.content.Context#bindService
505bindService()}. {@link android.content.ServiceConnection} bao gồm một phương pháp gọi lại mà hệ thống
506gọi để gửi {@link android.os.IBinder}.</p>
507
508<p class="note"><strong>Lưu ý:</strong> Chỉ các hoạt động, dịch vụ, và trình cung cấp nội dung mới có thể gắn kết
509với một dịch vụ&mdash;bạn <strong>không thể</strong> gắn kết với một dịch vụ từ một hàm nhận quảng bá (broadcast receiver).</p>
510
511<p>Vì vậy, để gắn kết với một dịch vụ từ máy khách của mình, bạn phải: </p>
512<ol>
513  <li>Triển khai {@link android.content.ServiceConnection}.
514    <p>Việc triển khai của bạn phải khống chế hai phương pháp gọi lại:</p>
515    <dl>
516      <dt>{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()}</dt>
517        <dd>Hệ thống gọi phương pháp này để gửi {@link android.os.IBinder} được trả về bởi
518phương pháp {@link android.app.Service#onBind onBind()} của dịch vụ.</dd>
519      <dt>{@link android.content.ServiceConnection#onServiceDisconnected
520onServiceDisconnected()}</dt>
521        <dd>Hệ thống Android gọi phương pháp này khi kết nối với dịch vụ bị mất
522đột ngột, chẳng hạn như khi dịch vụ bị lỗi hoặc bị tắt bỏ. Phương pháp này <em>không</em> được gọi khi
523máy khách bỏ gắn kết.</dd>
524    </dl>
525  </li>
526  <li>Gọi {@link
527android.content.Context#bindService bindService()}, chuyển việc triển khai {@link
528android.content.ServiceConnection}. </li>
529  <li>Khi hệ thống gọi phương pháp gọi lại {@link android.content.ServiceConnection#onServiceConnected
530onServiceConnected()} của bạn, bạn có thể bắt đầu thực hiện các lệnh gọi tới dịch vụ bằng các phương pháp
531được định nghĩa bởi giao diện.</li>
532  <li>Để ngắt kết nối khỏi dịch vụ, hãy gọi {@link
533android.content.Context#unbindService unbindService()}.
534    <p>Khi máy khách của bạn bị hủy, nó sẽ bỏ gắn kết khỏi dịch vụ, nhưng bạn nên luôn bỏ gắn kết
535khi bạn đã tương tác xong với dịch vụ hoặc khi hoạt động của bạn tạm dừng sao cho dịch vụ có thể
536tắt khi không dùng đến. (Thời điểm phù hợp để gắn kết và bỏ gắn kết được đề cập
537kỹ hơn ở bên dưới.)</p>
538  </li>
539</ol>
540
541<p>Ví dụ, đoạn mã HTML sau sẽ kết nối máy khách với dịch vụ được tạo bên trên bằng cách
542<a href="#Binder">mở rộng lớp Trình gắn kết</a>, vì vậy tất cả những việc mà nó phải làm là đổi kiểu
543{@link android.os.IBinder} được trả về thành lớp {@code LocalService} và yêu cầu thực thể {@code
544LocalService}:</p>
545
546<pre>
547LocalService mService;
548private ServiceConnection mConnection = new ServiceConnection() {
549    // Called when the connection with the service is established
550    public void onServiceConnected(ComponentName className, IBinder service) {
551        // Because we have bound to an explicit
552        // service that is running in our own process, we can
553        // cast its IBinder to a concrete class and directly access it.
554        LocalBinder binder = (LocalBinder) service;
555        mService = binder.getService();
556        mBound = true;
557    }
558
559    // Called when the connection with the service disconnects unexpectedly
560    public void onServiceDisconnected(ComponentName className) {
561        Log.e(TAG, "onServiceDisconnected");
562        mBound = false;
563    }
564};
565</pre>
566
567<p>Với {@link android.content.ServiceConnection} này, máy khách có thể gắn kết với một dịch vụ bằng cách chuyển
568nó cho {@link android.content.Context#bindService bindService()}. Ví dụ:</p>
569
570<pre>
571Intent intent = new Intent(this, LocalService.class);
572bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
573</pre>
574
575<ul>
576  <li>Tham số đầu tiên của {@link android.content.Context#bindService bindService()} là một
577{@link android.content.Intent} trong đó nêu rõ tên của các dịch vụ sẽ gắn kết (mặc dù ý định
578có thể ngầm hiểu).</li>
579<li>Tham số thứ hai là đối tượng {@link android.content.ServiceConnection}.</li>
580<li>Tham số thứ ba là một cờ cho biết các tùy chọn cho gắn kết. Nên luôn luôn là {@link
581android.content.Context#BIND_AUTO_CREATE} để tạo dịch vụ nếu nó chưa hoạt động.
582Các giá trị có thể khác là {@link android.content.Context#BIND_DEBUG_UNBIND}
583và {@link android.content.Context#BIND_NOT_FOREGROUND}, hoặc {@code 0} trong trường hợp không có.</li>
584</ul>
585
586
587<h3>Lưu ý bổ sung</h3>
588
589<p>Sau đây là một số lưu ý quan trọng về việc gắn kết với một dịch vụ:</p>
590<ul>
591  <li>Bạn nên luôn bẫy các lỗi ngoại lệ {@link android.os.DeadObjectException} phát sinh khi
592kết nối bị đứt. Đây là lỗi ngoại lệ duy nhất phát sinh bởi các phương pháp từ xa.</li>
593  <li>Các đối tượng được xem là tham chiếu khắp các tiến trình. </li>
594  <li>Bạn nên luôn ghép đôi gắn kết và bỏ gắn kết trong khi
595khớp những khoảnh khắc kết nối và đứt kết nối trong vòng đời của máy khách. Ví dụ:
596    <ul>
597      <li>Nếu bạn chỉ cần tương tác với dịch vụ trong khi hoạt động của bạn hiển thị, bạn
598nên gắn kết trong khi {@link android.app.Activity#onStart onStart()} và bỏ gắn kết trong khi {@link
599android.app.Activity#onStop onStop()}.</li>
600      <li>Nếu bạn muốn hoạt động của mình nhận được phản hồi ngay cả trong khi bị dừng khi đang
601dưới nền, khi đó bạn có thể gắn kết trong khi {@link android.app.Activity#onCreate onCreate()} và bỏ gắn kết
602trong khi {@link android.app.Activity#onDestroy onDestroy()}. Chú ý rằng điều này hàm ý rằng hoạt động
603của bạn cần sử dụng dịch vụ trong toàn bộ thời gian khi nó đang chạy (ngay cả khi chạy ngầm), do đó nếu
604dịch vụ ở trong một tiến trình khác thì bạn hãy tăng trọng số của tiến trình và khả năng hệ thống
605tắt bỏ tiến trình đó sẽ cao hơn.</li>
606    </ul>
607    <p class="note"><strong>Lưu ý:</strong> Thông thường bạn <strong>không</strong> nên gắn kết và bỏ gắn kết
608trong khi {@link android.app.Activity#onResume onResume()} và {@link
609android.app.Activity#onPause onPause()} cho hoạt động của mình, vì những lệnh gọi lại này diễn ra tại mọi thời điểm chuyển tiếp vòng đời
610và bạn nên duy trì xử lý tại những thời điểm chuyển tiếp này ở mức tối thiểu. Đồng thời, nếu
611nhiều hoạt động trong ứng dụng của bạn gắn kết với cùng dịch vụ và có sự chuyển tiếp giữa
612hai trong số những hoạt động đó, dịch vụ có thể bị hủy và tạo lại khi hoạt động hiện tại bỏ gắn kết
613(trong khi tạm dừng) trước khi hoạt động tiếp theo gắn kết (trong khi tiếp tục). (Sự chuyển tiếp hoạt động này đối với cách mà các hoạt động
614phối hợp vòng đời của chúng được mô tả trong tài liệu <a href="{@docRoot}guide/components/activities.html#CoordinatingActivities">Hoạt động</a>
615.)</p>
616</ul>
617
618<p>Để biết thêm mã ví dụ, thể hiện cách gắn kết với một dịch vụ, hãy xem lớp <a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
619RemoteService.java}</a> trong <a href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
620
621
622
623
624
625<h2 id="Lifecycle">Quản lý Vòng đời của một Dịch vụ Gắn kết</h2>
626
627<p>Khi một dịch vụ bị bỏ gắn kết khỏi tất cả máy khách, hệ thống Android sẽ hủy nó (trừ khi nó cũng
628được bắt đầu bằng {@link android.app.Service#onStartCommand onStartCommand()}). Như vậy, bạn không phải
629 quản lý vòng đời dịch vụ của mình nếu nó thuần túy là một
630dịch vụ gắn kết&mdash;hệ thống Android sẽ quản lý nó cho bạn dựa trên việc nó có gắn kết với bất kỳ máy khách nào không.</p>
631
632<p>Tuy nhiên, nếu bạn chọn triển khai phương pháp gọi lại {@link android.app.Service#onStartCommand
633onStartCommand()}, vậy thì bạn phải dừng dịch vụ một cách tường minh, vì dịch vụ
634lúc này đang được coi là <em>được bắt đầu</em>. Trong trường hợp này, dịch vụ sẽ chạy cho tới khi dịch vụ
635tự dừng bằng {@link android.app.Service#stopSelf()} hoặc một thành phần khác sẽ gọi {@link
636android.content.Context#stopService stopService()}, bất kể nó có gắn kết với bất kỳ máy khách
637nào không.</p>
638
639<p>Ngoài ra, nếu dịch vụ của bạn được bắt đầu và chấp nhận gắn kết, lúc đó khi hệ thống gọi
640phương pháp {@link android.app.Service#onUnbind onUnbind()} của bạn, bạn có thể tùy chọn trả về
641{@code true} nếu bạn muốn nhận một lệnh gọi tới {@link android.app.Service#onRebind
642onRebind()} vào lần tới khi một máy khách gắn kết với dịch vụ (thay vì nhận một lệnh gọi tới {@link
643android.app.Service#onBind onBind()}). {@link android.app.Service#onRebind
644onRebind()} sẽ trả về rỗng, nhưng máy khách vẫn nhận được {@link android.os.IBinder} trong gọi lại
645{@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} của mình.
646Hình 1 bên dưới minh họa lô-gic cho loại vòng đời này.</p>
647
648
649<img src="{@docRoot}images/fundamentals/service_binding_tree_lifecycle.png" alt="" />
650<p class="img-caption"><strong>Hình 1.</strong> Vòng đời của một dịch vụ được bắt đầu
651và cũng cho phép gắn kết.</p>
652
653
654<p>Để biết thêm thông tin về vòng đời của một dịch vụ được bắt đầu, hãy xem tài liệu <a href="{@docRoot}guide/components/services.html#Lifecycle">Dịch vụ</a>.</p>
655
656
657
658
659