狼人小林的博客

Android

Android - 应用前后台切换监听

最近工作中遇到了这么一个需求:如何实现 Android 应用前后台切换的监听?

解决方案笔记。

iOS 的情况

iOS 内边是可以实现的,UIApplicationDelegate 给了一个回调监听:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

}

我保留了系统注释。一个iOS应用周期,大概的流程是这样的。

Android 一种简单和优雅的方式实现下拉刷新和加载更多

老生常谈的问题,但是发现很多人仍然将其视为难题。

很多实现也很复杂,有人甚至做了一个 SuperRefreshLayout 或者 SuperListView 或者 SuperRecyclerView 来实现。

其实不需要 Super,使用很少的简介的代码也可以实现。

最近做了个总结,尝试给出最佳实践。上面是效果图,支持 ListView 和 RecyclerView。

相关代码在这里:https://github.com/TakWolf/Android-RefreshAndLoadMore-Demo

这个方案来源于我自己的开发实践,个人认为已接近最佳实践,简单且优雅。

要注意的是,这篇文章介绍的是如何用现有资源快速实现一个下拉刷新和加载更多分页效果,

而不是如何去实现或者自定义一个下拉刷新控件。那是另外一个话题,咱们改天再聊。

准备工作

我们的原则是,尽可能使用现成的资源去实现。

即便如此,我们仍然使用了下面的第三方依赖,但是注意,这些依赖都不是必须的:

1.Material-ish Progress

一个可以兼容低版本的 Material Design 风格进度条样式。我希望可以保证所有版本的 Android 都要良好的 Material Design 体验。

这不是必须的,你可以替换为默认的进度条控件或者你自己的控件,除了样式之外,不会有其他问题。

2.Android-HeaderAndFooterRecyclerView

这是我写的另外一个组件,它可以扩充 RecyclerView,让其支持 HeaderView 和 FooterView。我们在实现加载更多的时候需要这个特性。

这个组件使用非常简单,替换默认的 RecyclerView 就可以了。接口与 ListView 添加头部的方式类似。不需要修改其他任何东西(例如你的业务Adapter)。

仅此而已,非侵入式,没有额外的东西。

这不是必须的,你可以有你自己的方式实现这个功能。这不影响我们整篇文章的思路。但是我很推荐你去试试它,也许你会觉得不错呢。

3.Butter Knife

通过注解的方式快速实现控件绑定。

这不是必须的,你可以使用 findViewById(),效果是一样的。不过我推荐你去看看,真的很方便。

基本思路

下拉刷新比较容易实现,因为 Android 官方的 support 组件中就实现了一个下拉刷新组件:SwipeRefreshLayout

支持 ListView 和 RecyclerView,符合 Material Design,使用简单,性能良好。

港真,除非你遇到一个变态的产品经理,否则有啥理由不使用这个呢?

下拉刷新的实现,大家的方式分歧比较大,很多人尝试在父布局上面下功夫。

我个人觉得最简单的实现是在列表的最后添加一个 FooterView,用它来显示加载动画。同时监听列表滚动,检测滑动到底部的时候,触发加载动作。

这样的好处是,不在需要复杂的去实现一个自定义控件(包括去实现那些复杂的手势处理),也没有一些特殊情况下的问题(比如首页加载不足一屏,我们下面会讲)。

Android - 关于 Log.wtf()

Android SDK 的日志接口中,有这么一个函数:

android.util.Log.wtf();

我一直认为,这个是 “What the fuck” 的缩写,用于出现了不可能,无法挽救的错误的场景。

我甚至还觉得谷歌的工程师还蛮有意思的,诙谐幽默。

直到我今天偶然点进去了这个方法,看到了文档注释:

What a Terrible Failure: Report a condition that should never happen.
The error will always be logged at level ASSERT with the call stack.
Depending on system configuration, a report may be added to the
{@link android.os.DropBoxManager} and/or the process may be terminated
immediately with an error dialog.

原来 wtf 是 “What a Terrible Failure” 的意思……

让我笑一会

就这么个事,挺有趣的,水了一篇博客。

Android 的 support-v4 扩展库的 minSdkVersion=9 !是笔误还是故意为之?

今天更新了 Android Support Repository,相应的 android-support-v4 也升级到了 24.2.1 但是我的项目却报了如下的错误:

Error:Execution failed for task ':fragmentswitcher:processDebugAndroidTestManifest'.
> Manifest merger failed : uses-sdk:minSdkVersion 4 cannot be smaller than version 9 declared in library [com.android.support:support-v4:24.2.1] ~\Android-FragmentSwitcher\fragmentswitcher\build\intermediates\exploded-aar\com.android.support\support-v4\24.2.1\AndroidManifest.xml
Suggestion: use tools:overrideLibrary="android.support.v4" to force usage

这个错误的意思是,你的项目的 minSdkVersion=4,而 android-support-v4 要求他至少为9

看到这个错误,我其实是一脸懵逼的。

Android Support Repository 包含了很多库,很多都是按照 vX 结尾的,这个其实表示这个库的 API 兼容到的最低版本。 举个例子: cardview-v7,兼容到 API7 support-v13,兼容到 API13 也就是说,support v4 的意思就是,把一些兼容性组件,兼容到 API4 的级别上。

那么,你把 minSdkVersion 设置为9,那还叫啥 v4 啊?

心塞。。。

Android Support Repository 是安装到本地的 位置在:%ANDROID_SDK_HOME%/sdk/extras/android/m2repository/com/android/support

Android Studio 启动卡在 “fetching Android sdk compoment information”

由于国内墙的原因,无法连接到 Google 的更新服务器。

解决方法: 进入刚安装的 Android Studio 目录下的 bin 目录。 找到 idea.properties 文件,用文本编辑器打开。 在idea.properties文件末尾添加一行:

disable.android.first.run=true ,然后保存文件。关闭Android Studio后重新启动。

PJSIP 编译 Android 平台,报错:cannot locate symbol "rand" referenced by "libpjsua.so"

最近公司要实现一个IP电话的功能,选择了PJSIP这个框架。 服务端部分团队大牛已经搞完了,Android 这块还要实现一个 SIP 客户端。 安装官方文档编译Hello World,整个过程就是一个字:坑爹。

最开始是在 Windows 环境上编译,由于编译依赖于 Bash 命令以及 swig,还有坑爹的 Windows 和 Unix 换行符转换的问题,是在解决无力。 更换到 Ubuntu 之后编译通过了,在运行时报错:

cannot locate symbol "rand" referenced by "libpjsua.so"

但奇怪的是在 Android5.0 上运行却正常。 Google 上说是因为使用了64位 ndk 的原因,遂更换为32为 Ubuntu,问题仍未解决。

最后将 ndk 从 10r 更换到 9r,编译和运行都通过了。 猜测问题出现在 ndk 10r 的兼容性上。

吐槽一下 Android5.0 正式版有太多的兼容性问题。 ndk 10r 是匹配到 Android5.0 而推送的,估计也有兼容性问题。

经验和教训,简而言之就是以下几句话:

我编译成功的环境配置: