我曾经从事过五年的iOS应用开发工作,那段时间我一直在尽量避免同Android打交道——不过现在情况不同了。不管大家是否相信,Android开发其实乐趣满满、而且与iOS开发相比也不像大家想象的那样差异巨大。
我在Android平台上开发出这款“七分钟锻炼”应用,并借此学到了很多宝贵的知识。我希望这篇文章分享的一些小技巧也能帮助大家解决实际问题。请注意,我接下来进行比较的内容并不一定完全匹配,而且本文的重点也不在于完整地叙述Android开发;当然,我一定会提到自己在开发这款简单应用的过程中所积累到的全部经验。
IDE
我选择使用Android Studio,而且我愿意打赌:只要测试完成,它将成为未来的业界标准。虽然很多报道称它的运行状态并不稳定,但在我的实际使用中、它仅仅崩溃过一次。也许我只是习惯了Xcode。
Java
无论大家对Java如何评价,说到底它也只是不过是一种编程语言而已。它能够解决问题,而且对于经验丰富的开发者来说、大家肯定是把主要精力放在框架而非Java身上。很高兴我用不着跟J2EE扯上关系。
iOS加密
移动应用安全保护平台——爱加密,在Android应用加密保护方面有dex加壳、独有的so库加密保护、资源文件保护等。而且推出了iOS应用加密保护,实属全球首创。分别从本地数据、方法体/方法名、URL编码、程序结构、网络传输数据等几个方面对iOS应用进行全方位的保护,并可以根据iOS应用用户的需求提供定制解决方案,从而实现iOS防破解保护。下图是iOS应用使用前后
模拟器
我一直认为iOS模拟器让人头痛不已,但相比之下我才发现当初的自己还是太年轻。在稍作尝试之后,我决定放弃Android模拟器、直接将应用部署在实际设备上——除非大家愿意拿出大量时间盯着屏幕枯等。
Storyboard / NIB
我在自己的iOS开发博客上谈了很多关于Storyboard的话题,很多与我意见相左的读者发来的一些措辞强硬的邮件让我彻底放弃了这一交流平台。
Android使用的布局格式为xml。它们彼此之间完全独立。Android Studio还提供一套出色的“所见即所得”编辑器:
但大家仍然可以深入到原始xml当中——如果愿意的话(反正我一般是不愿意这么麻烦)。
相对于自动布局,大家也可以选择其它布局容器,例如RelativeLayout以及FrameLayout之类。在这里,我们能够以像素数量(即设备的像素容纳能力)或者matchparent、wrapcontant等来设定理想的宽度、高度、填充效果、边框以及色调。
Wrap非常适合文本内容,它会自动将调整正确的高度并设定与之相适应的尺寸,并把其余工作交给LinearLayout等特定布局方案。
虽然我还没有用过,但Fragment看起来同样是一种对自定义UI元素加以重新利用的好途径。
UIViewController
Android利用一个Activity来实现UIViewConroller的功能。每一个屏幕/窗口都相当于一个Activity。我们就在这里处理大部分工作,包括将数据绑定到UI当中或者处理事件等等。
Controller/View转换
在iOS当中我们利用segue、pushViewController、presentController等在不同屏幕之间进行迁移。但在Android环境下,我们需要使用Intent。
大家可以轻松迁移至新的activity当中,甚至能够将一部分数据传递过去。
public void onItemClick(...) {
Intent i = new Intent(getBaseContext(), MyActivity.class);
i.putExtra("row", position);
startActivity(i);
}
在新的Activity(也就是以上代码中的MyActivity)中,我们可以提取出传递来的数据:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mine);
Bundle extras = getIntent().getExtras();
if (extras != null) {
int row = extras.getInt("row");
....
}
...
}
大家也可以利用Intent来触发各类事件,例如实现表格共享:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "Share This");
sendIntent.setType("text/plain");
startActivity(sendIntent);
IBOutlet
也许大家跟我一样,在超过半数的情况下会忘记连接IBOutlet。
在Android当中,每一个场景/组件都拥有独立的ID,内容如下所示:
@+id/myButton
它随后会自动生成一个名为R的类,接下来我们可以如下所示访问代码中的按钮:
Button button = (Button)findViewById(R.id.myButton);
标签
iOS开发者们经常使用的一项技巧就是利用场景标签来保存查找信息,例如整体布局的位移。在Android环境下,大家也可以将整个对象加入到标签当中,这种作法非常实用。
row.setTag(data);
UITableViewController / UITableViewDataSource / UITableViewCell
Android当中的ListView就相当于iOS上的UITableView。
而UITableViewDataSource在Android中所对应的则是ArrayAdapter:
MyAdapter adapter = new MyAdapter(this, R.layout.listview_item_row);
listView.setAdapter(adapter);
其中listviewitemrow属于某一行的布局,相当于iOS中的UITableViewCell。
其中的adapter随后会在getView当中创建/重新使用各行。
大家也可以像这样设置标题:
View header = getLayoutInflater().inflate(R.layout.listview_header_row, null);
listView.addHeaderView(header);
图片/资源
由于有了Asset Catalogue的辅助,iOS环境下的图片处理变得非常轻松,通常情况下开发者只需考虑视网膜屏与非视网膜屏这两种情况(除非大家想要在iPhone上使用专门针对iPad的图片)。
由于Android阵营下各款设备的分辨率千差万别,因此大家必须要提供以下四种图片格式。
它们分别是:mdpi(普通分辨率)、hdpi(高分辨率)、xhdpi(超高分辨率)以及xxhdpi(超超高分辨率)。我个人认为xxxhdpi版本的诞生将只是时间问题。
在利用Android Studio创建项目时,大家只需要提供一份图标、它就能自动创建出这四种格式。这种作法相信已经给从事过Android应用开发的朋友们留下了严重的心理阴影:别怕,大家可以随后手动将其替换为完美的像素版本。
因此,最基本的解决思路就是为每幅图片针对每种像素密度创建一个单独的版本,为其设定同样的名称并放在正确的文件夹之下;这样Android就会视设备平台的具体情况挑选理想的版本。
自定义字体
自定义字体在Android上实现起来同样非常简单:将字体复制到main/assets当中,而后就能利用以下代码加以调用:
Typeface font = Typeface.createFromAsset(getAssets(), "Lato-Regular.ttf");
textView.setTypeface(font);
问题在于这种方式并不是在所有设备上都行得通,因此大家需要准备一套后备字体——不过我自己手头的两台Android设备都没有提供这样的字体。
NSLog
日志看起来没什么可讲的,大家可以利用它来进行应用程序调试什么什么的(此处省去一千字)。System.out.println(..)似乎也同样能够完成这项任务。
向下兼容能力
我们都听说过Android设备的碎片化问题。不过从本质上讲,处理旧版本Android的难度并不比在旧版本iOS上使用新型iOS功能更高。不过大家可能需要对这种兼容能力加以高度重视,毕竟Android环境下这类问题的出现频率要远高于iOS。
我们可以通过下列代码来检查当前Android版本:
if (Build.VERSION.SDK_INT >= 11.0) {
...
}
以下代码则用于防止函数调用引发的警告信息:
@SuppressLint({"NewApi", "LocalSuppress"})
private void myFunction() {
...
}
千奇百怪的漫长Android之旅
CountDownTimer
CountDownTimer——这项内置功能的存在实在让我兴奋不已,因为这正是我的七分钟锻炼应用所必需的要素。然而经过实际测试,它不会在onFinish之前发送最后一次onTick,这是个非常诡异的bug而且到现在也没能得到修复。诡异,真是太诡异了。
方位
当用户转动手中的设备时,我们的activity也会完全重置,这意味着大家必须在activity重新载入之后为其保留全部状态与恢复机制。Android环境下的处理方式令人头痛,但iOS则处理得很好。
Kindle Fire / Amazon Store
要让自己的应用程序顺利入驻Amazon Store,我只需要对现有成果作出两项调整:
·YouTube SDK无法起效,因为Kindle Fire上不提供YouTube应用。不过对Flash的支持能力依然被保留下来。
·大家需要针对Amazon Store替换应用购买代码。
大家可以利用android.os.Build.MANUFACTURER以及android.os.Build.MODEL对设备的制造商以及产品型号信息进行检测。