移動應用為支持各種功能,大多采用了多線程技術。使用單獨的線程執行某些任務,同時不影響界面的刷新,在線程執行過程中,可能需要通知一些信息給界面線程,在線程結束之后,需要告訴界面線程執行的結果,這是較為通用的一種線程執行方式。
在C#中,實現該功能的類是BackgroundWorker,而在android和ios中,并無類似的封裝好的類。通常在開發應用的時候需要考慮可移植性,存在為多種平臺開發相同應用的情況,為簡化不同平臺應用的開發,編程需要考慮相同的邏輯結構。因此在android和ios實現與BackgroundWorker類似的功能和接口。
BackgroundWorker包含的主要屬性和接口說明如下:
主要屬性:
event DoWorkEventHandler DoWork; //線程的主體 event PRogressChangedEventHandler ProgressChanged; //線程運行過程中的消息 event RunWorkerCompletedEventHandler RunWorkerCompleted; //線程結束時的處理
主要函數:
void CancelAsync(); 取消線程的運行 void ReportProgress(int percentProgress, object userState); //報告線程的消息 void RunWorkerAsync(object argument); //開始執行線程
為了方面使用,可以將BackgroundWorker進行封裝如下
    public class StarBackgroundWorker    {        private BackgroundWorker m_worker;        public StarBackgroundWorker()        {            m_worker = new BackgroundWorker();        }        public void CancelAsync()        {            m_worker.CancelAsync();        }        public void RunAsync(DoWorkEventHandler DoWork, object userState, ProgressChangedEventHandler ProgressChanged, RunWorkerCompletedEventHandler RunWorkerCompleted)        {            m_worker.DoWork += DoWork;            m_worker.WorkerSupportsCancellation = true;            m_worker.RunWorkerCompleted += RunWorkerCompleted;            if (ProgressChanged != null)            {                m_worker.ProgressChanged += ProgressChanged;                m_worker.WorkerReportsProgress = true;            }            m_worker.RunWorkerAsync(userState);        }        public void ReportProgress(int percentProgress, object userState)        {            m_worker.ReportProgress(percentProgress, userState);        }    }    使用方法:
StarCoreBackgroundWorker myworker = new StarCoreBackgroundWorker();myworker.RunAsync(    (object sender1, DoWorkEventArgs e1) =>    {        BackgroundWorker worker = sender1 as BackgroundWorker;        //線程的主體    },    null,    (object sender1, ProgressChangedEventArgs e1) =>    {        //--在界面線程中執行,可以刷新界面    },    (object sender1, RunWorkerCompletedEventArgs e1) =>    {        //--在界面線程中處理,線程運行結束后的處理    });2.Android中實現類似BackgroundWorker的功能
Android中使用java編程,通常創建線程使用Thread和Runnable,線程與界面線程通信使用消息的方式,從界面線程中的handler獲取一條消息結構,填充參數,使用sendMessage將消息發送給界面線程。界面線程的Handler獲取消息隊列中的消息進行處理。利用這些方式,可以實現類似c# BackgroundWorker功能
a. 封裝Handler
    由于采用Handler處理所有BackgroundWorker線程中的消息,為了區分不同的線程,需要線程在創建時進行登記。代碼如下:
public class StarUIHander {    static public Handler handler;    static int InvokeTag = 0;    static HashMap<Integer,HandlerCallBack> CallBackList;    public interface HandlerCallBack {        void Invoke(Message msg);    }    static int Register(HandlerCallBack CallBack)    {        int Val = InvokeTag;        CallBackList.put(InvokeTag,CallBack);        InvokeTag ++;        return Val;    }    static void Remove(int Which)    {        CallBackList.remove(Which);    }    static void InitStarUIHander()    {        handler = new android.os.Handler() {            public void handleMessage(Message msg) {                HandlerCallBack CallBack = CallBackList.get(msg.what);                if( CallBack != null )                    CallBack.Invoke(msg);            }        };        CallBackList = new HashMap<Integer,HandlerCallBack>();    }}    在android應用主Activity中,調用InitStarUIHander初始化Handler,對于創建的線程,調用Register注冊消息處理函數,獲取標識,使用該標識發送消息時。
b. 實現BackgroundWorker功能
    在實現BackgroundWorker之前,參照c#的定義,需要實現一些相關的接口。有以下幾個:    CancellationTokenSource, ProgressChangedEventArgs, DoWorkEventArgs,RunWorkerCompletedEventArgs,具體代碼可參考附件
    
public BackgroundWorker(){    //_dispatcher = this.Dispatcher;    cts = new CancellationTokenSource();    HandlerQueue = StarUIHander.Register(new StarUIHander.HandlerCallBack() {        @Override         public void Invoke(Message msg) {            Object[] Para = (Object[])msg.obj;            switch ((int)Para[0]) {            case Message_ReportProgress:                if (ProgressChanged != null ){                    ProgressChanged.Invoke(this,(ProgressChangedEventArgs)Para[1]);                }                break;            case Message_OnRunWorkerCompleted:                if (RunWorkerCompleted != null)                    RunWorkerCompleted.Invoke(this,(RunWorkerCompletedEventArgs)Para[1]);                break;            }        }    });}    報告狀態:
public void ReportProgress(int percentProgress, Object userState){    if (ProgressChanged != null ){        Message message = StarUIHander.handler.obtainMessage();        message.what = HandlerQueue;        message.obj = new Object[]{Message_ReportProgress,new ProgressChangedEventArgs(percentProgress,userState)};        StarUIHander.handler.sendMessage(message);    }}    創建線程執行:
public void RunWorkerAsync(Object userState){    final BackgroundWorker m_worker = this;    if (DoWork != null)    {        IsBusy = true;        try {            final DoWorkEventArgs args = new DoWorkEventArgs(userState);            new Thread(new Runnable(){                @Override                public void run() {                    DoWork.Invoke(m_worker, args);                    IsBusy = false;                    if (RunWorkerCompleted != null) {                        Message message = StarUIHander.handler.obtainMessage();                        message.what = HandlerQueue;                        message.obj = new Object[]{Message_OnRunWorkerCompleted, new RunWorkerCompletedEventArgs(args.Result, null, args.Cancel)};                        StarUIHander.handler.sendMessage(message);                    }                }            }).start();        }        catch (Exception ex) {            IsBusy = false;            if (RunWorkerCompleted != null) {                Message message = StarUIHander.handler.obtainMessage();                message.what = HandlerQueue;                message.obj = new Object[]{Message_OnRunWorkerCompleted, new RunWorkerCompletedEventArgs(false, ex, false)};                StarUIHander.handler.sendMessage(message);            }        }    }}     為了方面使用,將BackgroundWorker進行封裝如下
    public static class StarCoreBackgroundWorker    {        private BackgroundWorker m_worker;        public StarCoreBackgroundWorker()        {            m_worker = new BackgroundWorker();        }        public void CancelAsync()        {            m_worker.CancelAsync();        }        public void RunAsync(DoWorkEventHandler DoWork, Object userState, ProgressChangedEventHandler ProgressChanged, RunWorkerCompletedEventHandler RunWorkerCompleted)        {            m_worker.DoWork = DoWork;            m_worker.WorkerSupportsCancellation = true;            m_worker.RunWorkerCompleted = RunWorkerCompleted;            if (ProgressChanged != null)            {                m_worker.ProgressChanged = ProgressChanged;                m_worker.WorkerReportsProgress = true;            }            m_worker.RunWorkerAsync(userState);        }        public void ReportProgress(int percentProgress, Object userState)        {            m_worker.ReportProgress(percentProgress, userState);        }    }    使用方法:
StarBackgroundWorker myworker = new StarBackgroundWorker();myworker.RunAsync(        new DoWorkEventHandler() {            public void Invoke(Object sender1, DoWorkEventArgs e1) {                BackgroundWorker worker = sender1 as BackgroundWorker;                //線程的主體            }        },        null,        new ProgressChangedEventHandler() {            public void Invoke(Object sender1, ProgressChangedEventArgs e1) {                //--在界面線程中執行,可以刷新界面            }        },        new RunWorkerCompletedEventHandler() {            public void Invoke(Object sender, RunWorkerCompletedEventArgs e)             {                //--在界面線程中處理,線程運行結束后的處理            }       });3. ios中實現類似BackgroundWorker的功能
    ios創建線程可以使用NSThread,在界面線程中運行調用performSelectorOnMainThread函數;也可以使用GCD相關的函數,對多線程進行封裝,可以實現類似c#的BackgroundWorker功能
a. 實現BackgroundWorker功能
    與android類似,在實現BackgroundWorker之前,參照c#的定義,同樣需要實現一些相關的接口。有以下幾個:CancellationTokenSource, ProgressChangedEventArgs, DoWorkEventArgs,RunWorkerCompletedEventArgs,具體代碼可參考附件
    定義接口:
typedef void(^ProgressChangedEventHandler)(id,ProgressChangedEventArgs*);typedef void(^RunWorkerCompletedEventHandler)(id,RunWorkerCompletedEventArgs*);typedef void(^DoWorkEventHandler)(id,DoWorkEventArgs*);    實現BackgroundWorker
    上報狀態:
-(void)ReportProgress:(uint)percentProgress userState:(id)userState{    if (ProgressChanged != nil || ProgressChangedSelector != nil ){        dispatch_async(dispatch_get_main_queue(),^{            @try{                if( ProgressChangedSelector == nil )                    ProgressChanged(self,[ProgressChangedEventArgs initProgressChangedEventArgs:percentProgress UserState:userState]);                else{                    IMP imp = [SelectorController methodForSelector:ProgressChangedSelector];                    void (*func)(id, SEL, id, ProgressChangedEventArgs* ) = (void *)imp;                    func(SelectorController, ProgressChangedSelector, self, [ProgressChangedEventArgs initProgressChangedEventArgs:percentProgress UserState:userState]);                }            }            @catch(NSException* e)            {                            }        });    }}    異步執行-(void)RunWorkerAsync:(id)userState{    if (DoWork != nil || DoWorkSelector != nil)    {        @try {            DoWorkEventArgs* args = [DoWorkEventArgs initDoWorkEventArgs:userState];            dispatch_async(dispatch_get_global_queue(0, 0),^{                if( DoWork != nil )                    DoWork(self,args);                else if(DoWorkSelector != nil ){                    IMP imp = [SelectorController methodForSelector:DoWorkSelector];                    void (*func)(id, SEL, id, DoWorkEventArgs* ) = (void *)imp;                    func(SelectorController, DoWorkSelector, self,args);                }                dispatch_async(dispatch_get_main_queue(),^{                    if (RunWorkerCompleted != nil)                        RunWorkerCompleted(self,[RunWorkerCompletedEventArgs initRunWorkerCompletedEventArgs:args.Result Cancelled:args.Cancel]);                    else if(RunWorkerCompletedSelector != nil){                        IMP imp = [SelectorController methodForSelector:RunWorkerCompletedSelector];                        void (*func)(id, SEL, id, RunWorkerCompletedEventArgs* ) = (void *)imp;                        func(SelectorController, RunWorkerCompletedSelector, self,[RunWorkerCompletedEventArgs initRunWorkerCompletedEventArgs:args.Result Cancelled:args.Cancel]);                    }                });            });        }        @catch(NSException* e)        {            dispatch_async(dispatch_get_main_queue(),^{                if (RunWorkerCompleted != nil)                    RunWorkerCompleted(self,[RunWorkerCompletedEventArgs initRunWorkerCompletedEventArgs:e]);                else if( RunWorkerCompletedSelector != nil ){                    IMP imp = [SelectorController methodForSelector:RunWorkerCompletedSelector];                    void (*func)(id, SEL, id, RunWorkerCompletedEventArgs* ) = (void *)imp;                    func(SelectorController, RunWorkerCompletedSelector, self,[RunWorkerCompletedEventArgs initRunWorkerCompletedEventArgs:e]);                }            });        }    }} 
b. 為了方面使用,將BackgroundWorker進行封裝如下
-(void)RunAsync:(DoWorkEventHandler)DoWork userState:(id)userState ProgressChanged:(ProgressChangedEventHandler)ProgressChanged RunWorkerCompleted:(RunWorkerCompletedEventHandler)RunWorkerCompleted{    m_worker.DoWork = DoWork;    m_worker.RunWorkerCompleted = RunWorkerCompleted;    if (ProgressChanged != nil)    {        m_worker.ProgressChanged = ProgressChanged;    }    [m_worker RunWorkerAsync:userState];}-(void)ReportProgress:(uint)percentProgress userState:(id)userState{    [m_worker ReportProgress:percentProgress userState:userState];}使用方法:StarBackgroundWorker* myworker = [StarBackgroundWorker initStarBackgroundWorker];            [myworker RunAsync:^(id sender1, DoWorkEventArgs *e) {                BackgroundWorker* worker = (BackgroundWorker*)sender1;                            } userState:nil ProgressChanged:^(id sender1, ProgressChangedEventArgs *e) {            } RunWorkerCompleted:^(id sender1, RunWorkerCompletedEventArgs *e) {            }            }];4. 結束語
    如果不考慮可移植性,可以直接使用android,ios,windows中定義的多線程方法開發應用,但由于不同平臺采用的是不同語言,多線程實現接口和方式不同,會影響應用的邏輯結構,增加不同平臺移植的工作量。基于線程執行過程,參考C#中的BackgroundWorker機制,在android和ios實現了類似的多線程機制,采用相同的框架結構,提供類似的接口,可以使多線程在不同平臺具有相同的邏輯結構
    上面的代碼不完整,具體請參考附件
下載附件
新聞熱點
疑難解答