+9

Android O – Những Cái Mới Mà Lập Trình Viên Cần Biết

Chào các bạn.

Cuối cùng thì tại thời điểm bài viết này đây, Android O (hay có mã là Android 8.0, có API level là 26, còn tên thì chưa biết được) cũng đã bước đến các giai đoạn Developer Review 3, chắc sẽ không lâu nữa đâu, bản cập nhật đáng mong đợi nhất của hệ điều hành này kể từ khi Android L (Android 5.0) sẽ ra đời và lần lượt triển khai đến các thiết bị của người dùng.

Có rất nhiều các bài viết ngoài kia về Android O, nhưng với bài viết này mình muốn tổng hợp lại các tính năng mới mẻ của hệ điều hành này ở góc nhìn của lập trình viên. Các tổng hợp này dựa trên kinh nghiệm “xương máu” của mình suốt mấy tuần qua hì hụi nâng cấp tương thích với Android O cho các project của công ty.

Chắc chắn các tổng hợp dưới đây của mình sẽ không hoàn toàn đầy đủ, vì có vô vàn cái mới trong phiên bản Android này, nhưng mình hi vọng nó sẽ giúp ích cho bạn trong một vài trường hợp cụ thể nào đó. Và các bạn hãy cùng mình thảo luận, nếu bạn thấy thích tính năng nào đó, hoặc bạn thấy tính năng nào khác thực sự quan trọng cần tìm hiểu mà mình chưa kịp nêu ra, hoặc cần mình điều chỉnh nội dung nào đó, thì hãy để lại comment bên dưới bài viết này nhé.

Dành cho bạn nào cần chi tiết bài viết gốc của Google, bạn có thể đọc ở link này.

Source code và demo về các tính năng nổi trội của bài hôm nay của mình cũng đã có trên Github. Chúng ta cùng nhau bắt đầu nào.

Giới Hạn Các Tác Vụ Nền

Đây không phải tính năng mới, nó là sự thay đổi, hay có thể nói là sự giới hạn mạnh mẽ nhất mà mình nghĩ là bạn nên chú ý. Sự hạn chế này không giúp ích cho lập trình viên chúng ta, mà nó còn làm chúng ta khổ sở hơn nữa. Cụ thể là, với nhu cầu muốn cải thiện đáng kể việc làm tiêu hao pin của người dùng, Android O đã quyết định hạn chế các tác vụ nền (background service) của các ứng dụng khi chúng hầu như không còn được hiển thị và tương tác bởi người dùng nữa.

Tại Sao Lại Giới Hạn Tác Vụ Nền?

Như bạn biết thì sở dĩ hệ điều hành Android được cho là nặng nề hơn các hệ điều hành khác, là vì có quá nhiều các background service này. Hầu như ứng dụng nào cũng dễ dàng tạo ra một service, với đủ các loại mục đích khác nhau. Điều này gây lãng phí một lượng lớn nguồn lực của máy, để phục vụ cho các service mà người dùng có khi chẳng bao giờ biết đến.

Chính vì vậy mà với Android O, luật chơi đã thay đổi, các ứng dụng đã vào background sẽ bị hạn chế khả năng tạo mới hay duy trì các service đó. Bạn nên nhớ là nếu như ứng dụng chưa vào background thì các service vẫn hoạt động như bình thường. Nhưng một khi ứng dụng đã vào background rồi, thì bạn sẽ không thể tạo mới các service, còn các service đang chạy khác sẽ bị dừng lại, như là bị gọi đến bởi hàm Service.stopSelf() vậy, một số service đặc biệt khác thì được phép chạy thêm vài phút nữa trước khi “tắt ngúm”.

Mặc định thì việc giới hạn này chỉ xảy ra khi ứng dụng của bạn chỉ định targetSdkVersion ở build.gradle là 26. Các ứng dụng chưa nâng cấp lên Android O vẫn hoạt động bình thường như trước đây, nhưng cẩn thận, user của bạn có thể vào Settings để bật tính năng giới hạn này lên đấy.

Cách Tương Thích

