移动开发iOS&Android对比学习--异步处理

简介:

在移动开发里很多时候需要用到异步处理。Android的主线程如果等待超过一定时间的时候直接出现ANR(对不熟悉Android的朋友这里需要解释一下什么叫ANR。ANR就是Application Not Responding,应用无响应的意思。系统在应用一段时间无响应的时候会弹出这个对话框。用户可以选择继续等待或者强制关闭)。这些还是次要的,最主要的还是心急的用户。让用户长时间等待是得罪他们的最好办法!

Android有一个很简单的办法实现异步处理:AnsyncTask。使用的时候你需要继承一个基类

public abstract class AsyncTask<Params, Progress, Result>

对java不熟的同学这里需要说明,尖括号里的是类型参数。这是java的一个语法,泛型。这三个参数分别指定的是输入参数的类型、任务执行进度值的类型和任务执行结果的类型。并不是所有的类型都被使用,不用的时候指定为void类型。

最简单的使用就是继承这个类以后Override方法doInBackground(Params... params)。使用的时候实例化你的AsyncTask实现,调用execute(Params... params)方法就开启了异步操作。例如:

布局代码:

复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <Button  
        android:id="@+id/executeButton"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text=" Start "/>   
    <ScrollView  
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content">  
        <TextView  
            android:id="@+id/textView"  
            android:layout_width="fill_parent"   
            android:layout_height="wrap_content"/>  
    </ScrollView> 

</LinearLayout>
复制代码

 

java代码:

复制代码
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class AsyncTaskDemo extends Activity {
    
    private Button executeButton;   
    private TextView textView; 
    
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);
        
        executeButton = (Button)findViewById(R.id.executeButton);
        textView = (TextView)findViewById(R.id.textView);
         
        executeButton.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                Log.i("-task-","Task started.");
                new MyAsyncTask().execute(" on click");
            }
        });
    }
    
    class MyAsyncTask extends AsyncTask<String, Integer, String>{
        
        @Override
        public String doInBackground(String... params){
            Log.i("-task-","doInBackground is called" + params[0]);
            try {
                // 线程暂停2秒模拟后台任务
                Thread.sleep(2000);
            } catch (Exception e) {
                return "";
            }
            return "Hello World from AsyncTask";
        }
        
        // 在doInBackground方法执行之后调用这个方法
        public void onPostExecute(String result){
            Log.i("-task-", "doPostExecute is called");
            textView.setText(result);
        }
    }
}
复制代码

运行效果:

 

看到这里读者应该明白,doInBackground方法就是在后台执行的那个异步的方法。

但是AsyncTask的妙处不至于此。大家都知道,在UI线程意外不可以更新UI组件。如果后台线程执行完后一定要通知UI线程,由UI线程根据后台线程的执行结果更新UI组件。AsyncTask的妙处就在于,在它的实现中实现某些方法就可以直接更新UI。当然这些方法是在UI线程中的。这些方法有:

  1. onPreExecute() 在execute方法调用后立即执行,在doInBackground执行前执行。相当于在后台操作开始前做一些准备工作。
  2. doInBackground(Params... params) 在onPreExecute之后执行,处理需要在后台操作的任务。在其中可以通过publishProgress(Progress... values)通知UI线程更新进度。
  3. onProgressUpdate(Progress... values)在调用publishProgress后此方法执行。将进度更新到UI组件上。
  4. onPostExecute(Result result) 在doInBackground执行结束之后,后台执行结果作为参数传入这个方法并根据这个结果更新UI组件。
  5. onCancelled() 取消后台操作的时候调用方法cancel(boolean endTaskDuringExecuting),这个时候onCancelled方法会被调用。同事,isCancelled()方法返回true。在后台任务的执行中需要检查是否已经被取消,尤其是循环中。这样可以保证后台任务可以尽快退出。

下面就依据上面所说更新代码了:

layout:

复制代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <Button  
        android:id="@+id/executeButton"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text=" Start "/>   
    <Button  
        android:id="@+id/cancelButton"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:enabled="false"  
        android:text=" cancel "/>  
    <ProgressBar   
        android:id="@+id/progressBar"   
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content"   
        android:progress="0"  
        android:max="100"  
        style="?android:attr/progressBarStyleHorizontal"/>
    <ScrollView  
        android:layout_width="fill_parent"   
        android:layout_height="wrap_content">  
        <TextView  
            android:id="@+id/textView"  
            android:layout_width="fill_parent"   
            android:layout_height="wrap_content"/>  
    </ScrollView> 

</LinearLayout>
复制代码

java:

复制代码
public class AsyncTaskDemo extends Activity {
    
