A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黑妞~ 金牌黑马   /  2014-5-21 10:13  /  2119 人查看  /  4 人回复  /   3 人收藏 转载请遵从CC协议 禁止商业使用本文

    在移动应用飞速发展的今天,APP只针对IOS平台进行开发已经不够了,如今Android在移动设备占有近80%的市场,如此大量的潜在用户怎么能被忽略掉呢。


    在这篇文章中,本人会介绍在IOS开发中,怎么学习一些Android开发的理念,Android和IOS功能上本身有一定的相似之处,但是具体实现的方式各异,所以这篇文章会使用一个项目例子进行对比,说明怎么在这两个平台上分别去实现这个任务。


    除了了解IOS的开发知识,本文还需要对Java有一定的了解,并能够安装和使用ADT(Android Development Tools)。此外,如果你是一个Android新手,那么请试试去看看Android的官方教程—— building your first app,非常有用。


UI设计简要说明


    本文不会深入研究关于IOS和Android两个平台之间的用户体验或者设计模式之间的差异,不过如果能够理解Android上的一些优秀的UI范例也很有帮助:ActionBar、Overflow menu、back button share action等等。假如你很想尝试Android开发,那么强烈推荐你去Google Play Store上购置一台Nexus5,然后把它作为你日常使用的设备使用一周,然后尝试仔细了解这个操作系统的各种功能和扩展特性,如果开发者连操作系统的各种使用规则都不了解,那么做出来的产品一定有问题。


编程语言的应用框架


    Objective-C和Java之间有很多不同之处,如果把Objective-C的编程风格带到Java里面的话,很多代码也许会和底层的应用框架冲突。简单地说,就是需要注意一些区别:


    去掉Objective-C里面的类前缀,因为Java里有显式的命名空间和包结构,所以就没必要用类前缀了。


    实例变量的前缀用“m”,不用“_”,在写代码的过程中要多利用JavaDoc文档。这样能使代码更清晰,更适合团队合作。


    注意检查NULL值,Objective-C对空值检查做的很好,不过Java没有。


    不直接使用属性,如果需要setter和getter,需要创建一个getVariableName()方法,然后显式调用它。如果直接使用“this.object”不会调用自定义的getter方法,你必须使用this.getObject这样的方法。


    同样的,方法命名时带有get和set前缀来标示它是getter和setter方法,Java的方法很喜欢写成actions或者queries等,比如Java会使用getCell(),而不用cellForRowAtIndexPath。


项目结构


    Android应用程序主要分为两部分。第一部分是Java源代码,以Java包结构排布,也可以根据自己的喜好进行结构排布。最基本的结构就是分为这几个顶层目录:activities、fragments、views、adapters和data(models和managers)。


    第二部分是res文件夹,就是“resource”的简称,res目录存放的是图片、xml布局文件,还有其它xml值文件,是非代码资源的一部分。在IOS上,图片只需要匹配两个尺寸,而在Android上有很多种屏幕尺寸需要考虑,Android上用文件夹来管理管理图片、字符串,还有其它的屏幕配置数值等。res文件夹里也含有类似IOS中xib文件的xml文件,还有存储字符串资源、整数值,以及样式的xml文件。


    最后,在项目结构上还有一点相似的地方,就是AndroidManifest.xml文件。这个文件相当于IOS的Project-Info.plist文件,它存储了activities、application还有Intent的信息,要了解更多关于Intent的资料,可以继续阅读这篇文章。


Activities


    Activities是Android APP最基本的可视单元,就像UIViewControllers是IOS最基本的显示组件一样。Android系统使用一个Activity栈来管理Activity,而IOS使用UINavigationController进行管理。当APP启动的时候,Android系统会把Main Activity压栈,值得注意的是这是还可以再运行别的APP Activity,然后把它放到Activity栈中。返回键默认会从Activity栈进行pop操作,所以如果用户按下返回键,就可以切换运行已运行的App了。


    Activities还可以用Intent组件初始化别的Activity,初始化时可携带数据。启动一个新的Activity类似于IOS上创建一个UIViewController。最基本的启动一个新的Activity的方式就是创建一个带有data的Intent组件。Android上实现自定义Intent初始化器的最好方法就是写一个静态getter方法。在Activity结束的时候也可以返回数据,在Activity结束的时候可以往Intent里面放置额外的数据。


    IOS和Android的一个大的区别是,任何一个在AndroidManifest文件中注册的Activity都可以作为程序的入口,为Activity设置一个intent filter属性比如“media intent”,就可以处理系统的媒体文件了。最好的例子就是编辑照片Activity。它可以打开一张照片,然后进行修改,最后在Activity结束时返回修改后的照片。


    附加提醒:要想在Activity和Fragment之间传递对象,必须要实现Parcelable接口,就像在IOS里需要遵循协议一样。还有,Parcelable对象可以存在于Activity或者Fragment的savedInstanceState里,这样在它们被销毁后可以更容易重建它们的状态。


    下面就来看看怎么在一个Activity中启动另一个Activity,然后在第二个Activity结束时进行返回。


启动其它Activity并返回结果


// A request code is a unique value for returning activities
private static final int REQUEST_CODE_NEXT_ACTIVITY = 1234;

protected void startNextActivity() {
    // Intents need a context, so give this current activity as the context
    Intent nextActivityIntent = new Intent(this, NextActivity.class);
       startActivityForResult(nextActivityResult, REQUEST_CODE_NEXT_ACTIVITY);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
    case REQUEST_CODE_NEXT_ACTIVITY:
        if (resultCode == RESULT_OK) {
            // This means our Activity returned successfully. For now, Toast this text.  
            // This just creates a simple pop-up message on the screen.
                Toast.makeText(this, "Result OK!", Toast.LENGTH_SHORT).show();
            }
            return;
        }   
        super.onActivityResult(requestCode, resultCode, data);
}




Activity结束时返回数据


public static final String activityResultString = "activityResultString";

/*
* On completion, place the object ID in the intent and finish with OK.
* @param returnObject that was processed
*/
private void onActivityResult(Object returnObject) {
        Intent data = new Intent();
        if (returnObject != null) {
            data.putExtra(activityResultString, returnObject.uniqueId);
        }
     
        setResult(RESULT_OK, data);
        finish();        
}
Fragments
    Fragment的概念在Android上比较独特,从Android3.0开始引入。Fragment是一个迷你版的控制器,可以显示在Activity上。它有自己的状态和逻辑,同时在一个屏幕上支持多个Fragment同时显示。Activity充当Fragment的控制器,Fragment没有自己的上下文环境,只能依赖Activity存在。



    使用Fragment最好的例子就是在平板上的应用。可以在屏幕左边放一个fragment列表,然后在屏幕的右边放fragment的详细信息。Fragment可以把屏幕分成可重复利用的小块,分别控制管理。不过要注意Fragment的生命周期,会有些细微的差别。






    Fragment是实现Android结构化的一种新的方式,就像IOS中的不用UITableview而用UICollectionView实现列表数据结构化。因为只使用Activity而不用Fragment的话,会简单一些。不过,之后你会遇到麻烦。如果不使用Fragment代替全盘使用Activity的话,在后面需要利用intent和进行多屏幕支持的时候就会遇到困难。


    下面看一个UITableViewController的例子和一个ListFragment的地铁时刻表示例。


表格实现






@interface MBTASubwayTripTableTableViewController ()

@property (assign, nonatomic) MBTATrip *trip;

@end

@implementation MBTASubwayTripTableTableViewController

-(instancetype)initWithTrip: (MBTATrip *)trip
{
    self = [super initWithStyle:UITableViewStylePlain];
    if (self) {
        _trip = trip;
        [self setTitle:trip.destination];
    }
    return self;
}

-(void)viewDidLoad
{
    [super viewDidLoad];
     
    [self.tableView registerClass:[MBTAPredictionCell class] forCellReuseIdentifier:[MBTAPredictionCell reuseId]];
    [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([MBTATripHeaderView class]) bundle:nil] forHeaderFooterViewReuseIdentifier:[MBTATripHeaderView reuseId]];
}

#pragma mark - UITableViewDataSource

-(NSInteger)numberOfSectionsInTableView: (UITableView * )tableView
{
    return 1;
}

-(NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
    return [self.trip.predictions count];
}

#pragma mark - UITableViewDelegate

-(CGFloat)tableView: (UITableView * )tableView heightForHeaderInSection: (NSInteger)section
{
    return [MBTATripHeaderView heightWithTrip:self.trip];
}

-(UIView *)tableView: (UITableView * )tableView viewForHeaderInSection: (NSInteger)section
{
    MBTATripHeaderView *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:[MBTATripHeaderView reuseId]];
    [headerView setFromTrip:self.trip];
    return headerView;
}

-(UITableViewCell * )tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath * )indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[MBTAPredictionCell reuseId] forIndexPath:indexPath];
     
    MBTAPrediction * prediction = [self.trip.predictions objectAtIndex:indexPath.row];
    [(MBTAPredictionCell * )cell setFromPrediction:prediction];
     
    return cell;
}

-(BOOL)tableView: (UITableView * )tableView canEditRowAtIndexPath: (NSIndexPath * )indexPath
{
    return NO;
}

- (void)tableView: (UITableView * )tableView didSelectRowAtIndexPath: (NSIndexPath * )indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

@end

4 个回复

倒序浏览
我是大二计算机专业的学生,准备毕业后去黑马培训ios,现在入门了C/C++而已,自学.net和Objective-C中....加油。求技术分,哈哈
回复 使用道具 举报
说实话,有些看不太懂。。。
回复 使用道具 举报
只能搬个小板凳,慢慢琢磨了,辛苦立姐
回复 使用道具 举报
看不懂,这些东西太深奥了,慢慢研究
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马