"A Service is an application component that can perform long-running operations in the background and does not provide a user interface."
"This is the preferred technique when your service is merely a background worker for your own application."
public class BoundService extends Service {
public class LocalBinder extends Binder{
public int getA(){
return -1;
};
public void setB(int b){
//---TODO something ---
}
}
@Override
public IBinder onBind(Intent intent) {
return new LocalBinder();
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application ... >
<service
android:name=".BoundService"/>
</application>
</manifest>
public class MainActivity extends AppCompatActivity {
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (BoundService.LocalBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBinder = null;
}
};
//TODO something----
@Override
protected void onStop() {
super.onStop();
unbindService(mServiceConnection);
}
@Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, BoundService.class), mServiceConnection
, Service.BIND_AUTO_CREATE);
}
}
Programming Mobile Services for Android Handheld Systems: Concurrency
"This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don't have to design your service to be thread-safe."
public class SimpleService extends Service {
private Messenger mServiceMessnger;
private HandlerThread mThread;
@Override
public IBinder onBind(Intent intent) {
return mServiceMessnger.getBinder();
}
@Override
public void onCreate() {
super.onCreate();
mThread = new HandlerThread("BackgroundThread");
mThread.start();
Handler backgroundHandler =
new Handler(mThread.getLooper()){
@Override
public void handleMessage(Message msg) {
Message newMessage = Message.obtain();
//TODO something
try {
msg.replyTo.send(newMessage);
} catch (RemoteException e) {
Log.e(TAG,null,e);
}
}
};
mServiceMessnger = new Messenger(backgroundHandler);
}
@Override
public boolean onUnbind(Intent intent) {
mThread.quit();
return super.onUnbind(intent);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application ... >
<service
android:name=".SimpleService" />
//-----OR-----------
<service
android:process=":background"
android:name=".SimpleService" />
</application>
</manifest>
public class MainActivity extends Activity {
private Messenger mServiceMessenger;
private Messenger mClientMessenger = new Messenger(new Handler(){
@Override
public void handleMessage(Message msg) {
//TODO something
}
});
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mServiceMessenger = new Messenger(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mServiceMessenger = null;
}
};
public void onClick(View view){
Message message = Message.obtain();
message.replyTo = mClientMessenger;
message.setData(mBundle); // OR message.obj = mBundle;
try {
mServiceMessenger.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent();
intent.setPackage(getApplicationContext().getPackageName());
intent.setClass(this, SimpleService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
}
}
"Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service."
- Java Primitives (int, long, char, boolean, e.t.c)
- String, CharSequence,List,Map
- Parcelable
ParceExample.aidl
package com.bionic.model;
parcelable ParceExample;
ParceExample.java
import android.os.Parcel;
import android.os.Parcelable;
public final class ParceExample implements Parcelable {
//TODO parcelable implementation
}
- Interface Reference
ParceRefExample.aidl
package com.bionic.model;
import com.bionic.model.ParceExample;
interface ParceRefExample {
void send(in ParceExample obj);
}
- input (in, out, inout)
- return (oneway)
void copyArray(in byte[] source, out byte[] dest);
oneway void copyArray(in byte[] source, out byte[] dest);
package com.bionic.model;
interface IAidlService {
int add(in int value1, in int value2);
oneway void increase(in int value);
}
public class AidlService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new IAidlService.Stub() {
public int add(int value1, int value2) throws RemoteException {
return value1 + value2;
}
public void increase(int value) throws RemoteException {
//TODO something
}
};
}
}
package com.bionic.model;
interface IAidlService {
int add(in int value1, in int value2);
oneway void increase(in int value);
}
public class AidlService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new IAidlService.Stub() {
public int add(int value1, int value2) throws RemoteException {
return value1 + value2;
}
public void increase(int value) throws RemoteException {
//TODO something
}
};
}
}
public class BindingActivity extends Activity {
IAidlService mService ;
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this,
LocalService.class);
bindService(intent, mConnection,
Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
private ServiceConnection mServiceConnection =
new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name,
IBinder service)
{
mService = IAidlService.Stub
.asInterface((IBinder)service);
}
};
//---------------------------------------------------
{
int result = mService.add(2,2);
}
}
public class MainActivity extends Activity {
public void onClickStart(View v) {
PendingIntent pIntent = createPendingResult(REQUEST_CODE, null, 0);
Intent intent = new Intent(this, PiService.class);
intent.putExtra(PARAM_PINTENT, pIntent);
//TODO add extra params to intent
startService(intent);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE){
//TODO results processing
}
}
}
//----------------------------------------------------------------------------------------
public class PiService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
final PendingIntent pIntent = intent.getParcelableExtra(MainActivity.PARAM_PINTENT);
//TODO start new thread
{
public void run(){
pIntent.send(MainActivity.STATUS_START);
// ---- or -----------
Intent resultIntent = new Intent().putExtra(MainActivity.PARAM_RESULT, 9);
pIntent.send(PiService.this, MainActivity.STATUS_FINISH, resultIntent);
stopSelf();
}
}
//------------------------
return super.onStartCommand(intent, flags, startId);
}
}
public class MainActivity extends Activity {
public final static String BROADCAST_ACTION = "com.bionic.broadcast.ACTION";
private BroadcastReceiver mReceiver = BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
//TOD broadcast processing
}
//TODO add subscribe/unsubscribe from broadcast
}
public class BroadcastService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
//TODO start new thread
{
public void run(){
Intent intent = new Intent(MainActivity.BROADCAST_ACTION);
//TODO fill data into intent
sendBroadcast(intent);
stopSelf();
}
}
//------------------------
return super.onStartCommand(intent, flags, startId);
}
}
public class MainActivity extends Activity {
public ResultReceiver mReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new ResultReceiver(new Handler()){
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
//TODO result processing
}
};
Intent intent = new Intent(this, MyIntentService.class);
intent.putExtra(PARAM_RECEIVER, mReceiver);
//TODO fill data into intent
startService(intent);
}
}
//-------------------------------------------------------------------------------------
public class MyIntentService extends IntentService {
@Override
protected void onHandleIntent(Intent arg0) {
final ResultReceiver receiver = arg0.getParcelableExtra(PARAM_RECEIVER);
//TODO request processing
Bundle bundle = new Bundle();
//TODO fill data into bundle
receiver.send(STATUS_RESULT, bundle);
}
}
has advanced features like delivery threads, subscriber priorities, etc.
public class MainActivity extends Activity {
private EventBus mBus = EventBus.getDefault();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBus.register(this);
}
@Override
protected void onDestroy() {
mBus.unregister(this);
super.onDestroy();
}
public void onEvent(Event event){
}
}
//-------------------------------------------------------------------------------------
public class MyIntentService extends IntentService {
private EventBus mBus = EventBus.getDefault();
@Override
protected void onHandleIntent(Intent arg0) {
//TODO result processing
Event event = new Event();
mBus.post(event);
}
}
public class EventBus {
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
//----------------------------------------------
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
//To be continued
}
Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
LocalBroadcastManager.getInstance(this).registerReceiver(
mReceiver,
mIntentFilter);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
rodin.illya@gmail.com
https://ua.linkedin.com/in/illya-rodin-54a37419