Để tương thích với Android O, tức là để có thể chạy được các tác vụ nền cho ứng dụng của bạn ở Android O khi mà app đã vào background, bạn có thể cân nhắc sử dụng JobScheduler để thay thế cho các background service, JobScheduler này được hỗ trợ từ Android 5.0 (API 21) trở lên, được cho là sẽ được hệ thống quản lý chặt chẽ và hiệu quả hơn là các background service.

Có một cách nữa, mình vừa chuyển các project công ty sang dùng cách này, đó là bạn có thể tận dụng đến hàm startForeground() để tạo một notification báo cho user biết là ứng dụng của bạn vẫn đang chạy nền, thích hợp cho các ứng dụng chơi nhạc chẳng hạn, như thế thì hệ thống sẽ không tắt background service của ứng dụng đi. Bạn nên nhớ là cách này sẽ giữ một icon app của bạn ở notification đấy nhé, nếu bạn dùng cách này không hợp lý, user sẽ thấy khó chịu vì lúc nào cũng thấy ứng dụng của bạn trên thanh notification cả.

Phần giới hạn tác vụ nền này mình không có demo, bạn nào gặp phải tình trạng này khi nâng cấp lên Android O mà có khó khăn gì, thì liên lạc với mình nhé.

Notification Theo Từng Kênh

Cái tên đã nói lên tất cả, tính năng mới này của Android O cho phép bạn tạo kênh riêng cho các notification trong ứng dụng.

Cũng theo Google có nói, tính năng này của notification chỉ dùng được cho các ứng dụng có target là Android O mà thôi. Các ứng dụng chưa set target là Android O thì vẫn cứ hiển thị notification như với Android 7.0 (dù đang chạy trên Android O), do đó bạn hãy mau mau đọc phần sau và nâng cấp cho ứng dụng ngay nhé.

Mục Đích Của Việc Tạo Kênh Cho Notification Là Gì?

Có thể thấy rằng với Android O, Google muốn tập trung vào trải nghiệm của user nhiều hơn. Điều đó được thể hiện qua việc tạo kênh cho notification này, cốt là để giúp user của bạn có khả năng quản lý độ ưu tiên của các nhóm này tốt hơn. Khi đó hệ thống sẽ hỗ trợ user có thể vào Settings, hay nhấn giữ một notification nào đó, để họ có thể điều chỉnh độ ưu tiên cho từng kênh notification theo các cấp độ mà họ mong muốn.

Dưới đây là hình chụp từ ứng dụng demo mà mình có để link ở trên kia, cho thấy khi vào Settings, user có thể trông thấy và điều chỉnh độ ưu tiên cho từng kênh (các kênh này mình khai báo tạm là Channel 1, Channel 2,…).

Tạo Kênh Cho Notification

Với các ứng dụng có target là Android O. Trước khi tạo một notification, bạn phải tạo ra ít nhất một kênh notification nào đó trước. Bạn có thể tạo một kênh ngay khi ứng dụng được chạy, chứ không nhất thiết là đợi có push notification gửi về.

Câu lệnh tạo ra một kênh cho notification bạn có thể xem chi tiết ở link gốc này và trong source code demo của mình. Dưới đây là code mẫu.

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// The id of the channel.
String id = "my_channel_01";
// The user-visible name of the channel.
CharSequence name = getString(R.string.channel_name);
// The user-visible description of the channel.
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.enableLights(true);
// Sets the notification light color for notifications posted to this
// channel, if the device supports this feature.
mChannel.setLightColor(Color.RED);
mChannel.enableVibration(true);
mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
mNotificationManager.createNotificationChannel(mChannel);

Tạo Nhóm Kênh Cho Notification

Ngoài việc tạo một kênh cho notification, bạn còn có thể tạo nhiều nhóm kênh để gom nhóm các kênh lại, việc tạo một nhóm kênh này không bắt buộc. Nhóm kênh này sẽ giúp cho khi user vào Settings, họ sẽ có cái nhìn rõ ràng hơn, cho từng các kênh. Chẳng hạn như một ứng dụng có nhiều loại tài khoản, khi đó nếu user vào Settings, họ có thể điều chỉnh độ ưu tiên cho từng kênh, của từng nhóm kênh khác nhau. Chà chà, sướng user chứ có sướng cho lập trình viên đâu chớ. Hic.

