14/01/2019, 22:53

Network Manager In Your App With GCM Network Manager

Khi thực hiện xây dựng một ứng dụng Android bây giờ, việc phải thực thi các tác vụ với network là điều không thể tránh được. Vậy làm sao để có thể thực thi các tác vụ network một cách tối ưu nhất (các tác vụ network là một trong các tác vụ tiêu hao pin nhất) và hợp lý nhất trong từng trường hợp ...

Khi thực hiện xây dựng một ứng dụng Android bây giờ, việc phải thực thi các tác vụ với network là điều không thể tránh được. Vậy làm sao để có thể thực thi các tác vụ network một cách tối ưu nhất (các tác vụ network là một trong các tác vụ tiêu hao pin nhất) và hợp lý nhất trong từng trường hợp bạn có thể tham khảo bài viết dưới đây để hiểu rõ hơn về GCM Network Manager và cách sử dụng.

Why and When to use GCM Network Manager

Why?

Có thể bạn sẽ thắc mắc tại sao không thể sử dụng kiểu call network "NOW" - ngay lập tức trong mọi trường hợp. Trong rất nhiều trường hợp ứng dụng của bạn cần có một service để update các data, config từ phía server, nhưng đâu phải lúc nào điện thoại cũng trong tình trạng network available, như vậy bạn cũng không thể update được data từ server như mong muốn được, tại thời điểm update api có thể fail ngay lập tức nếu network not available, ý đồ của bạn không thể thực hiện được. Hoặc bạn có thể tự viết 1 service chạy ngầm liên tục để check trạng thái của network, nếu có mạng thì thực hiện giao tiếp network, nếu không có thì check lại sau một khoảng thời gian nào đó để đảm bảo việc giao tiếp với server là thành công, nhưng làm service như vậy liệu có tốt cho điện thoại, có thực sự tối ưu cho pin, hoặc với điền kiện máy khởi động lại thì service đó cũng bị end luôn không chạy tiếp, logic của bạn bị gián đoạn. Và GCM Network Manager là thứ có thể optimizes - tối ưu hóa việc giao tiếp network cho những trường hợp này và hơn thế.

Tuổi thọ của pin sẽ được cải thiện rất nhiều bằng cách tối ưu các giao tiếp network. Nếu hai hoặc nhiều request network giống nhau được gọi, GCM Network Manager có thể thay thế các request network trước bằng request cuối cùng để giảm số lượng request không cần thiết. Vì các tasks của GCM Network Manager không chạy khi thiết bị đang ở "Doze" mode, nên trường hợp này sẽ được xử lý tự động cho bạn.

Nếu một task của bạn được lên scheduled tại thời điểm network not available, thì hãy an tâm nó không bị tạch, mà GCM Network Manager sẽ giữ task đó và chỉ thực hiện nó khi network available trở lại.

When?

GCM Network Manager được thiết kế để tối ưu hóa các tác vụ network hoạt động ở background. Ví dụ như app syncing cũng là một kết quả của việc sử dụng GCM sync. GCM Network Manager không được thiết kế cho các hoạt động network call trực tiếp bởi các tương tác của người dùng như gửi mail, tin nhắn, upload ảnh hay lấy tin tức, trong những trường hợp này thì ta phải sử dụng style "NOW" rồi.

Bạn có thể tìm hiểu documents cụ thể tại đây: GCM Nework Manager documentation

Build sample use GCM Network Manager

Sau đây ta sẽ thực hiện xây dựng một app đơn giản sử dụng GCM Network Manager để có thể thấy được cách hoạt động của 2 style NOW và style GCM.

Add Auth dependency

Khởi tạo project bình thường bằng Android Studio. Sau đó thực hiện config app/build.gradle, về version thì các bạn cứ sử dụng version mới nhất được đề nghị (Android Studio sẽ hiển thị gợi ý khi version đang sử dụng thấp hơn version mới nhất), ở đây thì ta sử dụng bản 8.1.0

app/build.gradle