    private Button executeButton; 
    private Button cancelButton;
    private TextView textView; 
    private ProgressBar progressBar;
    
    private MyAsyncTask myAsyncTask;
    
    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_demo);
        
        executeButton = (Button)findViewById(R.id.executeButton);
        cancelButton = (Button)findViewById(R.id.cancelButton);
        textView = (TextView)findViewById(R.id.textView);
        progressBar = (ProgressBar)findViewById(R.id.progressBar);
         
        executeButton.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                Log.i("-task-","Task started.");
                
                // 每次开始的时候必须初始化一次。
                myAsyncTask = new MyAsyncTask();
                myAsyncTask.execute(" on click");
                
                cancelButton.setEnabled(true);
                executeButton.setEnabled(false);
            }
        });
        
        cancelButton.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                Log.i("-task", "Task cancelled");
                
                // 取消任务
                myAsyncTask.cancel(true);
            }
        });
    }
    
    class MyAsyncTask extends AsyncTask<String, Integer, String>{
        
        @Override
        protected void onPreExecute() {
            Log.i("-task-", "onPreExecute is called");
            textView.setText("Mission is about to start dude...");
        }
        
        @Override
        public String doInBackground(String... params){
            Log.i("-task-","doInBackground is called" + params[0]);
            
            if (isCancelled()) {
                return "cancelled";
            }
            try {
                // 开始进度是0.
                publishProgress(0);
                Thread.sleep(2000);
                publishProgress(30);
                
                // 如果有循环的话需要在循环中每次都检查是否任务已经被取消。
                if (isCancelled()) {
                    return "cancelled";
                }
                
                // 线程暂停2秒模拟后台任务
                Thread.sleep(2000);
                publishProgress(100);
            } catch (Exception e) {
                return "";
            }
            return "Hello World from AsyncTask";
        }
        
        @Override
        protected void onProgressUpdate(Integer...progresses){
            Log.i("-task-", "onProgressUpdate is called");
            
            progressBar.setProgress(progresses[0]);
            textView.setText(progresses[0] + "% is handled...");
        }
        
        // 在doInBackground方法执行之后调用这个方法
        @Override
        protected void onPostExecute(String result){
            Log.i("-task-", "doPostExecute is called");
            textView.setText(result);
            
            executeButton.setEnabled(true);
            cancelButton.setEnabled(false);
        }
        
        @Override
        protected void onCancelled(){
            Log.i("-task-", "onCancelled is called");
            
            progressBar.setProgress(0);
            textView.setText("Cancelled");
            
            executeButton.setEnabled(true);
            cancelButton.setEnabled(false);
        }
    }
}
复制代码

执行结果:

1. 没有取消的

2. 取消了的

这里有一点需要注意。AsyncTask对象,一个只跑一次任务!所以,这里你可以看到,每次在执行一个后台任务的时候都要初始化一次。从这里看到,AsyncTask非常好用。只要把后台任务放到doInBackground方法里,其他的在UI线程上执行的只要按照需要放在其他的方法中就可以了。简直是随用随调,方便已用。

在iOS里最方便的就是GCD了。GCD,Grand Central Dispatch。是OSX10.6 iOS4.0引入的,是一套新的编写并行程序的方法,是基于c开发的开源框架。GCD的便携很大程度上依赖于block。block就类似于lambda表达式。所以GCD的写法非常简单。GCD的异步操作是基于线程的,只不过是有GCD去管理这些线程,以发挥多核心CPU的优势。开发者就不用花时间在具体的线程管理的细节上。

block的例子:

void (^blockDemo)(void) = ^{
      // do something here...  
}

关于block更详细的知识,请到这里自行补脑。

如果说block是异步任务的子弹的话,那么那把枪就是dispatch queue。dispatch queue可以是串行执行的也可以是并行执行的。串行dispatch queue按照先进先出的顺序执行任务,并行的dispatch queue只是按照这样的方式开始任务,至于具体的执行顺序会随具体的执行条件变化。

GCD包括三中queue:

  1. Main queue:系统定义,用dispatch_get_main_queue获取。提交到这个queue的任务会在UI线程中执行。
  2. Global queue:系统定义,用dispatch_get_global_queue获取。global queue就是并行queue,一共有四种优先级。
  3. Private queue:用 dispatch_queue_create创建。默认为串行执行。可以用DISPATCH_QUEUE_CONCURRENT指定为并行队列(只在iOS5或以后的系统中有效)。

下面通过代码展示使用GCD实现异步操作有多简单:

复制代码
// 创建一个private queue
dispatch_queue_t myBackgroundQueue;
myBackgroundQueue = dispatch_queue_create("com.company.subsystem.task", NULL);
 