Các nhóm kênh như Group 1, Group 2 có xuất hiện ở hình chụp màn hình trên kia. Dưới đây là đoạn code mẫu để tạo một nhóm kênh của Google.

// The id of the group.
String group = "my_group_01";
// The user-visible name of the group.
CharSequence name = getString(R.string.group_name);;
NotificationManager mNotificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannelGroup(new NotificationChannelGroup(group, name));

Sau khi có nhóm kênh, thì bạn có thể chỉ định kênh nào thuộc vào nhóm kênh nào như đoạn code sau.

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// The id of the channel.
String id = "my_channel_01";
// The user-visible name of the channel.
CharSequence name = getString(R.string.channel_name);
// The user-visible description of the channel.
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.enableLights(true);
// Sets the notification light color for notifications posted to this
// channel, if the device supports this feature.
mChannel.setLightColor(Color.RED);
mChannel.enableVibration(true);
mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
mChannel.setGroup("my_group_01");
mNotificationManager.createNotificationChannel(mChannel);

Tạo Notification

Việc tạo một notification cho Android O không khác nhiều so với notification ở các phiên bản trước, chỉ có điều là lần này bạn phải chỉ định một kênh cho nó, thông qua hàm khởi tạo của Notification.Builder(). Có một khác biệt nữa, là bạn không cần gọi setPriority() trong quá trình tạo notification nữa, bởi vì priority đã được chỉ định ở khai báo kênh rồi, bạn có thể xem lại các dòng code tạo kênh bên trên. Bạn xem code mẫu sau cho việc tạo một notification.

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Sets an ID for the notification, so it can be updated.
int notifyID = 1;
// The id of the channel.
String CHANNEL_ID = "my_channel_01";
// Create a notification and set the notification channel.
Notification notification = new Notification.Builder(MainActivity.this, CHANNEL_ID)
        .setContentTitle("New Message")
        .setContentText("You've received new messages.")
        .setSmallIcon(R.drawable.ic_notify_status)
        .build();
// Issue the notification.
mNotificationManager.notify(id, notification);

Bạn có thể xem thêm ở bài viết gốc này để có nhiều thông tin hơn về việc tạo kênh hoặc tạo nhóm kênh, và xóa kênh nếu như bạn không còn sử dụng đến notification cho kênh đó nữa. Bạn cũng có thể xem code từ ứng dụng demo của mình.

Notification Badge

Nếu như notification trên đây quá quen thuộc với chúng ta từ các hệ điều hành Android trước. Thì sang Android O, chúng ta có thêm khái niệm Notification badge. Đây là một tính năng mới. Khi có một notification đến, thay vì bạn phải vuốt thanh notification xuống để xem các notification của tất cả các ứng dụng, giờ đây với Android O, bạn có thể nhấn giữ lên bất kỳ icon app nào để nó xổ ra một danh sách các notification (nếu có) của riêng nó. Ngoài ra, khi có notification đến, một chấm tròn sẽ xuất hiện trên icon app tương ứng với notification của app đó, chấm tròn này còn được gọi là notification dot.

Các Notification bình thường và các Notification badge này có liên kết với nhau, một khi Nofication bình thường bị mất đi thì Notification badge cũng bị xóa tương ứng, và ngược lại.

Việc xuất hiện notification trên Notification badge là hoàn toàn tự động. Tuy nhiên bạn cũng có thể vô hiệu hóa việc hiển thị Notification badge này bằng cách gọi setShowBadge(false) trong quá trình khai báo một kênh notification như sau.

NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// The ID of the channel.
String id = "my_channel_01";
// The user visible name of the channel.
CharSequence name = getString(R.string.channel_name);
// The user visible description of the channel.
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
// Configure the notification channel.
mChannel.setDescription(description);
mChannel.setShowBadge(false);
mNotificationManager.createNotificationChannel(mChannel);

