Note that there are some explanatory texts on larger screens.

plurals
  1. PORevised: Would like to move class LocalBinder (extends Binder implements ILocalService) from within LocalService (extends Service) to LocalBinder.java
    primarykey
    data
    text
    <p>My <strong>LocalService.java</strong> contains a class <code>LocalBinder</code> that defines the methods that are declared in <strong>ILocalService.java</strong> whose definitions clutter up my <strong>LocalService.java</strong>. I would like to move it to its own file <strong>LocalBinder.java</strong>. Here's my <code>LocalBinder</code>:</p> <pre><code>public class LocalBinder extends Binder implements ILocalService { @Override public LocalService getService() { return LocalService.this; } @Override public int getStatusCode() { return statusCode; } @Override public void startRcvThread(Handler handler) { Thread thread = passHandlerToThread(handler); thread.start(); } } </code></pre> <p>I've tried a number of times and failed. Am I just better off leaving <code>LocalBinder</code> in <code>LocalService</code>?</p> <p>Below is all five of my source code files marked off by header comments. Please have a look at the title of my question. It explains what I want to do. I want to unclutter my LocalService.java by removing "public class LocalBinder" from LocalService.java and put it in its own file: LocalBinder.java. Any help is greatly appreciated. @Commonsware has already provided significant help but it's a bit much for me to comprehend.</p> <pre><code>/************************************************************************************************** * Filename: Controller.java * Project name: Local Service Sample * Application name: Local Service * Description: This file contains the primary activity for this application **************************************************************************************************/ package com.marie.localservicesample; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; /* * Example of explicitly starting and stopping the local service. * This demonstrates the implementation of a service that runs in the same * process as the rest of the application, which is explicitly started and stopped * as desired. */ //public static class Controller extends Activity { public class Controller extends Activity { // Message types sent from the BluetoothReadService Handler public static final int MESSAGE_SONG = 1; public static final int MESSAGE_NOTHING = 2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.local_service_controller); // Watch for button clicks. Button button = (Button)findViewById(R.id.start); button.setOnClickListener(mStartListener); button = (Button)findViewById(R.id.stop); button.setOnClickListener(mStopListener); } private OnClickListener mStartListener = new OnClickListener() { public void onClick(View v) { // Make sure the service is started. It will continue running // until someone calls stopService(). The Intent we use to find // the service explicitly specifies our service component, because // we want it running in our own process and don't want other // applications to replace it. //startService(new Intent(Controller.this, LocalService.class)); Intent startSvc = new Intent(Controller.this, LocalService.class); startSvc.putExtra(LocalService.EXTRA_MESSENGER, new Messenger(ctrlHandler)); startSvc.putExtra(LocalService.EXTRA_SONG, 7); startService(startSvc); Intent binding = new Intent(Controller.this, Binding.class); startActivity(binding); } }; private OnClickListener mStopListener = new OnClickListener() { public void onClick(View v) { // Cancel a previous call to startService(). Note that the // service will not actually stop at this point if there are // still bound clients. stopService(new Intent(Controller.this, LocalService.class)); } }; /* * Here's a way to send a message to a handler - haven't tried it yet: * Give the new state to the Handler so the UI Activity can update * mHandler.obtainMessage(BlueSentry.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); * But for now let's msg.what to our handler */ private Handler ctrlHandler = new Handler() { @Override public void handleMessage(Message msg) { switch(msg.what){ case MESSAGE_SONG: String songObj = (String) msg.obj; int songArg1 = msg.arg1; Log.i("ctrlHandler", "MESSAGE_SONG: " + songObj + " " + songArg1); break; case MESSAGE_NOTHING: String nothingObj = (String) msg.obj; int nothingArg1 = msg.arg1; Log.i("ctrlHandler", "MESSAGE_NOTHING: " + nothingObj + " " + nothingArg1); break; default: break; } } }; } /************************************************************************************************** * Filename: LocalService.java * Project name: Local Service Sample * Application name: Local Service * Description: This file contains a local service **************************************************************************************************/ package com.marie.localservicesample; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.widget.Toast; public class LocalService extends Service { private NotificationManager mNM; // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. //private int NOTIFICATION = R.string.local_service_started; private int NOTIFICATION = R.string.local_service_started; private int statusCode = 99; private int emptyMsg = 549; // This is the object that receives interactions from clients. See // RemoteService for a more complete example. private final IBinder mBinder = new LocalBinder(); @Override public IBinder onBind(Intent intent) { return mBinder; } /** * Class for clients to access. Because we know this service always * runs in the same process as its clients, we don't need to deal with * IPC. */ public class LocalBinder extends Binder implements ILocalService { @Override public LocalService getService() { return LocalService.this; } @Override public int getStatusCode() { return statusCode; } @Override public void startRcvThread(Handler handler) { Thread thread = passHandlerToThread(handler); thread.start(); } } public static final String EXTRA_MESSENGER = "com.marie.localservicesample.EXTRA_MESSENGER"; private Messenger messenger; public static final String EXTRA_SONG = "com.marie.localservicesample.EXTRA_SONG"; private int song; @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting. We put an icon in the status bar. showNotification(); /* Move this stuff to afterStartCommand() Thread thr = new Thread(null, new ServiceWorker(), "LocalService"); thr.start(); */ } // Call this at the end of onStartCommand() public void afterStartCommand() { Thread thr = new Thread(null, new ServiceWorker(), "LocalService"); thr.start(); } /* * see http://developer.android.com/reference/java/lang/Thread.html */ class threadClass extends Thread { private Handler mHandler; private Message mMsg; // constructor public threadClass(Handler handler, Message msg) { // do something like save the Handler reference mHandler = handler; mMsg = msg; } @Override public void run() { // do some background processing, call the Handler? mHandler.sendMessage(mMsg); } } public Thread passHandlerToThread(Handler handler) { handler.sendEmptyMessage(emptyMsg); Message msg = Message.obtain(); msg.what = emptyMsg; Thread thread = new threadClass(handler, msg); return thread; } /* * This is the ServiceWorker thread that passes messages to the handler defined in * the Controller activity. */ class ServiceWorker implements Runnable { public void run() { // do background processing here... something simple while (messenger == null) { try { throw new Exception(); } catch (Exception e) { e.printStackTrace(); } } // send a message to the handler try { Message msg = Message.obtain(); msg.what = Controller.MESSAGE_SONG; msg.obj = "Song"; msg.arg1 = song; messenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } try { Message msg = Message.obtain(); msg.what = Controller.MESSAGE_NOTHING; msg.obj = "Nothing"; msg.arg1 = 0; messenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } catch (NullPointerException e) { e.printStackTrace(); } // stop the service when done... // LocalService.this.stopSelf(); // Or use the unbindBtn in the MainActivity class. } } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("LocalService", "Received start id " + startId + ": " + intent); Bundle extras = intent.getExtras(); messenger = (Messenger)extras.get(EXTRA_MESSENGER); try { song = (Integer) extras.get(EXTRA_SONG); } catch (NullPointerException e) { e.printStackTrace(); song = 0; } afterStartCommand(); // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY; } @Override public void onDestroy() { // Cancel the persistent notification. mNM.cancel(NOTIFICATION); // Tell the user we stopped. Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show(); } /** * Show a notification while this service is running. */ private void showNotification() { // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.local_service_started); // Set the icon, scrolling text and timestamp Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis()); // The PendingIntent to launch our activity if the user selects this notification //PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LocalServiceActivities.Controller.class), 0); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent); // Send the notification. mNM.notify(NOTIFICATION, notification); } } /************************************************************************************************** * Filename: Binding.java * Project name: Local Service Sample * Application name: Local Service * Description: This file contains the binding for this application **************************************************************************************************/ package com.marie.localservicesample; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; /* * Example of binding and unbinding to the local service. * This demonstrates the implementation of a service which the client will * bind to, receiving an object through which it can communicate with the service. */ public class Binding extends Activity { private boolean mIsBound; private ILocalService mBoundService = null; private LocalService mBoundService1; private LocalService mBoundService2; private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. mBoundService1 = ((LocalService.LocalBinder)service).getService(); ILocalService localSvc = (ILocalService)service; mBoundService2 = localSvc.getService(); if (mBoundService1 == mBoundService2) { Log.d("mBoundeService 1 and 2 ", "are equal"); mBoundService = (ILocalService) service; } int statusCode = localSvc.getStatusCode(); Log.d("Binding.java","called onServiceConnected. statusCode: " + statusCode); Toast.makeText(Binding.this, R.string.local_service_connected, Toast.LENGTH_SHORT).show(); } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. mBoundService1 = null; mBoundService2 = null; Log.d("Binding", "called onServiceDisconnected"); Toast.makeText(Binding.this, R.string.local_service_disconnected, Toast.LENGTH_SHORT).show(); } }; void doBindService() { // Establish a connection with the service. We use an explicit // class name because we want a specific service implementation that // we know will be running in our own process (and thus won't be // supporting component replacement by other applications). bindService(new Intent(Binding.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } void doUnbindService() { if (mIsBound) { LocalService service = mBoundService.getService(); if (service != null) Log.d("doUnbindService", "service: " + service); int statusCode = mBoundService.getStatusCode(); if (statusCode != 0) Log.d("doUnbindService", "statusCode: " + statusCode); // Detach our existing connection. unbindService(mConnection); mIsBound = false; } } @Override protected void onDestroy() { super.onDestroy(); doUnbindService(); } private OnClickListener mBindListener = new OnClickListener() { public void onClick(View v) { doBindService(); Intent rcvMsg = new Intent(Binding.this, RcvMessages.class); startActivity(rcvMsg); } }; private OnClickListener mUnbindListener = new OnClickListener() { public void onClick(View v) { doUnbindService(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.local_service_binding); // Watch for button clicks. Button button = (Button)findViewById(R.id.bind); button.setOnClickListener(mBindListener); button = (Button)findViewById(R.id.unbind); button.setOnClickListener(mUnbindListener); } } /************************************************************************************************** * Filename: RcvMessages.java * Project name: Local Service Sample * Application name: Local Service * Description: This file contains stub code that displays a test message in an EditText. **************************************************************************************************/ package com.marie.localservicesample; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.text.InputType; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; /* * Class: RcvMessages * Purpose: RcvMessages is stub code that I want to extend in some way to receive messages from * the background Service. */ public class RcvMessages extends Activity { //private LocalService mBoundService; private boolean mIsBound; private ILocalService mBoundService; //public static final String EXTRA_SONG = "com.marie.mainactivity.EXTRA_SONG"; EditText myText; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //mBoundService = ((LocalService.LocalBinder)service).getService(); mBoundService = (ILocalService)service; ILocalService localSvc = (ILocalService)service; int statusCode = localSvc.getStatusCode(); Log.d("RcvMessages.java","called onServiceConnected. statusCode: " + statusCode); //myText.setText("statusCode: " + statusCode); } @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } }; void doBindService() { // Establish a connection with the service. We use an explicit // class name because we want a specific service implementation that // we know will be running in our own process (and thus won't be // supporting component replacement by other applications). bindService(new Intent(RcvMessages.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } void doUnbindService() { if (mIsBound) { // Detach our existing connection. unbindService(mConnection); mIsBound = false; } } @Override protected void onDestroy() { super.onDestroy(); doUnbindService(); } /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.messages); myText = (EditText)findViewById(R.id.my_text); myText.setSingleLine(); myText.setInputType(InputType.TYPE_NULL); // Display a simple test message for now. // myText.setText("RcvMessages here"); Button button = (Button)findViewById(R.id.display); button.setOnClickListener(mDisplayListener); // I'm expecting this to call mConnection()'s onServiceConnected // bindService(new Intent(RcvMessages.this, LocalService.class), mConnection, Context.BIND_AUTO_CREATE); // IBinder binder = mBoundService.onBind(new Intent(RcvMessages.this, LocalService.class)); doBindService(); } private OnClickListener mDisplayListener = new OnClickListener() { public void onClick(View v) { // Make sure the service is started. It will continue running // until someone calls stopService(). The Intent we use to find // the service explicitly specifies our service component, because // we want it running in our own process and don't want other // applications to replace it. //startService(new Intent(Controller.this, LocalService.class)); mBoundService.startRcvThread(rcvHandler); } }; /* @Override public void onStart(){ super.onStart(); Bundle extras = getIntent().getExtras(); int song = (Integer) extras.get(EXTRA_SONG); //myText.setText("song " + song); // Start the background Service for sending canned messages to the handler as a test. Log.d("RcvMessages", "starting service from rcvmessages"); Intent localSvc = new Intent(RcvMessages.this, LocalService.class); localSvc.putExtra(LocalService.EXTRA_MESSENGER, new Messenger(handler)); localSvc.putExtra(EXTRA_SONG, song); startService(localSvc); } */ /* * This is a handler to be passed to the local Service. */ private Handler rcvHandler = new Handler() { @Override public void handleMessage(Message msg) { int what = msg.what; Log.i("rcvHandler", "rcvWhat: " + what); myText.setText("rcvWhat: " + what); } }; } /************************************************************************************************** * Filename: ILocalService.java * Project name: Local Service Sample * Application name: Local Service * Description: This file contains an example interface for LocalService **************************************************************************************************/ package com.marie.localservicesample; import android.os.Handler; public interface ILocalService { public LocalService getService(); public int getStatusCode(); public void startRcvThread(Handler handler); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload