从Eclipse到AndroidStudio(五)迁移一个eclipse工程到AndroidStudio有哪些坑
本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发。
我们还是以AndroidStudio 2.1.1为例来讲。
经过前几节的讲述,我们已经对AndroidStudio以及Gradle构建有了基本的认识,于是,我决定把公司的项目从eclipse迁移到AndroidStudio,正式开始我的AndroidStudio之旅,可谁知事情根本没有我想的那么简单,这期间遇到了N多坑,我想这些坑可能大家也有可能遇到,于是就决定写出来,跟大家一起交流。
首先,我们来看一下把一个eclipse工程迁移到AndroidStudio有几种方法:
方法1:直接导入一个eclipse工程;
方法2:在eclipse中利用ADT为工程生成一个Gradle文件,AndroidStudio导入这个gradle工程;
方法3:在AndroidStudio中新建一个工程,把eclipse工程的代码、资源一点点拷过来;
一、采用哪种方法
先说结论:我采用了方法3,如果你对方法1和方法2的效果不感兴趣,可以跳过这一部分。
方法1的好处是简单,AndroidStudio的早期版本只能用方法2,现在的新版可以支持方法1,直接导入一个eclipse工程,我开始时也是试这种方法的,确实简单,导进来不需要做任何设置居然就能运行,那么问题是什么呢?问题是编译运行一次那叫一个慢呀,比eclipse还慢N倍,而且异常消耗电脑资源,我们Macbook Pro配置不算低,买来一年多风扇从来没响过,以至于我以为电脑根本没有风扇,这下是听到风扇响了,响声那叫一个大,说明这种构建项目的方式极其耗内存耗CPU,并且由于没有gradle文件,Gradle的所有特性全部用不上,我都怀疑这种编译方式用的就是ant,根本没用到gradle。
综上所述,方法1既没有eclipse快,也没有AndroidStudio的好处,看来这种方法不可取。
再来看方法2,方法2是Google官方推荐的方式,操作步骤是:先在eclipse中的工程上点鼠标右键,在弹出的菜单中选择Export...,然后在弹出的窗口中选择Android标签下的Generate Gradle build files,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/ae7bd77d3aa8e0d4624046c885c4e4db.webp?x-image-process=image/format,png)
然后按提示操作就可以在工程目录下生成一个build.gradle文件,之后我们就可以用AndroidStudio导入这个build.gradle文件了,导入的过程中会连同这个工程一齐导入,之后,就会看到导入后的工程了,如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/cd79be2e3927daee2e6cf32a1f183de5.webp?x-image-process=image/format,png)
看到了吧,整个工程还是保持eclipse中的目录结构。右边是eclipse自动生成的build.gradle文件的内容,跟代码无关。并且只有一个build.gradle文件,没有分全局的gradle和模块的gradle,使用了很旧的Gradle版本,并且使用已经不建议的android插件,之所以工程目录没有使用AndroidStudio默认格式,而可以保持eclipse目录结构,都是因为gradle文件中的那一部分sourceSets下的配置,sourceSets的配置可以允许我们改变工程的目录组织结构,而不需要必须使用AndroidStudio的默认结构,而且build.gradle构建一直不成功。。。也是醉了。
由于存在这么多的疑问,我担心会给将来留坑,并且目录结构都不是AndroidStudio默认,我决定:放弃这种方法,采用方法3:新建一个AndroidStudio工程,把代码和资源一点一点拷过去,使用“纯粹”的AndroidStudio开发方式。
二、采用方法3把工程迁移到AndroidStudio
这种方法的过程也没什么好讲的,就是把java代码和资源文件复制粘贴到新工程的目录下就OK了,先来看一下效果,下图是我迁移完的效果:
![](https://i-blog.csdnimg.cn/blog_migrate/270a8dcafdb91cad262d26850085fcae.webp?x-image-process=image/format,png)
怎么样,是不是清爽了许多,目录结构完全是AndroidStudio的格式,首先一个注意的问题就是公司以前的项目是没有用到v7包的,所以在build.gradle中注释掉这个maven引用,以免引起不必要的麻烦。
还有一点就是以前项目中是有jni代码的,但是我们的jni代码目录组织结构比较复杂,不是标准的jni目录,AndroidStudio又不是靠mk文件来配置C代码,所以还没搞定,暂时只是把so包拿过来用,C代码的编译还是在eclipse下进行,将来搞定了我再回来给大家补充。下面把我的修改过程一一讲述一下:
1、注释掉build.gradle中v7包的引用,这个上面已经说过了,因为项目中以前没用到v7包;
2、迁移AIDL文件。如果你的项目中没有用到AIDL,那你可以跳过这部分。在eclipse中,aidl文件是跟java文件放在同一个包下的,但是AndroidStudio要求aidl文件默认放在模块下的src/main/aidl文件夹下,并且包名要与以前在java包下的包名、路径相同,比如以前aidl文件在com.example.mycode包下边,那么你也要在aidl文件夹下建这样一个同名的包,把aidl文件移过去,如果没有aidl文件夹,那就点右键新建一个,效果如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/2ccf228f647edd84c535f7e7e3250ada.webp?x-image-process=image/format,png)
![](https://i-blog.csdnimg.cn/blog_migrate/1149d2f2829a4ed5a5af98cb203fb8d9.webp?x-image-process=image/format,png)
如果aidl文件摆放不正确,java中引用service的类就会报错,aidl文件默认是放在这里的,当然也可以通过配置build.gradle文件来使它们跟java代码混在一起,但是不建议这样做,我们尽量按照 AndroidStudio的默认配置来做;
3、修改AndroidManifest.xml文件
我在进行完以上步骤后尝试同步gradle配置,结果报了
Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed with multiple errors, see logs
这个错误,如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/c202beed255cdc71bdbb189c26d4d080.webp?x-image-process=image/format,png)
merger是合并的意思嘛,开始觉得很奇怪,我们工程又没有Library引用,跟谁合并呢,后来想起来build.gradle中引用了v7包,但是把v7包的引用注释掉还是不行,有网友说在manifest中使用tools:replace标签,可能这种方式只适用于Library模块引起的merger冲突,我的很显然不是这种情况;还有网友说在build.gradle的android标签下加入aaptOptions.cruncherEnabled false和aaptOptions.useNewCruncher false,开始时管了点用,后来多试几次又不行,看来也不是这个问题。
后来用了一个笨办法,一点一点注释AndroidManifest.xml中的内容,看看注释掉哪一块可以不报错,结果发现是下图中所示的原因:
![](https://i-blog.csdnimg.cn/blog_migrate/8f3ce2a088c06eaf9861d58c49df5825.webp?x-image-process=image/format,png)
上图中,我的service下配置了intent-filter标签,按理说intent-filter标签下还应该有action子标签,比如像下图这样的标准写法:
![](https://i-blog.csdnimg.cn/blog_migrate/08cde854c68faf81cabadb3948b9f98d.webp?x-image-process=image/format,png)
所以,我们要做的就是注释掉AndroidManifest.xml中service标签下的空的intent-filter标签,至少我用这种方法处理后就不再报错了,看来AndroidStudio完全是一套新的api,跟以前的开发方式都不一样了;
此外,由于版本号等配置在build.gradle文件中已经有了,所以我们在AndroidManifest.xml文件中要删掉重复的配置;
4、图片资源引用问题
经过以上几步修改后,项目终于可以编译运行了,但是悲剧也发生了,一打开app立马闪退,报的错误是:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xxxxx.xx/com.xxxxx.xx.xxxxx.MainActivity}: android.view.InflateException: Binary XML file line #2: Error inflating class android.widget.RelativeLayout
报错的地方就在Activity的onCreate方法中的setConentView方法处,什么原因呢?原因是我们在build.gradle中buildToolsVersion配置的版本过低,我一直在用19.1.0,在这个版本下,要求所有图片必须放在mipmap目录下才能在布局文件中引用,否则就会引起上述Activity闪退,当我把buildToolsVersion的版本改成23.0.2之后就可以引入放在drawable目录下的图片了,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/e55349cdf6052e05087daa5bcf366555.webp?x-image-process=image/format,png)
还有的同学说这个错误是因为图片资源不符合规范,有些本来是jpg图片,只是把扩展名改成了png就拿来用,其实这个问题会导致build同步失败,根本就不可能让应用跑起来,关于这个问题,建议批量修改图片资源,把所有的图片都改成png格式,网上有很多修改图片的工具,但是mac操作系统下有一个现成的方法,不需要安装任何第三方软件就可以批量改图片格式,具体操作方法如下:
5、图片资源不规范导致同步gradle失败的解决方法(Mac操作系统)
(1)进入图片目录,按command+A选中所有图片,然后右键菜单选择打开方式->选择“预览”这个应用程序,这个程序是Mac操作系统自带的,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/16e4bc1dc10188ab61da46d44e62ad32.webp?x-image-process=image/format,png)
(2)打开“预览”之后,点左上角的“显示”,勾选“缩略图”,就可以在预览窗口左侧看到所有图片的缩略图了,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/96f87d5d6a47fac1ae104df2cbf2c9c5.webp?x-image-process=image/format,png)
(3)在缩略图区域的空白处点鼠标右键,勾选排序菜单中的“种类”,按种类排序,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/ec6f5ca041d565a02bf8da985c261832.webp?x-image-process=image/format,png)
然后你就可以看到下图所示的情景:
![](https://i-blog.csdnimg.cn/blog_migrate/fe4681a70d5f75fed361179ce59dd5f5.webp?x-image-process=image/format,png)
(4)将jpg图片重新导出为png图片,方法是在图片上点鼠标右键(如果有多张图片想批量导出的话按住command键点鼠标进行多选,或者直接按command+A全选所有图片),选择“导出为...”, 在弹出的对话框中选择PNG类型,如下图所示
![](https://i-blog.csdnimg.cn/blog_migrate/7b2b93ebddf13a1651228afd5236c1ef.webp?x-image-process=image/format,png)
这样就可以将不符合规范的图片规范化了。
这里之所以用Mac来讲是因为Windows下图片转换的工具有很多,一抓一大把,但是Mac中这类工具却相对较少,为了让大家少走弯路,分享一下Mac的图片转换方法,其实我也是在百度上找的,忘记哪个网站了,感谢那位朋友的无私分享。
6、jar包和so包应该放在哪?
在eclipse中,so包和jar都是放在lib目录下的,那么在AndroidStudio中是不是这样呢?当然不是的。
(1)首先看jar应该放在哪?jar包应该放在模块下的libs目录下,如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/c23f09138bd22959a366df2da0a1d7e6.webp?x-image-process=image/format,png)
然后就可以了,因为在新建工程的时候,系统已经在build.gradle中自动为我们配置了jar包的位置,如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/38067f09e29a92b3add94a86110a4872.webp?x-image-process=image/format,png)
所以我们不需要再配了,直接把jar包拷在libs目录下就可以用;
(2)言归正转,so包应该放在哪呢?AndroidStudio默认的so存放位置是模块下的src/main/jniLibs目录,如图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/19b996a9b81058b3ad593267ee62363f.webp?x-image-process=image/format,png)
如图所示,so包不能像在eclipse中那样跟jar包放在一起(默认情况下),如果没有jniLibs目录就自己建一个。
其实无论是aidl文件的存放位置,还是so包的存放位置,都是可以通过build.gradle文件修改的,这个不是今天的重点,大家有兴趣可以自行搜索相关资料,我们尽量遵循AndroidStudio的默认方式,以便让别人看到我们的项目时不至于一头雾水。
7、最后就是jni源码的存放位置以及如何配置了,这个我始终没搞明白,我知道常规的jni源码应该放在模块下的main/jni目录,跟java目录以及aidl目录并列,但是公司的这个项目有点特殊,jni目录下又包含了两个子目录,两个子目录又各自有各自的mk文件,我直接复制过来的话会报C语言中#include进来的头文件找不到,没办法我只能是在eclipse中编译好so文件之后再拷进来,但是这样一来就无法在AndroidStudio中调试C代码了,好悲摧~~~这个问题有点像是mk文件配置的问题,那么对应的build.gradle文件应该怎么配?还需不需要mk文件?如果有大神知道的话希望能够指点迷津,感激不尽。
至此,我在迁移项目中遇到一些坑大概就总结到这里了,可能没办法涵盖所有的问题,但是希望有遇到跟我一样的问题的时候可以帮助大伙少走弯路。^_^