Một ý nhỏ nữa, rằng Notification badge sẽ tự động đếm các notification còn đang hiển thị trong danh sách, như hình trên bạn có thấy số 2 khi nhấn giữ icon app không? Bạn cũng có thể thay đổi số đếm này cho một số mục đích nào đó, bằng hàm setNumber() sau, khi bạn tạo một notification.

mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int notificationID = 1;
String CHANNEL_ID = "my_channel_01";
// Set a message count to associate with this notification in the long-press menu.
int messageCount = 3;
// Create a notification and set a number to associate with it.
Notification notification = new Notification.Builder(MainActivity.this)
        .setContentTitle("New Messages")
        .setContentText("You've received 3 new messages.")
        .setSmallIcon(R.drawable.ic_notify_status)
        .setChannelId(CHANNEL_ID)
        .setNumber(messageCount)
        .build();
// Issue the notification.
mNotificationManager.notify(notificationID, notification);

Bạn có thể xem thêm link gốc này để biết chi tiết về notification badge.

Ngoài các ý trên đây về notification của mình, thì còn hàng tá cái hay nữa mà trong khuôn khổ bài viết mình không thể trình bày hết được. Như set timeout cho phép notification tự hẹn giờ tắt, cách xóa notification nếu user không tự xóa nó, tạo màu sắc hay các nội dung màu mè khác cho notification,…

Chế Độ Picture-in-Picture (PIP)

Chế độ này trước đây xuất hiện trên Android TV, thú thiệt là trước đây mình chưa thử bao giờ. Nay Google nói là mang nó lên Android O, mình mới quyết định thử xem sao và mang nó vào bài viết hôm nay.

Dành cho các bạn nào chưa biết. PIP là một tính năng thú vị, nó cho phép ứng dụng của bạn thu lại thành một cửa sổ nho nhỏ và neo vào một góc màn hình, trong khi user vẫn có thể tương tác với các ứng dụng khác. Tuy nhiên như mình được biết, thì chế độ này khá “kén” mục đích sử dụng. Thường thì vì ứng dụng của bạn là một ứng dụng video, và bạn muốn user không bỏ lỡ từng giây phút trong video của bạn, nên bạn hỗ trợ PIP. Hoặc ứng dụng bạn có chức năng video call, cũng sẽ rất tốt nếu bạn sử dụng PIP để hiển thị ứng dụng với một cửa sổ nho nhỏ.

Việc thu ứng dụng của bạn lại thành một cửa sổ nhỏ đó như thế nào là chuyện của hệ thống, việc của chúng ta là thử nghiệm xem làm thế nào để một ứng dụng có thể thu nhỏ như vậy được.

Đầu tiên, bạn phải báo cho hệ thống biết Activity nào được phép sử dụng mode PIP này, thông qua khai báo cho Activity đó các thuộc tính sau ở Manifest.

<activity android:name="VideoActivity"
    android:resizeableActivity="true"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"

Sau đó, ở sự kiện nào đó, bạn có thể gọi đến hàm enterPictureInPictureMode() như sau.

