欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android 开发中不得不知道的 Tips 集合 (第三波),androidtips,so,既然开发人员不能阻

来源: 开发者 投稿于  被查看 7598 次 评论:24

Android 开发中不得不知道的 Tips 集合 (第三波),androidtips,so,既然开发人员不能阻


相关文章
1.Android 开发中不得不知道的 Tips 集合 (持续更新 ing)
2.Android 开发中不得不知道的 Tips 集合 (第二波))

1.应用又崩溃啦!!!

开发过程中,受种种因素影响(机型适配问题、程序员技术功底等),已发布上线的应用难免回出现Crash,如果我们不做处理,崩溃后系统会弹出对话框(xxx应用已停止).这时候用户手一哆嗦就直接卸载了有木有。so,既然开发人员不能阻止Crash的出现,那就得从崩溃后的提示入手了,将对用户的影响降到最低。

解决方案:
利用Thread的setDefaultUncaughtExceptionHandler方法,将未知的异常进行捕获,然后友好的提示用户,重新启动应用。(伸手党可直接拿走哈)
有图有真相:



1.新建CrashHandler类,这个类负责捕获未处理的异常

/**
 * Created by weixinjie on 2017/6/1.
 */

public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    public static final String TAG = "CatchExcep";
    SampleApplication application;

    public CrashHandler(SampleApplication application) {
        //获取系统默认的UncaughtException处理器
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        this.application = application;
    }

    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (!handleException(ex) && mDefaultHandler != null) {
            //如果用户没有处理则让系统默认的异常处理器来处理
            mDefaultHandler.uncaughtException(thread, ex);
        } else {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Log.e(TAG, "error : ", e);
            }
            Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);
            PendingIntent restartIntent = PendingIntent.getActivity(
                    application.getApplicationContext(), 0, intent,
                    PendingIntent.FLAG_CANCEL_CURRENT);
            //退出程序
            AlarmManager mgr = (AlarmManager) application.getSystemService(Context.ALARM_SERVICE);
            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
                    restartIntent); // 1秒钟后重启应用
            System.exit(0);
        }
    }

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return false;
        }
        //使用Toast来显示异常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(application, "应用异常,正在重启", Toast.LENGTH_LONG).show();
                Looper.loop();
            }
        }.start();
        return true;
    }
}


    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return false;
        }
        //使用Toast来显示异常信息
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                ToastUtil.toastLong(R.string.error_for_restart);
                Looper.loop();
            }
        }.start();
        return true;
    }
}

2.在应用的Application的onCreate方法中调用如下代码:

@Override
    public void onCreate() {
        initCrashHandler();
    }

 private void initCrashHandler() {
        //设置该CrashHandler为程序的默认处理器
        CrashHandler catchExcep = new CrashHandler(this);
        Thread.setDefaultUncaughtExceptionHandler(catchExcep);
    }

3.在清单文件中将自定义的Application注册一下.

2.为什么要用IntentService而不用Thread

面试的时候大家经常会被问IntentService跟Thread有什么区别吧?比如App升级的时候,去服务端下载apk包的时候为什么要开一个IntertService而不是Thread.
Answer:我们要从Android系统的5大进程级别来看待这个事情,分别为“前台进程”,“可视进程”,“服务进程”,“后台进程”,“空进程”.当系统的内存不足时,会根据进程的级别来回收这些进程.即回收的顺序为:“空进程”->...->“前台进程”.很明显,如果用户按下home键之后,我们的进程会变成一个后台进程,此时很容易被系统回收掉,那咱们在Thread中所做的操作就白扯了,而如果我们开一个IntentService的话,我们的进程会变成一个Service进程,被回收的几率就大大降低了。
当然,这种问题我们不应该只停留在理论阶段,应付面试是一方面,我们还是要多看系统的文档,这也是我等菜鸟通往高级工程师必不可少的一环。
祭上官方文档:https://developer.android.com/guide/components/processes-and-threads.html?hl=zh-cn (科学上网哈)

3.Gradle脚本中已删除的sdk,发布release包的事后报NoClassDefFoundError错误

缘由:项目在内测阶段用到了BugTags来指Bug (BugTags确实可以大大提高测试的效率,建议大家在内测阶段接入他们的服务进行测试)
,发布release版本的时候,为了减少包体,便将该sdk从gradle脚本中剔除了。然后打出release包之后。一打开就闪退,并且报如下错误



我当时就郁闷了,Gradle脚本中都删了咋还报类找不到?然后花了一下午的时间挨个疑点进行排查——没错是新版的gradle的锅。
解决方案:
找到 gradle --> wrapper --> gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
android gradle build 插件版本
classpath 'com.android.tools.build:gradle:2.2.3'


4.用adb进行wifi链接真机调试(不需root呦)。

方案如下:
1.手机与你的电脑要在同一个局域网下
2.配置你电脑上的adb命令。不要告诉我你不会配,请自行百度哈。
3.用usb链接电脑跟手机,在命令窗口输入:[ adb tcpip 5555 ]



4.查看你手机的ip地址:设置-WLAN-[点击你正在使用的wifi],例如我手机的ip地址为:
192.168.31.237
5.在adb命令中输入: adb connect 192.168.31.237




6.拔掉的usb线,以后就可以用wifi调试这部手机啦。看下你的as中的Android Monitor模块,正常来说已经可以出现要调试的手机了。(搞不定的叫我微信,或留言哈)




5.通往大牛的路上,怎能不看系统源码

前段时间项目赶,没时间继续我的看系统源码计划,还好,现在项目进入正常迭代周期,我又有时间可以折腾源码啦。
推荐给大家一个Chrome插件:https://chrome.google.com/webstore/search/Android%20SDK%20Reference%20Search%20
安装之后,你用Chrome浏览器去Android Developer上查api的时候,会自动加入这么一个东东,你就可以enjoy看系统源码带给你的充实啦。



楼主用的Mac,用Sublime+CTag折腾了一套源码阅读器,用了半年了感觉很棒。需要的同学留言,下次分享给大家哈。


写在最后,一直想把“Android开发中不得不知道的Tips集合”做成一个系列,把自己踩过去坑分享给大家,避免更多的同学在同一个地方绊倒。毕竟项目赶进度的日子是最痛苦的时候。希望看到这系列文章的同学join进来,把自己认为踩过有价值的坑分享出来,或者直接发给我,我整理过后接到这系列文章中去。
大家可以发我邮箱weixinjie1993@gmail.com。


作者:weixinjie

用户评论