// 异步处理
// Dispatch a private queue
dispatch_async(myBackgroundQueue, ^(void) {
    // do some time consuming things here
});

// Release queue。iOS6以后系统自动管理内存。
dispatch_release(myBackgroundQueue);

// 获取global queue
dispatch_queue_t myGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 异步操作
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
, ^(void) {
    // do some time consuming things here
});
复制代码

只要给你的queue dispatch_async一个任务(block)就可以。

由此可见,用dispatch queue实现异步比Android的AsyncTask简单了很多。只需要简单的几句话就可以实现。不用实现抽象类什么的繁琐操作。当你调用dipatch_async后,代码立即返回分发出去的任务由系统分配资源在后台异步执行。

参考上面Android的例子,在dispatch queue执行的过程中要更新异步任务执行进度怎么办呢,要在界面上现实执行了百分之多少,progress bar要现实对应的进度怎么办呢?UI组件的更新需要在UI线程中执行。这个时候就需要用到上面说的main queue了。我们上面已经说过使用dispatch_get_main_queue方法来获取main queue也就是UI线程的queue。下面通过一个简单的例子说明在dispatch queue异步操作中如何更新UI组件。

复制代码
dispatch_async(myBackgroundQueue, ^(void) {
 
// 异步操作在这里。。。
 
    dispatch_async(dispatch_get_main_queue(), ^{
 
        // 操作UI组件等。。。
    });
});
复制代码

另外需要说明一点:如果一个变量需要在queue中操作,准确的说是在block中操作的话,需要有一个特别的声明:在常用的声明前加__block。

那么上面在Android中示例用ObjC的GCD该如何实现呢?下面给出答案。

界面布局:

头文件代码:

复制代码
#import <UIKit/UIKit.h>

@interface CMRootViewController : UIViewController{
@private
    __block BOOL _cancelTask;
}

@property (assign, nonatomic, readonly) __block BOOL cancelled;
@property (strong, nonatomic) dispatch_queue_t taskQueue;

@property (weak, nonatomic) IBOutlet UIProgressView *progressBar;
@property (weak, nonatomic) IBOutlet UILabel *progressLabel;
@property (weak, nonatomic) IBOutlet UIButton *startButton;
@property (weak, nonatomic) IBOutlet UIButton *cancelButton;

- (IBAction)startAction:(id)sender;
- (IBAction)cancelAction:(id)sender;

@end
复制代码

源文件:

复制代码
#import "CMRootViewController.h"

@implementation CMRootViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // 初始化线程
        self.taskQueue = dispatch_queue_create("com.queue.demo", NULL);
        _cancelTask = NO;
        _cancelled = NO;
        
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = @"Queue Demo";
    self.progressBar.progress = .0f;
    self.progressLabel.text = @"0%";
}

- (IBAction)startAction:(id)sender {
    NSLog(@"Start button is clicked.");
    
    _startButton.enabled = NO;
    _cancelButton.enabled = YES;
    _cancelled = NO;
    _cancelTask = NO;
    
    // 这里用sleep方法暂停线程,代表那些费时的操作。
    // 在任务执行的过程中check是否已经取消了操作,尤其在循环里。这样可以尽快停止后台操作
    dispatch_async(self.taskQueue, ^{
        if (_cancelTask) {
            NSLog(@"Task cancelled");
            _cancelButton.enabled = NO;
            _startButton.enabled = YES;
            _cancelled = YES;
            return;
        }
        sleep(2);
        NSLog(@"Task: 10%% is completed.");
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressBar.progress = .1f;
            self.progressLabel.text = @"10%";
        });
        
        if (_cancelTask) {
            NSLog(@"Task cancelled");
            _cancelButton.enabled = NO;
            _startButton.enabled = YES;
            _cancelled = YES;
            return;
        }
        sleep(3);
        NSLog(@"Task: 60%% is completed.");
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressBar.progress = .6f;
            self.progressLabel.text = @"60%";
        });
        
        if (_cancelTask) {
            NSLog(@"Task cancelled");
            _cancelButton.enabled = NO;
            _startButton.enabled = YES;
            _cancelled = YES;
            return;
        }
        sleep(2);
        NSLog(@"Task: 80%% is completed.");
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressBar.progress = .8f;
            self.progressLabel.text = @"80%";
        });
        
        if (_cancelTask) {
            NSLog(@"Task cancelled");
            _cancelButton.enabled = NO;
            _startButton.enabled = YES;
            _cancelled = YES;
            return;
        }
        sleep(1);
        NSLog(@"Task: 100%% is completed.");
        dispatch_async(dispatch_get_main_queue(), ^{
            self.progressBar.progress = 1.f;
            self.progressLabel.text = @"100%";
        });
        
    });
}