@Override
public void onActionClicked(Action action) {
    if (action.getId() == R.id.lb_control_picture_in_picture) {
        getActivity().enterPictureInPictureMode();
        return;
    }

Khá đơn giản đúng không nào, bạn có thể thử ngay bây giờ.

Bạn có thể xem source code và cách hành xử của chế độ này trong ứng dụng demo của mình ở link trên kia. Tuy nhiên mình cũng khuyên bạn nên đọc thêm một chút ở link gốc này, sẽ có một vài ý nhỏ nữa dành cho bạn để hoàn thiện app hơn.

Autofill Framework

Có thể nói rằng tính năng này của Android khá thú vị, các lập trình viên chúng ta nên dành chút thời gian nghiên cứu về nó. Tính năng này giúp cho các field bên trong các ứng dụng Android có thể lưu và chia sẽ dữ liệu với nhau, sau đó chúng sẽ gợi ý và điền các dữ liệu đó vào các field tương ứng.

Thực sự thì ở thời gian này, mình vẫn chưa có cái nhìn rõ ràng nhất về tính năng Autofill này của Android. Chắc chắn mình sẽ tìm hiểu, và có bài viết demo về nó, còn bây giờ để các bạn dễ hình dung nhất, bạn có thể click vào để xem video này, đây video demo về Autofill Framework được quay ở sự kiện Google I/O 2017 vừa qua.

Adaptive Icons

Hỗ trợ này từ Android O có thể hiểu là, bạn có thể làm cho các icon app có sự thích nghi. Thích nghi như thế nào? Tức là các lập trình viên chúng ta cần đảm bảo được tất cả các hình thù khác nhau cho icon, như icon tròn, vuông, vuông có bo góc, hay vuông gần như tròn, v.v… Rồi sau đó tùy từng thiết bị phần cứng, họ (nhà sản xuất phần cứng) sẽ chỉ định hình dáng cho các icon app, và thế là app của chúng ta do có sự thích nghi tốt, sẽ được nhìn thấy hòa hợp với các kiểu dáng của các icon khác.

Bạn cứ tưởng tượng như các ứng dụng launcher ngày xưa vậy, các launcher này “ép” các icon của các ứng dụng khác vào một dạng hình thù nào đó, nhưng khi đó lập trình viên chúng ta không có sự chuẩn bị trước các adaptive icon này, nên có thể sẽ không hiển thị đẹp như mong muốn. Giờ thì Android O đã hỗ trợ, và rồi chúng ta không phải lo nghĩ nhiều về các yêu cầu quái gở từ các phần cứng hay các launcher khác nữa nhé.

Việc của bạn thì không cần làm gì nhiều, chỉ cần dùng đến công cụ Image Asset mà mình cũng có nói qua ở bài viết này của mình. Nhưng lần này bạn phải dùng Android 3.0 trở lên thì công cụ Image Asset này mới có thể hỗ trợ adaptive icon cho Android O được nhé. Công cụ Image Asset này sẽ giúp gì khi bạn dùng đến nó để tạo bộ icon mới?

  • Đối với các hệ điều hành trước Android O, Image Asset vẫn tạo các ảnh icon vuông và tròn như bình thường. Bằng chứng là trong res/mipmap-mdpi/ của ứng dụng demo của mình vẫn có các icon 48 x 48 dp này.
  • Với Android O, ví dụ cũng trong thư mục res/mipmap-mdpi/ này, Image Asset tạo thêm một ảnh foreground có kích thước 108 x 108 dp, và một ảnh background với kích thước tương ứng. Ảnh foreground này phải đảm bảo nội dung chính của nó nằm gọn trong cái diện tích 72 x 72 dp. Vậy thì 18 dp trống xung quanh icon foreground này sẽ được dùng cho các thể loại mặt nạ tròn, bo góc gì đó mà mình có nhắc đến trên đây. Ngoài ra thì không gian trống đó còn mang lại cho icon của bạn có các hiệu ứng rung, lắc, kết hợp với parallax (kỹ thuật này sẽ tạo ra nhiều lớp ảnh, các lớp ảnh này sẽ đè lên nhau và di chuyển với các vận tốc và vị trí khác nhau, tạo ra một hiệu ứng chiều sâu cho ảnh).

Chúng ta sẽ xem qua các bước tạo một bộ adaptive icon như sau. Ở ứng dụng demo của mình, mình đã làm rồi, nếu bạn muốn thử nghiệm lại thì có thể vào link này để download một icon app trong suốt về rồi dạo qua các bước như sau.

  • Từ project của bạn, bạn click phải chuột vào res/ và chọn New > Image Asset.
  • Popup xuất hiện như sau.
  • Tại đây, Icon TypeName bạn cứ để như hình trên.
  • Phí dưới Name sẽ có ba tap, tương ứng với ba tùy chọn quan trọng dành cho bạn. Đầu tiên là tab Foregaround Layer, tab này cho phép bạn chọn ảnh làm foreground. Đó có thể là một ảnh bitmap của bạn, hay ảnh từ thư viện Clip Art của Google, thậm chí là text. Với bước này của mình thì mình sẽ chọn ảnh vừa download từ link mình để trên kia. Kết quả trông như sau.
  • Sau đó qua tab Background Layer. Tại đây, nếu bạn chỉ định một ảnh, thì icon của bạn sẽ có hai lớp ảnh chồng lên nhau. Một ảnh là ic_launcher_foreground và một ảnh là ic_launcher_background. Nhưng ở tab này của mình thì mình lại chọn màu vàng đặc trưng của Yellow Code Books. Vậy khi đó sẽ không có ảnh background, thay vào đó hệ thống sẽ định nghĩa màu tương ứng trong resource color.
  • Tab Legacy chủ yếu giúp bạn xác nhận lại rằng có cần sử dụng hay không một số dạng icon nào đó. Bạn có thể để như mặc định bên tab này và nhấn Next rồi nhấn Finish ở bước sau đó.
  • Sau khi hoàn tất, bạn có thể vào project và kiểm tra. Khi này trong các thư mục mipmap truyền thống, như mipmap-mdpi/ chẳng hạn, sẽ có các icon truyền thống ic_launcher.pngic_launcher_round.png. Bên cạnh đó bạn sẽ thấy thêm ic_launcher_foreground.pngic_launcher_background.png (trường hợp của ví dụ trên không có launcher background vì mình đã chỉ định màu sắc thay thế ảnh). Ngoài ra nếu bạn vào mipmap-anydpi-v26/, đây là một alternative resource khá chất, nó được sử dụng cho tất cả các màn hình có chạy hệ điều hành Android O, bạn xem, trong đây định nghĩa các icon là các file XML, chính Android O sẽ sử dụng file này để vẽ icon, trong đó định nghĩa ra hai lớp ảnh tương đương với hai thẻ backgroundforeground, để giúp tạo các hiệu ứng như mình có nói bên trên. Thật là vi diệu.

Downloadable Fonts

Với Android O thì việc download và sử dụng font được thuận tiện hơn. Theo đó, trước đây, nếu như bạn muốn sử dụng một font, bạn phải để sẵn font vào resource và build kèm với APK, hoặc bạn chỉ định APK download font sau đó để sử dụng. Dù làm với cách nào đi nữa thì vẫn khiến APK của bạn phình lên, hoặc gây ra một chút khó khăn cho logic của ứng dụng. Vậy là với Android O, và nếu bạn có sử dụng thư viện Support, thì có thể hỗ trợ ngược đến Android API 14, sẽ giúp download font mà ứng dụng yêu cầu, vào catch của hệ thống, và khi đó các ứng dụng khác cũng có thể dùng đến font này mà hệ thống không cần phải download lại.

Bạn có quyền chọn nhiều cách để thiết lập font cho widget, và yêu cầu hệ thống download font cho bạn dùng, như link gốc này đây. Nhưng các bước dưới đây mình sẽ sử dụng công cụ hỗ trợ từ Android Studio 3.0, mọi thứ diễn ra suôn sẻ và dễ dàng.

Điều Kiện Sử Dụng Downloadable Font

Để sử dụng các bước dưới đây của mình, bạn phải đảm bảo các thông số sau.

  • Sử dụng Android Studio 3.0 trở lên (hoặc bản Android Studio 3.0 Preview cũng được).
  • Sử dụng thư viện com.android.support:appcompat-v7 version 26.0.0-beta1 trở lên.
  • Thiết bị được cài đặt phải có Google Play service phiên bản 11 trở lên.

Cách Sử Dụng Downloadable Font

Giờ thì mọi thứ rất dễ dàng. Ở editor của layout, bạn chọn tab Design, chọn widget cần áp dụng font, rồi nhìn bên danh sách các tùy chọn ở cửa sổ Attributes, chọn vào fontFamily > More Fonts…. Như hình sau. Cửa sổ tiếp theo xuất hiện, bạn cứ tìm cho ứng dụng một font ưng ý. Sau khi bạn nhấn OK, Android Studio sẽ định nghĩa các thông tin cần thiết để hệ thống có thể download và ứng dụng của bạn có thể sử dụng font này khi được khởi chạy. Bao gồm cả việc định nghĩa chứng nhận sở hữu, tiền khai báo giúp download font trước khi ứng dụng của bạn sử dụng tới nhằm giảm thiểu độ trễ.

Bạn có thể xem ví dụ về sử dụng dowloadable font của ứng dụng demo của mình.

Sử Dụng Font Từ XML

Lại một tính năng mới hỗ trợ cho font, nhưng khác với mục trên đây nói về việc bạn có thể download các font về dùng thoải mái. Tính năng này tập trung vào việc nếu như bạn đã có bộ font chuẩn của riêng bạn và không mong muốn download bất kỳ font nào khác, thì sao?

Từ Google cho hay, với Android O, và nếu dùng thư viện Support như ở mục trên đây mình có liệt kê, sẽ có thể áp dụng được cho Android API từ version 24. Nếu như trước đây, bạn phải để font vào đâu đó trong thư mục res/ rồi gọi chúng thông qua hàm setTypeface(). Thì giờ bạn đã có thể gọi đến chúng ở XML thông qua id như bình thường. Như cách dùng của mình đến font roboto_medium.ttf như sau.

<TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fontFamily="@font/roboto_medium"
        android:text="Cupcake ipsum dolor sit. Amet chupe chups tiramisu dessert. Marshmallow jelly bonbon sessert halvah pastry candy canes dragee. Jujubes liquorice sesame snaps halvah toffee toffee dessert" />

Hoặc bạn có thể tạo một file font-family để có thể định nghĩa các dạng của font, như hình trên, mình muốn tổng hợp roboto_medium.tffroboto_italic.tff vào trong cùng một font-family roboto.xml, rồi sau đó tùy vào style của widget mà hệ thống sẽ load font tương ứng. Bạn xem cách khai báo roboto.xml của mình như sau.

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <font
        android:font="@font/roboto_medium"
        android:fontStyle="normal"
        android:fontWeight="400"
        app:font="@font/roboto_medium"
        app:fontStyle="normal"
        app:fontWeight="400" />
 
    <font
        android:font="@font/roboto_italic"
        android:fontStyle="italic"
        android:fontWeight="400"
        app:font="@font/roboto_italic"
        app:fontStyle="italic"
        app:fontWeight="400" />
</font-family>

Cách dùng đến roboto.xml thì cũng tương tự như khi bạn gọi trực tiếp đến file font thôi.

<TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:fontFamily="@font/roboto"
        android:textStyle="italic"
        android:text="Cupcake ipsum dolor sit. Amet chupe chups tiramisu dessert. Marshmallow jelly bonbon sessert halvah pastry candy canes dragee. Jujubes liquorice sesame snaps halvah toffee toffee dessert" />

Bạn cũng có thể xem source code và demo đầy đủ của mình ở link này, hoặc có thể đọc link gốc của Google ở link này.

Một Số Tính Năng Hữu Ích Khác

Do còn khá nhiều tính năng mới xuất hiện trên Android O, mà mình có trình bày hết chắc chắn sẽ khó cho mình và khó cho bạn nữa. Do đó mình liệt kê một số tính năng còn lại một cách tóm tắt ở đây, bạn có thể vào link gốc của Google để xem một cách đầy đủ hơn. Bạn cũng có thể xem source code ứng dụng demo của mình.

Vậy các tính năng còn lại là gì?

Autosizing TextView

Tính năng này mình nghĩ theo lẽ Android nên thêm vào sớm hơn, so với việc bây giờ mới xuất hiện. Nhưng dù sao thì có còn hơn không.

Tính năng hữu ích này cho phép bạn thêm một vài thuộc tính vào cho TextView, và thế là thay vì TextView được cố định font chữ như trước đây, thì giờ nó có thể tự điều chỉnh kích thước font chữ cho vừa với khung chứa. Nếu như trước đây bạn phải dùng đến thư viện bên ngoài, thì giờ bạn đã an tâm dùng hàng “chính chủ” rồi nhé.

Bạn có thể xem link gốc ở đây.

Hoặc bạn có thể xem source code ứng dụng demo của mình.

App Shortcuts, Pinning Shortcuts & Pinning Widgets

App shortcuts nghe đồn là đã được hỗ trợ từ Android 7.1 (API level 25) rồi, nhưng mình vẫn chưa có dịp dùng tới. Nên nay nhân dịp Android O “khai trương” Pinning shortcutsPinning widgets thì mình nói đến cả ba cùng một lúc luôn.

Tất cả chúng đều đóng vai trò là các shortcut, giúp user đi tắt vào các thành phần bên trong ứng dụng của bạn. Về cách sử dụng thì hơi khác nhau chút.

Nếu như App shortcut là các danh sách xuất hiện khi user nhấn giữ vào icon app. Như hình sau. Trông hơi giống với Notification badge trên kia, nhưng không phải Notification badge đâu nhé. Còn Pinning shortcutPinning widget là các icon tược tách ra khỏi app chính. Như hình dưới. Bằng cách kéo thả các App shortcut ở trên vào launcher, hay bằng code trong ứng dụng của bạn. Trong ứng dụng demo của mình đã có thử nghiệm tính năng App shortcutPinning shortcut, bạn xem nhé. Ngoài ra nếu bạn muốn biết nhiều hơn về App shortcut thì có thể xem ở link này. Còn muốn biết về Pinning shortcutPinning widget thì xem ở link này.

Bổ Sung Thuộc Tính Cho margin Và pading

Đây là một nâng cấp nhỏ thôi. Đó là giờ đây bạn có thêm các thuộc tính sau, khi định nghĩa margin và padding cho view.

  • layout_marginVertical – Dùng thuộc tính này để thay thế luôn cho cả layout_marginToplayout_marginBottom nếu giá trị của chúng như nhau.
  • layout_marginHorizontal – Dùng để thay thế cho cả layout_marginLeftlayout_marginRight nếu giá trị của chúng như nhau.
  • paddingVertical – Dùng để thay thế cho cả paddingToppaddingBottom nếu giá trị của chúng như nhau.
  • paddingHorizontal – Dùng để thay thế cho cả paddingLeftpaddingRight nếu giá trị của chúng như nhau.

Thay Đổi Kiểu Trả Về Khi Gọi Hàm findViewById()

Điều này, như Google có nói là, giờ đây hàm findViewById() đã trả về kiểu <T extends View> chứ không còn là View như ngày xưa nữa. Vậy thì có gì khác biệt? Trước mắt mình thấy rằng khi gọi đến hàm này khi khai báo bất kỳ một view nào khác là con của View, như Button, TextView,… thì chúng ta không cần phải ép kiểu chúng nữa. Tức là cách viết cũ như thế này.

TextView tvNone = (TextView) findViewById(R.id.tv_none);
SeekBar sbNone = (SeekBar) findViewById(R.id.sb_none);

Thì chỉ cần viết như này với Android O thôi.

TextView tvNone = findViewById(R.id.tv_none);
SeekBar sbNone = findViewById(R.id.sb_none);

Mình chỉ mới vừa kiểm chứng tính năng này của findViewById(), nếu bạn biết việc thay đổi này còn giúp ích cho các trường hợp nào khác thì bạn giúp mình và các bạn khác comment bên dưới bài viết hôm nay nhé.

Kết Luận

Mình vừa trình bày một số các thay đổi và các tính năng mới trên Android O, hi vọng sẽ giúp ích cho các bạn rất nhiều trong việc nâng cấp các ứng dụng của các bạn, hoặc cho các bạn nào đang xây dựng mới ứng dụng Android, cũng có thể hiểu được bạn phải thêm gì cho chúng, để bắt kịp xu thế thay đổi của nền tảng Android này.

Chắc chắn nội dung bài viết sẽ còn được mình cập nhật ở blog của mình ở địa chỉ yellowcodebooks.com khi mình tìm hiểu thêm vài tính năng mới nữa, các bạn nên thường xuyên ghé qua kiểm tra nhé.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí