Click here to Skip to main content
15,884,537 members
Articles / Programming Languages / Java
Tip/Trick

A Pattern to Simplify Multiple Async Waiting for Android

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
5 Feb 2018CPOL1 min read 10.7K   46   3   4
Provide a multiple-async-waiting operation management pattern for Android

Introduction

Provide a multiple-async-waiting operation management pattern for Android.

Background

Commonly, when we have some IO FileDescriptor (File, Pipe, Socket, etc.) to do the async-operation, we have to create a dedicated thread to handle the async waiting. If some modules/components require the async waiting simultaneously, we may have to create multiple threads, these will cause some resource wasting.

To reduce the resource consumption and simplify the multiple-async-waiting management, we will create a pattern/method to handle the async waiting in a single dedicated thread.

Using the Code

This article provides native(C++) implementation & Java implementation.

Native(C++) Implementation

Prepare the looper for Native Implementation
C++
void *looperThreadCallback(void *data) {
    *(ALooper **) data = ALooper_prepare(0);
    ALooper_pollAll(-1, 0, NULL, NULL);     //this function will return when call ALooper_wake
    return NULL;
}

ALooper *createLooper(const char *threadName) {
    ALooper *looper = NULL;
    pthread_t t;
    pthread_create(&t, NULL, looperThreadCallback, &looper);
    pthread_setname_np(t, threadName);
    pthread_detach(t);  //detach the pthread_t, because we don't care the thread termination
    while (looper == NULL) { usleep(0); }   //simple spin wait, because the looper should be ready quickly
    return looper;
}

void createDefaultLooper() {
    g_defaultWaitIOLooper = createLooper("DefaultNativeIO");
}
Native main Function
C++
void *registerWaitForSingleFD(int fd, int events, ALooper_callbackFunc func, 
                              void *data, bool isLongRunListener) {
    LOGD("registerWaitForSingleFD: fd=%d events=%d", fd, events);
    ALooper *looper = NULL;
    if (isLongRunListener) {
        looper = createLooper("LongRunNativeIO");
    } else {
        pthread_once(&g_defaultWaitIOLooper_once_t, createDefaultLooper);
        looper = g_defaultWaitIOLooper;
    }
    ALooper_addFd(looper, fd, 0, events, func, data);
    return looper;
}

void unregisterWaitForSingleFD(void *hWait, int fd) {
    LOGD("unregisterWaitForSingleFD: fd=%d", fd);
    ALooper_removeFd((ALooper *) hWait, fd);
    if (hWait != g_defaultWaitIOLooper) {   //check whether LongRunListener
        ALooper_wake((ALooper *) hWait);    //notify ALooper_pollAll to return
    }
}

Java Implementation

Prepare the looper for Java Implementation
C++
private static final HandlerThread mHandlerThread = new HandlerThread("DefaultJavaIO") {{
    start();
}};
Java main Function
Java
public static WaitIOThreadPool registerWaitForSingleFD(FileDescriptor fd, int events, 
MessageQueue.OnFileDescriptorEventListener listener, boolean isLongRunListener) {
    final Looper looper;
    if (isLongRunListener) {
        looper = new HandlerThread("LongRunJavaIO") {{
            start();
        }}.getLooper();
    } else {
        looper = mHandlerThread.getLooper();
    }
    looper.getQueue().addOnFileDescriptorEventListener(fd, events, listener);
    return new WaitIOThreadPool(looper, isLongRunListener);
}

public void unregisterWaitForSingleFD(FileDescriptor fd) {
    mLooper.getQueue().removeOnFileDescriptorEventListener(fd);
    if (mIsLongRunListener) {
        mLooper.quitSafely();
    }
}

In this way, we can handle the multiple-async-waiting in a single dedicated thread for multiple modules/components.

Points of Interest

  1. Android has provided the threadpool implementation in Java side, so we can execute the async callback(MessageQueue.OnFileDescriptorEventListener) in threadpool instead of inline execution (using by the demo code). Because the inline executation may cause some latency on IO data handling.
  2. You even can utilize the main looper(in the UI thread) as the waitor, then no additional dedicated thread require

 

History

  • 8th January, 2018: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questioni cant find full source code Pin
lyricc17-Jan-18 15:58
lyricc17-Jan-18 15:58 
AnswerRe: i cant find full source code Pin
Yesy4-Feb-18 23:14
Yesy4-Feb-18 23:14 
QuestionA few things... Pin
Afzaal Ahmad Zeeshan8-Jan-18 4:13
professionalAfzaal Ahmad Zeeshan8-Jan-18 4:13 
GeneralRe: A few things... Pin
David Crow15-Jan-18 10:32
David Crow15-Jan-18 10:32 
Afzaal Ahmad Zeeshan wrote:
Secondly, why not just consider using Kotlin language approach for async/await.
Isn't there more than one way to skin a cat?

Afzaal Ahmad Zeeshan wrote:
You have not mentioned Android NDK, or Java for Android, and since this is primarily focused on Android, I must ask why not Kotlin for await pattern?
Maybe that was not within the scope of the article.

"One man's wage rise is another man's price increase." - Harold Wilson

"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons

"You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles


General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.