- (IBAction)cancelAction:(id)sender {
    NSLog(@"Cancel button is clicked.");
    _cancelTask = YES;
    
    _startButton.enabled = YES;
    _cancelButton.enabled = NO;
}

@end
复制代码

 

Android和iOS对比着学习可以对这两个平台的各种技术留下深刻的印象。毕竟都是移动平台,大多数的语言之外的东西有很多东西都是想通的。Android有着广大的用户群体,而且在不断的进步。所以不必把两个平台完全独立或者对立起来。对于开发者来说得到实惠才是最重要的!

 

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 572064792 | Nodejs:329118122 做人要厚道,转载请注明出处!














本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sunshine-anycall/p/3411112.html ,如需转载请自行联系原作者

相关文章
|
1月前
|
机器学习/深度学习 人工智能 语音技术
探索未来:安卓与iOS的人工智能竞赛
在当今数字化时代,安卓和iOS作为两大主流移动操作系统,已经成为人们日常生活不可或缺的一部分。随着人工智能技术的飞速发展,安卓与iOS之间的竞争日益激烈。本文将深入探讨安卓与iOS在人工智能领域的发展现状和未来趋势,分析两者之间的差异和竞争优势,为读者带来全新的视角和思考。
16 1
|
2月前
|
API 开发工具 Android开发
iOS 和 Android 平台的开发有哪些主要区别?
iOS与Android开发区别:iOS用Objective-C/Swift,App Store唯一下载渠道;Android用Java/Kotlin,多商店发布(如Google Play、华为市场)。设计上,iOS简洁一致,Android灵活可定制。开发工具,iOS用Xcode,Android用Android Studio。硬件和系统多样性,iOS统一,Android复杂。权限管理、审核流程及API各有特点,开发者需依据目标平台特性进行选择。
36 3
|
10天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
13天前
|
人工智能 安全 Android开发
【专栏】在人工智能时代,Android和iOS两大移动操作系统巨头正加速融合与创新
【4月更文挑战第27天】在人工智能时代,Android和iOS两大移动操作系统巨头正加速融合与创新。Android以其开放性占据广阔市场,集成AI功能如语音助手;而iOS以其稳定性和生态优势,如Siri,提供卓越体验。两者在AI技术、应用场景上相互借鉴,拓展至医疗、教育等领域,并逐步打通生态系统。然而,技术竞争、数据隐私和标准不一是挑战,新市场需求、技术创新和产业合作则带来机遇。未来,二者将继续推动AI发展,为社会进步贡献力量。
|
11天前
|
缓存 Android开发 iOS开发
打造高效移动应用:Android与iOS性能优化策略
【4月更文挑战第29天】 在移动设备日益成为用户日常互动的主要平台的今天,应用程序的性能已成为决定其成功的关键因素之一。本文将探讨针对Android和iOS平台的性能优化技巧,涵盖内存管理、多线程处理、网络请求优化以及用户界面的流畅性提升等方面。通过分析不同操作系统的架构特点,我们旨在提供一套综合性的策略,帮助开发者构建快速、响应迅捷且用户体验良好的应用。
|
18天前
|
网络协议 Shell Android开发
Android 深入学习ADB调试原理(1)
Android 深入学习ADB调试原理(1)
26 1
|
18天前
|
缓存 网络协议 编译器
针对Android系统工程师的C/C++学习目录
针对Android系统工程师的C/C++学习目录
5 0
|
22天前
|
安全 Android开发 iOS开发
探索安卓与iOS操作系统的异同
在当今移动互联网时代,安卓和iOS作为两大主流移动操作系统,扮演着至关重要的角色。本文将深入探讨安卓与iOS操作系统的异同之处,包括界面设计、应用生态、安全性等方面,为读者提供全面的了解和比较。
11 0
|
1月前
|
物联网 vr&ar Android开发
探索安卓与iOS操作系统的发展趋势
本文探讨了安卓与iOS操作系统在不同方面的发展趋势,并分析了它们在技术、用户体验和市场竞争等方面的特点和趋势。通过对比研究,揭示了两大操作系统的发展方向,为读者了解移动操作系统的未来发展提供了参考。
7 0
|
移动开发 程序员 Android开发
寒冬之下,移动开发没人要了, iOS 开发者该 何去何从?
前言: 作者 | 梅梅    文章来源 CSDN 对于移动互联网而言,2018 年像是球场上的一声裁判哨。哨声响起,高潮迭起的上半场结束。本该再创辉煌的下半场,还没开赛却被告之:规则改变、场地收缩、教练下课、冷板凳无限加长。