dependencies {
   compile 'com.google.android.gms:play-services-gcm:8.1.0'
   compile 'com.android.support:design:23.1.0'
   compile 'com.android.support:recyclerview-v7:23.1.0'
   compile 'commons-io:commons-io:2.4'
   compile 'com.google.code.gson:gson:2.3.1'
}

Add a GcmTaskService to the Manifest

Sau khi đã config xong ở app/build.gradle, thì bước tiếp theo ta sẽ thực hiện xây dựng một service extends GcmTaskService và khai báo nó trong file Manifest. Ở bài viết này ta sẽ viết một service có tên là BestTimeService và nó extends GcmTaskService.

Manifest.xml

<service android:name=".BestTimeService"
        android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"
        android:exported="true">
   <intent-filter>
       <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
   </intent-filter>
</service>

Add code to GcmTaskService

Khai báo, đặt tên thì cũng đã xong rồi. Bây giời ta thực hiện viết code cho service để thực hiện các tác vụ network theo mong muốn.

GcmTaskService đã cung cấp đầy đủ các thứ cho việc quản lý network, vì vậy để sử dụng các tính năng của GcmTaskService bạn chỉ cần để class của bạn extends GcmTaskService, cụ thể trong bài viết này là class BestTimeService.

BestTimeService.java

public class BestTimeService extends GcmTaskService {
...

Sau đó ta thực hiện implement các method cần thiết, ở đây ta sẽ implement method onRunTask() và thêm code vào đây, hầu như các đoạn code xử lý của bạn sẽ được viết ở đây, ngoài ra bạn cũng có thể implement thêm các method khác như onStartCommand(), onInitializeTasks(), ... tùy theo mục đích sử dụng khác.

Cụ tỉ trong bài viết này ta sẽ viết code để thực hiện action sau: Khi GCM task chạy, ta thực hiện call api network, khi thực hiện call network xong thì bắn LocalBroadcast để notify cho MainActivity update trạng thái của tác vụ call network đó fail hay success.

BestTimeService.java

@Override
public int onRunTask(TaskParams taskParams) {
    String taskId = taskParams.getExtras().getString("taskId");
    // Make a network call
    boolean completed = CodelabUtil.makeNetworkCall();

    Log.d(TAG, "Oneoff scheduled call executed. Task ID: " + taskId);

    // Prepare Intent to send with broadcast.
    Intent taskUpdateIntent = new Intent("task-update");
    taskUpdateIntent.putExtra("taskId", taskId);
    TaskItem taskItem = CodelabUtil.getTaskItemFromFile(this, taskId);
    if (taskItem == null) {
       return GcmNetworkManager.RESULT_FAILURE;
    }
    if (completed) {
       taskItem.setStatus(TaskItem.EXECUTED_STATUS);
    } else {
       taskItem.setStatus(TaskItem.FAILED_STATUS);
    }
    taskUpdateIntent.putExtra(CodelabUtil.TASK_STATUS, taskItem.getStatus());
    CodelabUtil.saveTaskItemToFile(this, taskItem);

    // Notify listeners (MainActivity) that task was completed successfully.
    LocalBroadcastManager localBroadcastManager =         
            LocalBroadcastManager.getInstance(this);
    localBroadcastManager.sendBroadcast(taskUpdateIntent);
    return GcmNetworkManager.RESULT_SUCCESS;
}

Schedule OneoffTask

Bây giờ ta thực hiện xây dựng 2 button "NOW" và "WHEN BEST":

  • Button NOW: thực hiện call api network ngay khi ấn.
  • Button WHEN BEST: thực hiện run OneoffTask và GCM task sẽ thực hiện call api network khi tốt nhất.

Ở MainAcitivity, ta khai báo GcmNetworkManager, đây sẽ là đối tượng để ta thực hiện run các schedule task.

MainActivity.java

private GcmNetworkManager mGcmNetworkManager;

Thực hiện khởi tạo đối tượng GcmNetworkManager ở onCreate().

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   mGcmNetworkManager = GcmNetworkManager.getInstance(this);

   ...
}

MainActivity ta thực hiện implement AddTask AsyncTask, sau đó thêm code trong method onPostExecute(), ở đây sẽ thực hiện công việc run OneoffTask của GCM hoặc run NowIntentService để call api network ngay lập tức:

MainActivity.java

@Override
protected void onPostExecute(TaskItem taskItem) {
   mTaskAdapter.addTaskItem(taskItem);
   mRecyclerView.scrollToPosition(0);

   if (taskItem.getType().equals(TaskItem.ONEOFF_TASK)) {
       Bundle bundle = new Bundle();
       bundle.putString(CodelabUtil.TASK_ID, taskItem.getId());

       // Schedule oneoff task.
       OneoffTask oneoffTask = new OneoffTask.Builder()
               .setService(BestTimeService.class)
               .setTag(taskItem.getId())
               .setRequiredNetwork(OneoffTask.NETWORK_STATE_CONNECTED)
               // Use an execution window of 30 seconds or more. Less than 30
               // seconds would not allow GcmNetworkManager enough time to
               // optimize the next best time to execute your task.
               .setExecutionWindow(0, 30)
               .setExtras(bundle)
               .build();
       mGcmNetworkManager.schedule(oneoffTask);
   } else {
       // Immediately make network call.
       Intent nowIntent = new Intent(mContext, NowIntentService.class);
       nowIntent.putExtra(CodelabUtil.TASK_ID, taskItem.getId());
       mContext.startService(nowIntent);
   }
}

Chú ý: Khi setting OneoffTask, bạn cần setting setRequiredNetwork (có nhiều option để lựa chọn tùy trường hợp mà bạn sử dụng) là NETWORK_STATE_CONNECTED để chắc chắn rằng GCM task này chỉ run khi có kết nối mạng. Ngoài ra ta thực hiện setting thêm 1 Bundle để truyền các thông tin cần sử dụng, cụ thể ở đây là TASK_ID.

Thực hiện set listener cho 2 button của chúng ta, cụ thể vs button "WHEN BEST" như sau (butotn "NOW" tương tự):

MainActivity.java

bestTimeButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
       String taskId = TASK_ID_PREFIX + 
               Calendar.getInstance().getTimeInMillis();
       Log.d(TAG, "Scheduling oneoff task. " + taskId);
       TaskItem taskItem = new TaskItem(taskId, TaskItem.ONEOFF_TASK,
               TaskItem.PENDING_STATUS);
       new AddTask(view.getContext()).execute(taskItem);
   }
});

nowButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
       String taskId = TASK_ID_PREFIX + Calendar.getInstance().getTimeInMillis();
       Log.d(TAG, "Creating a Now Task. " + taskId);
       TaskItem taskItem = new TaskItem(taskId, TaskItem.NOW_TASK, TaskItem.PENDING_STATUS);
       new AddTask(view.getContext()).execute(taskItem);
   }
});

Như vậy về cơ bản ta đã add đủ code thể thực hiện 2 chức năng call api network theo 2 style NOW và style GCM rồi. Giờ ta sẽ thực hiện test app để hiểu rõ hơn sự khác biệt của GCM.

Test Scheduling OneoffTasks

Ta sẽ thực hiện ấn 2 button NOW và WHEN BEST để check các trường hợp. Điều quan trọng là ta cần verity được 2 điều sau đây:

  • Trường hợp có mạng - network available: khi click button NOW request network sẽ được thực thi ngay lập tức, còn khi click button WHEN BEST thì request network được thực thi trong vòng khoảng 30 giây.
  • Trường hợp không có mạng (bạn có thể bật Airplane Mode lên): khi click button NOW thì request network được thực thi ngay lập tức đồng thời trả về fail, còn khi click button WHEN BEST thì request không được thực thi ngay mà phải đợi đến khi có mạng network available thì request được tự động thực hiện xử lý và trả về thành công.

Sau khi đã test các trường hợp, đồng thời verify được 2 điều trên thì bạn sẽ cơ bản hiểu cách thức hoạt động GCM Network Manager, và hiểu tại sao GCM Network Manager lại là tối ưu cho các tác vụ network ở background, và hiểu tại sao GCM Network Manager sẽ giúp cho tuổi thọ của pin sẽ tốt hơn, hiệu năng của app cũng được tăng cường.

0