Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9236927
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 18, 20262026-06-18T07:25:03+00:00 2026-06-18T07:25:03+00:00

Let’s imagine we have a simple Android application, which connects to a remote service

  • 0

Let’s imagine we have a simple Android application, which connects to a remote service via IPC, schedules a relatively long task, then continues working while awaiting for callback with some results. AIDL interfaces:

IRemoteService.aidl

package com.var.testservice;
import com.var.testservice.IServCallback;

interface IRemoteService {

    void scheduleHeavyTask(IServCallback callback);

}

IRemoteService.aidl

package com.var.testservice;

interface IServCallback {

    void onResult(int result);

}

Code for activity:

package com.var.testclient;

import com.var.testservice.IServCallback;
import com.var.testservice.IRemoteService;

import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;

public class MainActivity extends Activity {

    private static final String TAG = "TestClientActivity"; 

    private IServCallback.Stub servCallbackListener = new IServCallback.Stub(){
        @Override
        public void onResult(int result) throws RemoteException {
            Log.d(TAG, "Got value: " + result);
        }

};

private ServiceConnection servConnection = new ServiceConnection(){

    @Override
    public void onServiceConnected(ComponentName name, IBinder binder) {
        service = IRemoteService.Stub.asInterface(binder);          
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        service = null;         
    }

    };

    private IRemoteService service;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(!bindService(new Intent(IRemoteService.class.getName()), servConnection, Context.BIND_AUTO_CREATE)){
            Log.d(TAG, "Service binding failed");
        } else {
            Log.d(TAG, "Service binding successful");
        }
    }

    @Override
    protected void onDestroy() {
        if(service != null) {
            unbindService(servConnection);
        }
        super.onDestroy();
    }

    public void onButtonClick(View view){
        Log.d(TAG, "Button click");
        if(service != null){
            try {
                service.scheduleHeavyTask(servCallbackListener);
            } catch (RemoteException e) {
                Log.d(TAG, "Oops! Can't schedule task!");
                e.printStackTrace();
            }
        }
    }

}

Code for service:

package com.var.testservice;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;

public class TestService extends Service {

    private static final String TAG = "TestService";

    class TestServiceStub extends IRemoteService.Stub {

        private IServCallback servCallback;
        //These 2 fields will be used a bit later
        private Handler handler;
        private int result;

        //The simpliest implementation. In next snippets I will replace it with
        //other version
        @Override
        public void scheduleHeavyTask(IServCallback callback)
                    throws RemoteException {
            servCallback = callback;
            result = doSomethingLong();
            callback.onResult(result);
        }

        private int doSomethingLong(){
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                return 42;
            }
        }

    }

    @Override
    public IBinder onBind(Intent intent) {
        return new TestServiceStub();
    }

}

This version, while being really dumb (it makes UI thread from application hang for 5 seconds, causing ANR), it successfully executes all calls via IPC, delivering result to activity.
Problems start if I try to put calculations into separate thread:

@Override
public void scheduleHeavyTask(IServCallback callback)
        throws RemoteException {
    servCallback = callback;
    Runnable task = new Runnable(){

        @Override
        public void run() {
            result = doSomethingLong();
            try {
                Log.d(TAG, "Sending result!");
                servCallback.onResult(result);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

    };
    new Thread(task).start();
}

In this case the callback is just not delivered to activity: service successfully calls servCallback.onResult(result);, but nothing is called within activity. No exceptions, no clues, no survivors: perfect invocation murder. I couldn’t find any information about possible cause of such behavior, so I’d be grateful if someone could clarify what happens here. My suggestion’s that there’s some kind of security mechanism, tracking which exact threads were bound, and ignoring “unsafe” calls from other threads (something similar happens when we try to mess with UI elements from non-UI thread), but I can’t be sure.

The most obvious solution is to post callback invocation to the bound thread, so I made this:

@Override
public void scheduleHeavyTask(IServCallback callback)
        throws RemoteException {
    Log.d(TAG, "Schedule request received.");
    servCallback = callback;
    if(Looper.myLooper() == null) {
        Looper.prepare();
    }

    handler = new Handler();
    Runnable task = new Runnable(){

        @Override
        public void run() {
            result = doSomethingLong();
            Log.d(TAG, "Posting result sender");
            handler.post(new Runnable(){

                @Override
                public void run() {
                    try {
                        Log.d(TAG, "Sending result!");
                        servCallback.onResult(result);
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    Looper.myLooper().quit();
                    Log.d(TAG, "Looper stopped");
                }

            });
        }

    };
    new Thread(task).start();
    Looper.loop();
}

Here I faced 2 more problems:

  1. I had to call Looper.loop() to enable processing of callback runnables, but it blocks IPC, so I have the same result as in the beginning – no actual multithreading;
  2. Registering for callback second time (after first cycle finished and returned value) results in exception:

    java.lang.RuntimeException: Handler (android.os.Handler) sending message to a Handler on a dead thread
    at android.os.MessageQueue.enqueueMessage
    at android.os.Handler.sendMessageAtTime
    at android.os.Handler.sendMessageDelayed
    at android.os.Handler.post
    at com.var.testservice.TestService$TestServiceStub$1.run
    at java.lang.Thread.run
    

This lefts me completely puzzled: I make a fresh instance from actual Looper, how can it point to dead thread?

The whole idea of service being able of queueing tasks and making callbacks when they finish doesn’t sound insane to me, so I hope someone more experienced could explain me:

  1. Why can’t I actually make IPC calls from different threads?
  2. What’s wrong with my Handler?
  3. What instruments/architecture should I use to make a clean, proper queue mechanism, so it could call IPC methods on the right thread without constantly calling Looper.loop()/Looper.quit()?

Thank you.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-18T07:25:04+00:00Added an answer on June 18, 2026 at 7:25 am

    I can’t explain why your program isn’t working. But the version involving threads and an asynchronous callback:

    @Override
    public void scheduleHeavyTask(IServCallback callback)
            throws RemoteException {
        servCallback = callback;
        Runnable task = new Runnable(){
    
            @Override
            public void run() {
                result = doSomethingLong();
                try {
                    Log.d(TAG, "Sending result!");
                    servCallback.onResult(result);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
        };
        new Thread(task).start();
    }
    

    should work just fine.

    Here’s how Android arranges threads for AIDL and other types of Binder transaction.

    • If the caller and the callee are in the same process, it becomes a simple method call. So, you should fine that scheduleHeavyTask is called from the very same thread as onButtonClick. Similarly, you should fine that the call to onResult should be a simple method call, from the thread running the task.
    • If the caller and callee are in different processes, Android will run the Binder transactions from a pool of threads within the callee process (they are called Binder #1 etc.) Even here it’s quite clever – so if onButtonClick called scheduleHeavyTask which called back to onResult from the same thread, then onButtonClick would appear directly to call onResult within the caller process.

    There are absolutely no mechanisms to avoid calls from “unsafe” or “unbound” threads – so this simple approach you posted should work. As you say, it’s a common pattern, and I’ve used it lots of times. I’d therefore recommend proceeding with this rather than fiddling with extra loopers and handlers.

    Here are some ideas:

    • Run it in a debugger. Assuming your service and activity are in the same process, you should be able to set breakpoints and see sensible method calls taking place.
    • Even if you can’t, fire up ddms from the command line, or show the Devices and Threads views within Eclipse. This will give you a view of exactly what each thread is doing – you can get a callstack. It’s normally possible to use this even in cases where a full-on debugger would be inconvenient.
    • Do you have the word synchronized anywhere? What could be happening is that onResult wants to go ahead and run, but it’s blocked on some monitor. As soon as it becomes unblocked, it might well run.
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Let's have an example like below: package xliiv.sandbox; import android.app.Activity; import android.os.Bundle; import android.util.Log;
Let's say I have a method in java, which looks up a user in
Let's say I have a main folder in my website named test which contains
Let me frame it this way.. Say I have an application server running on
Let's say I have a Job Scheduler which has 4 consumers A, B, C
Let's say, I have an application that access(read/write) the file system(files inside application), Active
Let's say I have a simple form in the administration of my Rails 2.x
Let's say I have a simple UserControl with no codebehind: <UserControl xmlns= .... x:Class=TrafficLight.LightControl>
Let's say I have 2 windows in my application, and two classes responsible for
Let's say I have a dataset, which can be neatly classified using weka's J48

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.