Android 5.0 (Lollipop) 是 Android 平台的一个重要版本,带来了许多新特性和变更。本文将详细介绍 Android 5.0 的核心更新及其适配方法,并配以图解和代码示例。
主要变更概览
1. Material Design
Android 5.0 引入了 Material Design,这是一套全新的设计语言,为用户提供了一致的、直观的交互体验。
核心特性:
- 界面动画与过渡效果
- 阴影和光照
- 调色板和主题支持
图解:Material Design 元素
代码示例:实现基本 Material Design 样式
<!-- styles.xml -->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<item name="colorPrimary">#6200EE</item>
<item name="colorPrimaryDark">#3700B3</item>
<item name="colorAccent">#03DAC5</item>
</style>
// Kotlin 示例
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener {
Snackbar.make(it, "Hello Material Design!", Snackbar.LENGTH_LONG).show()
}
2. ART Runtime
Android 5.0 默认启用了 ART(Android Runtime)替代 Dalvik,提升了应用性能和响应速度。
适配建议
- 确保应用支持 ART。
- 避免依赖运行时特定行为,如直接修改字节码。
3. 新的通知系统
通知系统在 Android 5.0 进行了重大更新,支持锁屏通知和优先级管理。
图解:通知优先级
代码示例:创建优先级通知
val builder = NotificationCompat.Builder(this, "default")
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("通知标题")
.setContentText("这是通知内容")
.setPriority(NotificationCompat.PRIORITY_HIGH)
with(NotificationManagerCompat.from(this)) {
notify(1, builder.build())
}
适配建议
- 测试通知在锁屏上的显示效果。
- 使用
NotificationChannel
管理不同类型的通知(从 Android 8.0 开始支持)。
4. JobScheduler API
引入了 JobScheduler API,用于高效地管理后台任务。
图解:JobScheduler 工作流
代码示例:使用 JobScheduler
val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val jobInfo = JobInfo.Builder(1, ComponentName(this, MyJobService::class.java))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPeriodic(15 * 60 * 1000) // 每 15 分钟执行一次
.build()
jobScheduler.schedule(jobInfo)
5. RecyclerView 和 CardView
Android 5.0 引入了 RecyclerView 和 CardView,作为 ListView 和 GridView 的替代品,提供更强大的功能。
图解:RecyclerView 结构
代码示例:使用 RecyclerView
- 添加依赖:
dependencies {
implementation "androidx.recyclerview:recyclerview:1.3.0"
implementation "androidx.cardview:cardview:1.0.0"
}
- 实现 RecyclerView Adapter:
class MyAdapter(private val dataset: List<String>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
class MyViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val textView = LayoutInflater.from(parent.context)
.inflate(R.layout.text_row_item, parent, false) as TextView
return MyViewHolder(textView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.textView.text = dataset[position]
}
override fun getItemCount() = dataset.size
}
6. Vector Drawables
支持矢量图形(Vector Drawable),提升了图像的可伸缩性和质量。
示例:定义矢量图形
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,2L15.09,8.26L22,9.27L17,14.14L18.18,21.02L12,17.77L5.82,21.02L7,14.14L2,9.27L8.91,8.26L12,2z"/>
</vector>
适配建议
-
Material Design 主题适配
- 使用
Theme.MaterialComponents
。 - 更新旧组件为
Toolbar
和FloatingActionButton
。
- 使用
-
通知测试
- 测试在不同锁屏设置下的表现。
-
RecyclerView 替代 ListView
- 优化复杂列表的性能。
-
矢量图支持
- 在
build.gradle
中启用vectorDrawables.useSupportLibrary = true
。
- 在
webview适配
- 不允许加载混合内容,也就是说https的网页内不允许加载http资源,反之依然
android5.0以下版本,WebView.getSettings().getMixedContentMode()的默认值为MIXED_CONTENT_ALWAYS_ALLOW,也就是总是允许加载混合内容。android5.0起,这个值默值为MIXED_CONTENT_NEVER_ALLOW。处于安全考虑,一般情况下,强烈建议使用MIXED_CONTENT_NEVER_ALLOW模式。但是,如果该网页为第三方网页或者我们的https网页中加载了第三方资源,我们不太可能立马要求对方升级为https。那么我们就做如下适配:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mWebView.getSettings()
.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
- 不允许写入第三方cookie
android5.0起,默认不允许写入第三方cookie,需手动设置:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView,true);
}
- 不再一次性渲染整个网页
android5.0以前,webview总是一次性渲染整个网页。android5.0以后实行只能渲染,只保证可视部分是已渲染的。这在某些场合可能会出问题,比如为webview截屏。当试图在5.0上对webview截屏时会发现只截取到可视部分,并没有截取整个网页。当然,这种情况发生在你并没有上下滑动webview使其整个网页得到渲染。
通过在创建webview前调用静态方法WebView.enableSlowWholeDocumentDraw()使其总是一次性渲染整个网页。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
WebView.enableSlowWholeDocumentDraw();
}
setContentView(R.layout.activity_main);
}
}
- webview选择文件时WebChromeClient回调方法的改变
mWebView.setWebChromeClient(new WebChromeClient() {
// when sdk version < 3.0
public void openFileChooser(ValueCallback<Uri> valueCallback) {
}
// when sdk version >= 3.0
public void openFileChooser(ValueCallback valueCallback, String acceptType) {
}
//when sdk version >= 4.1
public void openFileChooser(ValueCallback<Uri> valueCallback,
String acceptType, String capture) {
}
// when sdk version >= 5.0
@Override
public boolean onShowFileChooser(WebView webView,
ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
return true;
}
});
在android5.0以前,我们在Web页面上点击选择文件的控件(<input type="file">)时,会回调WebChromeClient的openFileChooser方法,不过该方法的形参在android3.0以前、3.0及以后、4.1及以后有所变化。到了android5.0,直接剔除了该方法,以onShowFileChooser代之。这将导致在5.0以下版本运行时,无法在onShowFileChooser方法中处理回调。openFileChooser方法不要标注@Override,由于是直接剔除,在高版本的sdk找不到该方法,如果你的编译版本>=5.0那么将编译报错。可根据你的minSdkVersion选择性地加入openFileChooser的三个历史版本。
Service适配
android5.0之前,我们可以隐式启动一个Service,
Intent intent = new Intent().setAction("com.android.test.for.service");
startService(intent);
android5.0及以后,隐式启动Service,程序会崩溃。
所以,在android5.0及以后必须显示调用Service。两种方式:
- 指定packageName
Intent intent = new Intent()
.setAction("com.android.test.for.service")
.setPackage(getPackageName());
startService(intent);
- 直接指定具体的Service类
Intent intent = new Intent(this, MyService.class);
startService(intent);
结论
Android 5.0 带来了许多变革,为开发者提供了更强大的工具和 API。同时也要求开发者在适配过程中注意新旧版本兼容问题。