Service trong lập trình Android

(ZmikiSoft.com) – Service trong lập trình Android.

Service là một thành phần ứng dụng có khả năng thực hiện các thao tác chạy kéo dài trong nền và không cung cấp giao diện người dùng. Một thành phần ứng dụng khác có thể bắt đầu một dịch vụ và nó sẽ tiếp tục chạy ngầm ngay cả khi người dùng chuyển sang một ứng dụng khác. Ngoài ra, một thành phần có thể gắn kết với một dịch vụ để tương tác với nó và thậm chí thực hiện truyền thông liên tiến trình (IPC). Ví dụ, một dịch vụ có thể xử lý các giao dịch mạng, phát nhạc, thực hiện I/O tệp, hoặc tương tác với một trình cung cấp nội dung, tất cả đều xuất phát từ nền.

Ví dụ đơn giản dễ hiểu:

Bạn mở một ứng dụng để chạy một bài hát, ứng dụng sẽ mở ra có giao diện để bạn thao tác ( chọn bài hát cho bài hát chạy, dừng …), nhưng sau đó bạn click vào button Home, Back trên Android để ứng dụng không còn hiện thị trên màn hình Android thì bạn vẫn nghe bài hát đó. Lúc này bạn không thấy giao diện của ứng dụng nữa nhưng bài hát vẫn được chơi => đây chính là service đang chạy. Nó thực hiện nhiệm vụ nhưng không cần giao diện hiện thị. Không phải ứng dụng chơi nhạc nào cũng sử dụng cách này, nên bạn có thể sẽ thấy khi sử dụng ứng dụng này thì click Back/Home ứng dụng vẫn hát, nhưng sử dụng ứng dụng khác thì khi Back/Home ứng dụng cũng dừng chơi nhạc, chỉ ứng dụng nào có sử dụng service trong nó thì khi Back/Home ứng dụng mới tiếp tục chạy ngầm.

Để sử dụng một service trong ứng dụng ta có 2 cách:

  • startService():  Sau khi được bắt đầu, dịch vụ có thể chạy ngầm vô thời hạn, ngay cả khi thành phần bắt đầu nó bị hủy. Thông thường, dịch vụ được bắt đầu sẽ thực hiện một thao tác đơn lẻ và không trả về kết quả cho hàm gọi. Ví dụ, nó có thể tải xuống hoặc tải lên một tệp thông qua mạng. Khi thao tác được hoàn thành, dịch vụ tự nó sẽ dừng lại. Ví dụ dễ hiểu: khi bạn startService từ một Activity thì khi Activity đó destroy rồi thì service vẫn chạy.
  • bindService(): Dịch vụ gắn kết sẽ đưa ra một giao diện máy khách-máy chủ cho phép các thành phần tương tác với dịch vụ, gửi yêu cầu, nhận kết quả, và thậm chí làm vậy thông qua truyền thông liên tiến trình (IPC). Dịch vụ gắn kết chỉ chạy trong khi một thành phần ứng dụng khác được gắn kết với nó. Nhiều thành phần có thể gắn kết cùng lúc với dịch vụ, nhưng khi tất cả bị bỏ gắn kết thì dịch vụ sẽ bị hủy. Ví dụ dễ hiễu: khi bạn chạy một ứng dụng download file, nếu ứng dụng sử dụng bindService thì cách thức sẽ như sau: service thực hiện download dữ liệu từ server và sau mỗi phần trăm download được, service sẽ gửi thông tin báo cáo lên Activity, tại đây Activity nhận thông tin và hiện thị ra cho người dùng biết.

Chú ý: 

Cần phân biệt Service và Thread. Chúng đều có điểm giống nhau là chạy không cần giao diện hiện thị, nhưng chúng là 2 thành phần khác nhau. Service là thành phần của ứng dụng không phải Thread, có thể hiểu Service là thành phần như Activity nhưng không có giao diện. Do đó những tác vụ nào cần thực hiện nặng thì chúng ta NÊN cho vào một Thread để thực hiện. Nhưng trong quá trình sử dụng cần tránh sự xung đột giữa các thread với nhau, đặc biệt là UIThread với các Thread chạy tác vụ khác.

Khai báo để sử dụng:

Cũng giống như Activity, Service khi sử dụng cũng cần phải khai báo trong file Manifest.

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>


Khi khai báo Manifest các bạn chú ý có thể khai báo android:exported = “false” để tránh việc các ứng dụng khác sử dụng service của bạn.

Giới thiệu các Class service

  •  Service: Đây là lớp cơ bản cho tất cả dịch vụ. Khi bạn mở rộng lớp này, điều quan trọng là bạn tạo một luồng mới để thực hiện tất cả công việc của dịch vụ trong đó, do dịch vụ sử dụng luồng chính của ứng dụng của bạn, theo mặc định, điều này có thể làm chậm hiệu năng của bất kỳ hoạt động nào mà ứng dụng của bạn đang chạy.
  •  IntentService: Đây là một lớp con của Service có chức năng sử dụng một luồng trình thực hiện để xử lý tất cả yêu cầu bắt đầu một cách lần lượt. Đây là lựa chọn tốt nhất nếu bạn không yêu cầu dịch vụ của mình xử lý đồng thời nhiều yêu cầu. Tất cả những gì bạn cần làm đó là triển khai onHandleIntent(), nó sẽ nhận ý định cho mỗi yêu cầu bắt đầu để bạn có thể thực hiện công việc chạy ngầm.

Một ví dụ về Service

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          long endTime = System.currentTimeMillis() + 5*1000;
          while (System.currentTimeMillis() < endTime) {
              synchronized (this) {
                  try {
                      wait(endTime - System.currentTimeMillis());
                  } catch (Exception e) {
                  }
              }
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

Một ví dụ về IntentService

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super 
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}

 

Khóa học lập trình Android
Khóa học lập trình Java
Khóa học lập trình iOS
Khóa học lập trình Objective-C/Swift