หลังจากที่ Android O เปิดตัวมาได้ซักพัก ก็ได้มีบทความเกี่ยวกับการเปลี่ยนแปลงในเวอร์ชันใหม่นี้ไปแล้ว ซึ่งเจ้าของบล็อกก็ไม่มีเหตุผลว่าทำไมต้องไปเขียนซ้ำกับคนอื่นอีก ก็เลยหนีมาเขียนเรื่องนี้แทน เพื่อให้ผู้ที่หลงเข้ามาอ่านได้รู้ว่านอกจากฟีเจอร์หลักๆแล้ว มีคำสั่งอะไรบ้างที่เปลี่ยนแปลงไป
ก่อนที่จะอ่านต่อ
ถ้ายังไม่รู้ว่าฟีเจอร์หลักของ Android O มีอะไรบ้างที่มีผลต่อนักพัฒนา ให้ไปอ่านจากบทความเพื่อนบ้านก่อนเลย• มาดูกันว่า Android O มีอะไรใหม่บ้าง ในแบบฉบับนักพัฒนา
• สรุปของเล่นใหม่คร่าวๆใน ANDROID O(MG) ฉบับ DEVELOPER
ป่ะ ลุยกันต่อ
นอกจากจะมีฟีเจอร์ใหม่ๆ และคำสั่งใหม่ๆสำหรับฟีเจอร์เหล่านั้นแล้ว ก็ยังมีการเปลี่ยนแปลงของโค้ดใน API เก่าที่มีอยู่ด้วย ซึ่งเจ้าของบล็อกเข้าไปนั่งไล่ส่องมาแล้ว ก็เลยขอหยิบเฉพาะคำสั่งของคลาสที่สำคัญๆมาให้ดูนะConfiguration
ชื่อเต็ม : android.content.res.Configurationมีการเพิ่มคำสั่งเข้ามาเพื่อให้รองรับการแสดงผลบนหน้าจอที่รองรับ HDR และ Wide Color Gamut
boolean isScreenHdr = getResources().getConfiguration().isScreenHdr();
boolean isScreenWideColorGamut = getResources().getConfiguration().isScreenWideColorGamut();
ซึ่งถ้าลงละเอียดไปลึกกว่านั้น ผู้ที่หลงเข้ามาอ่านสามารถดึงค่า Color Mode ด้วยคำสั่งแบบนี้ได้เลย
int colorMode = getResources().getConfiguration().colorMode;
แล้วอยากรู้ว่ามีค่าเป็นอะไรบ้างก็ให้ทำ Bit Mask กับค่า Color Mode ที่ได้ฮะ
Configuration.COLOR_MODE_HDR_MASK
Configuration.COLOR_MODE_HDR_NO
Configuration.COLOR_MODE_HDR_SHIFT
Configuration.COLOR_MODE_HDR_UNDEFINED
Configuration.COLOR_MODE_HDR_YES
Configuration.COLOR_MODE_UNDEFINED
Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK
Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO
Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED
Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
แต่แนะนำว่าอย่าไปทำครับ เหนื่อยตายกันพอดี ไปเช็คจากคำสั่งที่มีให้โดยตรงเถอะนะ..
และมีการเพิ่ม UI Mode สำหรับ VR Headset ให้ด้วย สำหรับนักพัฒนาที่ทำเกี่ยวกับ VR ก็สามารถ Detected ได้จาก Configuration แล้วว่าแสดงผลหน้าจอสำหรับ VR อยู่หรือไม่
int Configuration.UI_MODE_TYPE_VR_HEADSET
Display
ชื่อเต็ม : android.view.Displayเพิ่มคำสั่งสำหรับเช็คว่าหน้าจอที่แสดงผลอยู่นั้นเป็น HDR หรือ Wide Color Gamut หรือป่าว
boolean isHdr = getWindowManager().getDefaultDisplay().isHdr();
boolean isWideColorGamut = getWindowManager().getDefaultDisplay().isWideColorGamut();
Window
ชื่อเต็ม : android.view.Windowเพิ่มคำสั่งสำหรับดึงค่า Color Mode ของหน้าจอ
int colorMode = getWindow().getColorMode();
Permission
ชื่อเต็ม : android.Manifest.permissionเพิ่ม Permission เข้ามาใหม่อีก 10 ตัว
Manifest.permission.ALLOCATE_AGGRESSIVE
Manifest.permission.BIND_AUTO_FILL
Manifest.permission.BIND_VISUAL_VOICEMAIL_SERVICE
Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE
Manifest.permission.MANAGE_OWN_CALLS
Manifest.permission.READ_PHONE_NUMBER
Manifest.permission.REQUEST_DELETE_PACKAGES
Manifest.permission.RESTRICTED_VR_ACCESS
Manifest.permission.RUN_IN_BACKGROUND
Manifest.permission.USE_DATA_IN_BACKGROUND
ALLOCATE_AGGRESSIVE เป็นการบังคับจองพื้นที่ข้อมูล ใช้สำหรับ System เท่านั้น ไม่สามารถเข้าไปใช้งานได้
BIND_AUTO_FILL สำหรับใช้งาน Auto Fill ที่เพิ่มเข้ามาใหม่ในเวอร์ชันนี้
BIND_VISUAL_VOICEMAIL_SERVICE สำหรับใช้งาน Visual Voicemail ที่เพิ่มเข้ามาใหม่ในเวอร์ชันนี้ (สามารถ)
INSTANT_APP_FOREGROUND_SERVICE เพื่อให้ Instant App สามารถทำงานเป็น Foreground Service ได้
MANAGE_OWN_CALLS สำหรับควบคุมการรับสายผ่านโค้ด (เวอร์ชันนี้ยอมให้ทำแบบนี้ได้แล้ว)
READ_PHONE_NUMBER ใช้ในการขอดึงเบอร์มือถือจากเครื่อง
REQUEST_DELETE_PACKAGES เพื่อให้สามารถเรียกหน้าต่างลบแอปฯขึ้นมาด้วยคำสั่ง ACTION_UNINSTALL_PACKAGE (ใช้ใน Intent) ซึ่งมีตั้งแต่สมัย API 14 แล้วล่ะ แต่ใน API 26 เป็นต้นไปจะต้องประกาศ Permission นี้ด้วยทุกครั้ง
RESTRICTED_VR_ACCESS เข้าถึง VR API บางอย่างที่ถูกจำกัดสิทธิ์ไว้ Permission นี้สำหรับ System App เท่านั้น
RUN_IN_BACKGROUND เพื่อให้แอปฯสามารถทำงานใน Background ได้ (ใช้ใน CompanionDeviceManager สำหรับ System App เท่านั้น)
USE_DATA_IN_BACKGROUND เพื่อให้แอปฯสามารถใช้งานอินเตอร์เน็ตใน Background ได้ (ใช้ใน CompanionDeviceManager สำหรับ System App เท่านั้น)
Fingerprint Gesture
เป็นหนึ่งฟีเจอร์ที่อยู่ใน Accessibility หรือโหมดคนพิการ ซึ่งเปิดให้นักพัฒนาสามารถดัก Event การ Gesture บน Fingerprint ได้ถ้านึกไม่ออก ให้นึกถึง Google Pixel ที่ Fingerprint สามารถทำ Gesture ง่ายๆได้ เช่นปัดลงเพื่อเปิด Notification นั่นล่ะครับ ที่สามารถทำบน Android O ได้เลย แต่ก็ขึ้นอยู่กับแต่ละเครื่องด้วยว่า Fingerprint มีมั้ย และรองรับการทำ Gesture มั้ย
โดยจะมีคลาสสำคัญที่ชื่อว่า FingerprintGestureController ที่ใช้ในการ Register/Unregister Event Callback และลักษณะของ Gesture ก็จะมีอยู่ 4 แบบเท่านั้น คือ ปัดขึ้น, ปัดลง, ปัดซ้าย และปัดขวา
FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN
FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT
FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT
FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP
Animator
เป็นหนึ่งใน Animation API ที่ใช้งานกันอยู่บ่อยๆ ในตอนนี้มีการเพิ่มคำสั่งให้กำหนดระยะเวลาที่จะเริ่มเล่นได้ เช่น ใช้ Animator เลื่อนจากตำแหน่ง X : 0 ไปยังตำแหน่ง X : 100 โดยใช้เวลาทั้งหมด 1,000 มิลลิวินาทีหรือ 1 วินาทีObjectAnimator animator = ObjectAnimator.ofFloat(tvMessage, View.TRANSLATION_X, 0, 100);
animator.setDuration(1000);
animator.start();
ระหว่างที่ Animator กำลังเล่นอยู่นั้น มีคำสั่งสำหรับเช็คได้ว่าตอนนี้กำลังเล่นอยู่ที่วินาทีเท่าไร และกำหนดได้ว่าจะให้ข้ามไปแสดงผลเป็นวินาทีที่เท่าไร (เหมือนเวลาดูหนังแล้วสั่งให้ข้ามไปเล่นวินาทีที่ต้องการ)
long currentPlayTime = animator.getCurrentPlayTime();
animator.setCurrentPlayTime(500);
จากคำสั่ง setCurrentPlayTime จะทำให้ Animator ข้ามไปแสดงผลที่ 500 มิลลิวินาทีหรือ 0.5 วินาที ทันที
และสามารถสั่งให้เล่นย้อนกลับได้ด้วยนะเออ
animator.reverse();
ซึ่งคำสั่งสำหรับ Current Play Time และ Reverese นั้นจะใช้ได้ก็ต่อเมื่อ Animator ทำงานแล้วเท่านั้นนะจ๊ะ
เมื่อ Animator สามารถทำงานแบบ Reverse ได้ ดังนั้น Animator Listener จึงเพิ่ม Event เข้ามาอีก 2 ตัวเพื่อรองรับการทำงานแบบ Reverse
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation, boolean isReverse) {
}
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
}
...
});
หมายเหตุ - แนะนำให้ใช้ AnimatorListenerAdapter แทน Animator.AnimatorListener
Fragment
สำหรับ Fragment Manager ในตอนนี้มี Fragment Life Cycle Callback ให้ใช้แล้วจ้าาาาาาาาาาาาาาา (Support v4 ก็มีให้ใช้แล้วเหมือนกัน)private FragmentManager.FragmentLifecycleCallbacks callback = new FragmentManager.FragmentLifecycleCallbacks() {
@Override
public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {
}
@Override
public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
}
@Override
public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
}
@Override
public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
}
@Override
public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
}
@Override
public void onFragmentStarted(FragmentManager fm, Fragment f) {
}
@Override
public void onFragmentResumed(FragmentManager fm, Fragment f) {
}
@Override
public void onFragmentPaused(FragmentManager fm, Fragment f) {
}
@Override
public void onFragmentStopped(FragmentManager fm, Fragment f) {
}
@Override
public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
}
@Override
public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
}
@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
}
@Override
public void onFragmentDetached(FragmentManager fm, Fragment f) {
}
};
ซึ่ง Callback ตัวนี้จะบอกให้หมดว่า Fragment ตัวไหนเกิด Life Cycle อะไร ส่วนการใช้งานก็จะเป็นลักษณะของ Register/Unregister
FragmentManager manager = getSupportFragmentManager();
manager.registerFragmentLifecycleCallbacks(callback, true);
// เมื่อไม่ใช้งานแล้ว
manager.unregisterFragmentLifecycleCallbacks(callback);
คำสั่ง Register นั้นสามารถกำหนดได้ว่าจะให้คำสั่งนี้ Recursive ใน Child Fragment Manager ด้วยหรือไม่
ส่วน Fragment นั้นก็มีการเพิ่มคำสั่งเข้ามาเล็กน้อย
boolean isStateSaved()
void postponeEnterTransition()
void startPostponedEnterTransition()
isStateSaved เช็คว่า Fragment State มีการ Save เก็บไว้เรียบร้อยแล้วหรือยัง
postponeEnterTransition กำหนดให้ Transition ของ Fragment ตัวนั้นอย่าเพิ่งทำงาน จนกว่าจะสั่งด้วยคำสั่ง startPostponedEnterTransition (มี Transition แต่ยังไม่อยากให้เล่นทันที)
startPostponedEnterTransition สั่งให้ Transition ของ Fragment ที่กำหนดด้วยคำสั่ง postponeEnterTransition เริ่มทำงาน
Notification
เพิ่มคำสั่งเพื่อรองรับ Channel และ Channel Group ซึ่งเจ้าของบล็อกแยกเป็นบทความเรื่องนี้ให้แล้ว สามารถตามไปอ่านกันได้ที่ [Android Code] ลองเล่น Notification Channels ของเล่นใหม่จาก Android OActivity
สำหรับคลาส Activity จะเพิ่มคำสั่งต่างๆเพื่อให้รองรับการทำงานแบบ Picture in Picture และ Freeform Windowboolean enterPictureInPictureMode(PictureInPictureArgs arge)
boolean isOverlayWithDecorCaptionEnabled()
void setOverlayWithDecorCaptionEnabled(boolean enabled)
void setPictureInPictureArgs(PictureInPictureArgs args)
เนื่องจาก Android O รองรับการแสดงผลบนหลายหน้าจอ (Multi-display Support) จึงมีการเพิ่ม Override Method ที่ชื่อว่า onMovedToDisplay เข้ามาด้วย
public class MainActivity extends AppCompatActivity {
...
@Override
public void onMovedToDisplay(int displayId) {
}
}
ซึ่ง onMovedToDisplay จะทำให้นักพัฒนารู้ได้ว่าในขณะที่ Activity นั้นๆกำลังทำงานอยู่แล้วผู้ใช้มีการย้ายไปแสดงบนหน้าจออื่น
และมีการเพิ่มคำสั่ง isActivityTransitionRunning เพื่อให้เช็คได้ว่า Activity ณ ตอนนั้นกำลังแสดง Transition ใดๆอยู่หรือป่าว
boolean isActivityTransitionRunning()
AppWidgetManager
ชื่อเต็ม : android.appwidget.AppWidgetManagerเพิ่มคำสั่งสำหรับแปะ Widget ลงใน Home Screen ผ่านโค้ดได้แล้ว เพราะเดิมทีนั้นให้ผู้ใช้เป็นคนลาก Widget ไปใส่เองเท่านั้น
boolean isRequestPinAppWidgetSupported()
boolean requestPinAppWidget(ComponentName provider, PendingIntent successCallback)
Content Provider
มีการ Overload Method เพิ่มเข้ามาให้กับ Query และ Refresh เพื่อให้รองรับการยกเลิกกลางคันโดยใช้คลาส CancellationSignalCancellationSignal signal = new CancellationSignal();
// ใช้กับ Query
provider.query(uri, projection, queryArgs, signal);
// ใช้กับ Refresh
provider.refresh(uri, args, signal);
// เมื่อต้องการยกเลิกการ Query หรือ Refresh กลางคัน
signal.cancel();
Context
มีการเพิ่ม Service Manager เข้ามาใหม่ทั้งหมด 5 ตัวด้วยกัน (บางอันใช้สำหรับ System App เท่านั้น)Context.COMPANION_DEVICE_SERVICE
Context.FONT_SERVICE
Context.STORAGE_STATS_SERVICE
Context.TEXT_CLASSIFICATION_SERVICE
Context.WIFI_AWARE_SERVICE
// ยกตัวอย่างการเรียกใช้ Font Manager
FontManager fontManager = (FontManager) getSystemService(Context.FONT_SERVICE);
และเพิ่มคำสั่งเข้ามาอีก 1 ตัว
Context createContextForSplit(String splitName)
เป็นคำสั่งที่ใช้สำหรับสร้าง Context ขึ้นมาใหม่โดยใช้ Context ที่มีอยู่ ซึ่ง Context ที่ถูกสร้างขึ้นมาใหม่จะเป็นคนละตัวกับ Context ตัวเก่า แต่ก็ได้ Resource จากตัวเก่ามาใช้งานได้อยู่นะ
Intent
เพิ่มคำสั่ง removeFlags มาให้ จะได้ลบ Flag ที่ไม่ต้องการออกไปได้ (เดิมทีมีแค่ setFlags กับ addFlags)Intent intent = new Intent(MainActivity.this, OmgActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
// ลบบาง Flag ออก
intent.removeFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
เพิ่ม Constant สำหรับใช้ใน Intent (Action, Category และ Extra) เข้ามาใหม่
Intent.ACTION_CLEAR_PACKAGE
Intent.CATEGORY_TYPED_OPENABLE
Intent.CATEGORY_VR_HOME
Intent.EXTRA_CONTENT_ANNOTATIONS
Intent.EXTRA_QUICK_VIEW_ADVANCED
และประกาศ Deprecated Constant ของ App Shortcut ทั้งหมด แล้วให้เปลี่ยนไปใช้คำสั่งที่เพิ่มเข้ามาใหม่ใน ShortcutManager แทน
// Deprecated
Intent.EXTRA_SHORTCUT_ICON
Intent.EXTRA_SHORTCUT_ICON_RESOURCE
Intent.EXTRA_SHORTCUT_INTENT
Intent.EXTRA_SHORTCUT_NAME
// ใช้อันนี้แทน
ShortcutManager manager = (ShortcutManager) getSystemService(SHORTCUT_SERVICE);
ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(getContext(), name)
.setIcon(icon)
.setIntent(intent)
.build();
Intent shortcutResultIntent = manager.createShortcutResultIntent(shortcutInfo);
Package Manager
ชื่อเต็ม : android.content.pm.PackageManagerเพิ่ม Feature เข้ามาใหม่ 3 ตัว
PackageManager.FEATURE_EMBEDDED
PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE
PackageManager.FEATURE_WIFI_AWARE
Bitmap
คลาส Bitmap มีการเพิ่ม Static Method ที่ใช้ในการสร้าง Bitmap Instance มา 2 ตัว สำหรับการสร้าง Bitmap แบบ ARGB_8888 หรือ RGBA_16FBitmap createBitmap(DisplayMetrics display, int width, int height, Bitmap.Config config, boolean hasAlpha)
Bitmap createBitmap(int width, int height, Bitmap.Config config, boolean hasAlpha)
ส่วน BitmapFactory.Options เพิ่มตัวแปรที่ชื่อว่า outConfig เข้ามาด้วย เป็นค่าที่บอกว่า Bitmap นั้นๆใช้ Decode แบบไหนอยู่
BitmapFactory.Options options = new BitmapFactory.Options();
options.outConfig = Bitmap.Config.RGBA_F16;
Canvas
ชื่อเต็ม : android.graphics.Canvasมีการประกาศ Deprecated คำสั่งตระกูล Clip ที่ต้องกำหนด Region.Op ทุกตัว เพื่อให้ไปใช้เป็นคำสั่ง Clip Out แทน
// Deprecated
boolean clipPath(Path path, Region.Op op)
boolean clipRect(Rect rect, Region.Op op)
boolean clipRect(RectF rectF, Region.Op op)
boolean clipRect(float left, float top, float right, Region.Op op)
// ใช้คำสั่งเหล่านี้แทน
boolean clipOutPath(Path path)
boolean clipOutRect(Rect rect)
boolean clipOutRect(RectF rectF)
boolean clipOutRect(float left, float top, float right, float bottom)
boolean clipOutRect(int left, int top, int right, int bottom)
Color
ชื่อเต็ม : android.graphics.Colorเพิ่มคำสั่งใหม่เข้ามาเยอะมากกกกกกกกกกกกกกก
TypeFace
ชื่อเต็ม : android.graphics.Typefaceเพิ่มคำสั่งสร้าง TypeFace โดยใช้ Font Provider (ของเล่นใหม่เช่นกัน) ได้แล้ว
void create(FontRequest request, Typeface.FontRequestCallback callback)
Sensor
ชื่อเต็ม : android.hardware.Sensorเพิ่มประเภทของ Sensor เข้ามาใหม่อีก 2 แบบ
Sensor.TYPE_ACCELEROMETER_UNCALIBRATED
Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT
Location
ชื่อเต็ม : android.location.Locationเพิ่มคำสั่งสำหรับ Bearing Accuracy, Speed Accuracy และ Vertical Accuracy
float getBearingAccuracyDegrees()
float getSpeedAccuracyMetersPerSecond()
float getVerticalAccuracyMeters()
boolean hasBearingAccuracy()
boolean hasSpeedAccuracy()
boolean hasVerticalAccuracy()
void removeBearingAccuracy()
void removeSpeedAccuracy()
void removeVerticalAccuracy()
void setBearingAccuracyDegrees(float bearingAccuracyDegrees)
void setSpeedAccuracyMetersPerSecond(float speedAccuracyMeterPerSecond)
void setVerticalAccuracyMeters(float verticalAccuracyMeters)
ExifInterface
ชื่อเต็ม : android.media.ExifInterfaceเพิ่มคำสั่งสำหรับ Thumbnail ใน EXIF นั้นๆ
Bitmap getThumbnailBitmap()
byte[] getThumbnailBytes()
boolean isThumbnailCompressed()
และเพิ่ม Tag ใหม่เพื่อให้ครอบคลุมมากขึ้น
ExifInterface.TAG_DEFAULT_CROP_SIZE
ExifInterface.TAG_DNG_VERSION
ExifInterface.TAG_NEW_SUBFILE_TYPE
ExifInterface.TAG_ORF_ASPECT_FRAME
ExifInterface.TAG_ORF_PREVIEW_IMAGE_LENGTH
ExifInterface.TAG_ORF_PREVIEW_IMAGE_START
ExifInterface.TAG_ORF_THUMBNAIL_IMAGE
ExifInterface.TAG_RW2_ISO
ExifInterface.TAG_RW2_JPG_FROM_RAW
ExifInterface.TAG_RW2_SENSOR_BOTTOM_BORDER
ExifInterface.TAG_RW2_SENSOR_LEFT_BORDER
ExifInterface.TAG_RW2_SENSOR_RIGHT_BORDER
ExifInterface.TAG_RW2_SENSOR_TOP_BORDER
ExifInterface.TAG_SUBFILE_TYPE
Media Recorder
มี Output Format แบบ MPEG_2_TS แล้วนะMediaRecorder.OutputFormat.MPEG_2_TS
Build
ชื่อเต็ม : android.os.Buildเปลี่ยนวิธีการดึงค่า Serial ที่เดิมจะเรียกจากตัวแปรโดยตรง ให้ไปเรียกผ่าน Getter ที่เพิ่มเข้ามาใหม่แทน
// Deprecated
String serial = Build.SERIAL;
// ใช้คำสั่งนี้แทน
String serial = Build.getSerial();
และเพิ่ม Version Code สำหรับ Android O เข้ามาด้วย
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// DO something
}
Bundle
ชื่อเต็ม : android.os.Bundleเพิ่มคำสั่งสำหรับ Hard Copy เข้ามาเพื่อให้สามารถสร้าง Bundle จาก Bundle อีกตัวได้ โดยที่ทั้งสองตัวนั้นเป็น Object คนละตัวกัน
Bundle oldBundle = new Bundle();
oldBundle.putString(KEY_NAME, name);
oldBundle.putString(KEY_COUNTRY, country);
// สร้าง Bundle ตัวใหม่ โดยที่ยังมีค่าเดิมที่กำหนดไว้อยู่
Bundle newBundle = oldBundle.deepcopy();
Parcelable
Parcel รองรับ SparseIntArray แล้ว จากเดิมที่รองรับแค่ SparseArray กับ SparseBooleanArray (ทำไมไม่มี SparseLongArray ด้วยนะ)PreferenceDataStore
เป็นคลาสใหม่ที่สร้างขึ้นมาใช้ใน Preference เวลาที่ผู้ใช้ตั้งค่าการทำงานต่างๆ (หน้าที่ใช้ PreferenceActivity หรือ PreferenceFragment) ซึ่งเป็นคลาสที่สามารถนำมาใช้แทนที่ SharedPreference เดิมได้เลยpublic class UserSettingFragment extends PreferenceFragment {
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
PreferenceManager.setDefaultValues(getActivity(), R.xml.advanced_preferences, false);
addPreferencesFromResource(R.xml.activity_preference);
}
...
public void updateNamePreference() {
PreferenceDataStore dataStore = getPreferenceManager().getPreferenceDataStore();
dataStore.putString(KEY_NAME, etUsername.getText().toString());
}
}
จากการนั่งดูแล้วก็ยังไม่เข้าใจเหมือนกันว่าทำไมถึงสร้างคลาสตัวนี้ขึ้นมาเพื่อใช้แทน SharedPreference เฉพาะใน Preference เท่านั้น...
แต่ถ้าเป็น Activity หรือ Fragment ทั่วๆไป ไม่ต้องสนใจครับ ใช้ SharedPreference เหมือนเดิมน่ะแหละ
Settings
ชื่อเต็ม : android.provider.Settingsเพิ่ม Action และ Extra ที่เกี่ยวกับ Notification เพิ่มเข้ามา
Settings.ACTION_APP_NOTIFICATION_SETTINGS
Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS
Settings.ACTION_MANAGE_EXTERNAL_SOURCES
Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS
Settings.EXTRA_APP_PACKAGE
Settings.EXTRA_CHANNEL_ID
TelephonyManager
ชื่อเต็ม : android.telephony.TelephonyManagerมีหลายๆอย่างในนี้ที่เพิ่มเข้ามา แต่บางอย่างก็ไม่น่าสนใจ บางอย่างก็มีไว้สำหรับ System App ซึ่งที่น่าสนใจที่สุดก็คงจะเป็นการที่เปิดให้สามารถส่ง USSD และรับ Reponse ได้แล้ว เพราะเดิมต้องไปเรียกผ่าน Intent โดยใช้ ACTION_CALL ซึ่งไม่สามารถดักข้อมูลที่ส่งกลับมาได้
String ussdCode = "*103#";
TelephonyManager manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
manager.sendUssdRequest(ussdCode, new TelephonyManager.OnReceiveUssdResponseCallback() {
@Override
public void onReceiveUssdResponse(String request, CharSequence response) {
super.onReceiveUssdResponse(request, response);
}
@Override
public void onReceiveUssdResponseFailed(String request, int failureCode) {
super.onReceiveUssdResponseFailed(request, failureCode);
}
}, new Handler());
TransitionListenerAdapter
ชื่อเต็ม : android.transition.TransitionListenerAdapterเพิ่มเข้ามาเพื่อทดแทนการใช้ Transition.TransitionListener ที่ทำให้โค้ดยาวเหยียด (เหมือนกับ AnimatorListenerAdapter เลย)
InputDevice
ชื่อเต็ม : android.view.InputDeviceเพิ่ม Constant เข้ามาใหม่อีก 2 ตัว
InputDevice.SOURCE_MOUSE_RELATIVE
InputDevice.SOURCE_ROTARY_ENCODER
มันมีใครควบคุมอุปกรณ์แอนดรอยด์ผ่าน Input Device พวกนี้ด้วยหรอเนี่ย...
MotionEvent
ชื่อเต็ม : android.view.MotionEventเพิ่ม Constant ที่ชื่อว่า AXIS_SCROLL เพื่อรองรับกับ Input Device ที่สามารถ Scroll ได้
MotionEvent.AXIS_SCROLL
ViewGroup
ชื่อเต็ม : android.view.ViewGroupประกาศ Deprecated บางคำส่ง
// Deprecated
void invalidateChild(View child, Rect dirty)
ViewParent invalidateChildInParent(int[] location, Rect dirty)
// ใช้คำสั่งนี้แทน
onDescendantInvalidated(View child, View target)
DatePicker
ชื่อเต็ม : android.widget.DatePickerเพิ่ม Listener เมื่อมีการเปลี่ยนวันที่
DatePicker datePicker = (DatePicker) findViewById(R.id.date_picker);
datePicker.setOnDateChangedListener(new DatePicker.OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
}
});
ProgressBar
ชื่อเต็ม : android.widget.ProgressBarสามารถกำหนด Minimum Progress ได้แล้วววววววววววววว
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// กำหนดค่า Minimum Progress
int minimumProgress = 10;
progressBar.setMin(minimumProgress);
// ดังค่า Minimum Progress
int minProgress = progressBar.getMin();
และเพิ่มคำสั่ง isAnimating เพื่อใช้แทน isIndeterminate ด้วย เพราะว่า isAnimating นั้นหมายถึง Progress Bar กำลังอยู่ใน Indeterminate Mode และ Visible อยู่ (นอกเหนือจากนี้จะเป็น False ทั้งหมด)
boolean isAnimating = progressBar.isAnimating();
เก็บตกคำสั่งอื่นๆที่ถูก Remove และ Deprecate
• คลาส ProgressDialog ถูกประกาศ Deprecate ทั้งคลาส ให้สร้าง Dialog ที่มี Progress Bar เอง• คลาส DialerFilter ถูกประกาศ Deprecate ทั้งคลาส ให้ใช้ Custom View หรือ Layout จัดการเองแทน
• คลาส ZoomButton และ ZoomButtonsController ถูกประกาศ Deprecate ให้ใช้วิธีเขียนคำสั่งเพื่อควบคุมการทำงานเอง
• คำสั่ง findViewTraversal และ findViewWithTagTraversal ในคลาส ListView ถูกลบออกไป
• คลาส RasterizerSpan ถูกลบออกไป
• คลาส LayerRasterizer ถูกลบออกไป
• คลาส Rasterizer ถูกลบออกไป
• คลาส PskKeyManager ถูกลบออกไป
สุดท้ายแล้วก็ให้หมั่นอัปเดตอยู่บ่อยๆ ว่าในแต่ละเวอร์ชันเนี่ยมีอะไรเพิ่มเข้ามาบ้าง เปลี่ยนอะไรบ้าง อันไหนเลิกใช้ ให้ใช้อันไหนแทน เพื่อให้แอปฯของผู้ที่หลงเข้ามาอ่านทำงานได้ปกติสุขบนอุปกรณ์แอนดรอยด์ที่ต่างเวอร์ชันกันครับ
• คลาส LayerRasterizer ถูกลบออกไป
• คลาส Rasterizer ถูกลบออกไป
• คลาส PskKeyManager ถูกลบออกไป
สรุป
เยอะมากกกกกกกกก นี่ขนาดตัดหลายๆอันออกไปแล้วนะ (แถมเอามาแค่ Android เท่านั้น ยังไม่นับส่วนของ Java) ซึ่งหลายๆคำสั่งที่เปลี่ยนไปก็น่าจะกระทบกับนักพัฒนาหลายๆคนอยู่บ้าง (เจ้าของบล็อกก็ด้วย) ถ้าจะแก้ไขให้รองรับกับ Android O ก็อย่าลืมเรื่อง Backward Compatibility ด้วยนะสุดท้ายแล้วก็ให้หมั่นอัปเดตอยู่บ่อยๆ ว่าในแต่ละเวอร์ชันเนี่ยมีอะไรเพิ่มเข้ามาบ้าง เปลี่ยนอะไรบ้าง อันไหนเลิกใช้ ให้ใช้อันไหนแทน เพื่อให้แอปฯของผู้ที่หลงเข้ามาอ่านทำงานได้ปกติสุขบนอุปกรณ์แอนดรอยด์ที่ต่างเวอร์ชันกันครับ