Can we call IntentService class from a running Service class .
Intent myintentservice = new Intent(this, MyIntentService.class);
startService(myintentservice);
I using above lines of code in service class to start IntentService class. But then I get following error:-
Process: objectdistance.ankeshkjaisansaria.ram.sita.cameratag, PID: 21823
java.lang.NullPointerException: Attempt to invoke virtual method
'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ComponentName.<init>(ComponentName.java:77)
at android.content.Intent.<init>(Intent.java:4161)
**Edited:------------- **
1. Main Activity.Java
OnCreate():-
Intent i = new Intent(this, ServiceA.class);
startService(i);
2. ServiceA.java
public class ServiceA extends Service {
String TAG = "Log";
private static HandlerThread sWorkerThread;
private static Handler sWorkerQueue;
private static DataProviderObserver sDataObserver;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
sWorkerThread = new HandlerThread("ContentObserver");
sWorkerThread.start();
sWorkerQueue = new Handler(sWorkerThread.getLooper());
final ContentResolver r = this.getContentResolver();
if (sDataObserver == null) {
sDataObserver = new DataProviderObserver(getApplicationContext(), sWorkerQueue);
Log.d("CP", " " + android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
r.registerContentObserver(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, sDataObserver);
}
else{Log.d("Error","Error Content Observer Service");}
super.onCreate();
}
public void IntService(){
Intent MyIntentService = new Intent(this, MyIntentService.class);
startService(MyIntentService);
}
#Override
public void onDestroy() {
getContentResolver().unregisterContentObserver(sDataObserver);
super.onDestroy();
}
}
3. DataProviderObserver.Class
public class DataProviderObserver extends ContentObserver {
Context context;
DataProviderObserver(Context context ,Handler h) {
super(h);
this.context = context;
}
#Override
public void onChange(boolean selfChange, Uri uri) {
if (uri.toString().equals("content://media/external/images/media")){
ServiceA obj1 = new ServiceA();
ob1.IntService();
}
}
#Override
public boolean deliverSelfNotifications() {
return false;
}
}
4. MyIntentService.java
public class MyIntentService extends IntentService {
Context ctx;
public MyIntentService() {
super("test-service");
}
#Override
public void onCreate() {
ctx = getBaseContext();
super.onCreate();
}
#Override
public void onHandleIntent(Intent i){
try {
Uri uri;
Cursor cursor;
int column_index_id , column_index_data;
uri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
String order = MediaStore.MediaColumns.DATE_ADDED + " desc";
String[] projection = {MediaStore.MediaColumns._ID , MediaStore.MediaColumns.DATA};
cursor = **CONTEXT_REQUIRED**.getContentResolver().query(uri, projection, null, null, order);
column_index_id = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
column_index_data = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
cursor.close();
}catch (Exception e){
e.printStackTrace();
}
// My Task
}
}
I have answered another question today which has exactly the same mistake.
ServiceA obj1 = new ServiceA();
ob1.IntService();
You are trying to create a new object of a service which is a very very bad practice. You cannot simply create an object of service like this. All Services in Android must go through the Service lifecycle so that they have a valid context attached to them. In this case a valid context is not attached to the obj1 instance. So as a result the line
Intent MyIntentService = new Intent(this, MyIntentService.class);
causes a null pointer as 'this' is null. (Why? Because this refers to the context which has not yet been created as the service is not started using startService(intent))
Btw I don't understand why you are starting the intent service from within the service. you can simply do it from the DataProviderObserver class like this
Intent MyIntentService = new Intent(context, MyIntentService.class);
context.startService(MyIntentService);
since context is present in the class.
Related
In my MainActivity I need to know the state of a boolean type variable to hide or put an icon visible, but this variable is generated in another class called TcpClient which is called several times by the MainActivity, I am trying to use intent to send this variable from the TcpClient class but I have errors.
This is my code of my MainActivity:
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener {
private TcpClient mTcpClient;
public boolean statusWIFI = false;
.
.
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
#Override
protected TcpClient doInBackground(String... message) {
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) { //we create a TCPClient object and
publishProgress(message); //this method calls the onProgressUpdate
}
});
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//arrayList.add("RX: " + values[0]); //in the
arrayList we add the messaged received from server
mDumpTextView.append( values[0] );
mDumpTextView.append( "\n" );
mScrollView.smoothScrollTo( 0, mDumpTextView.getBottom() );
mAdapter.notifyDataSetChanged(); // notify the
adapter that the data set has changed. This means that new message
received
// from server was added to the list
}
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem IconWIFI = menu.findItem(R.id.bt1_wifi);
Intent intent = getIntent();
Bundle bundle = null;
bundle = getIntent().getExtras();
if (bundle !=null) {
statusWIFI = bundle.getBoolean( "mstatusWIFI");
}
if (statusWIFI == true){
IconUsbON.setVisible(true);
}else{
IconUsbON.setVisible(false);
}
return true;
}
This is the code of my TcpClient class:
public class TcpClient {
private Boolean statusWIFIX = false;
.
.
public void stopClient() {
statusWIFIX = false;
Intent intent = new Intent( this, MainActivity.class );
intent.putExtra( "mstatusWIFI", statusWIFIX );
startActivityForResult( intent, 0 );
sendMessage(Constants.CLOSED_CONNECTION+": " + Modelox);
// send message that we are closing the connection
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
Here is the error; someone could tell me how to correct this
I did't see any initialization of mTcpClient, you need to initialize it like:
mTcpClient= TcpClient();
and if your variable is in TcpClient class you can access it via mTcpClient.statusWIFIX
You also need to make statusWIFIX scope to public like this:
public Boolean statusWIFIX = false;
in your TcpClient class.
You can also send data via intent but just for accessing statusWIFIX to start an activity again is not a good approach.
You must have to pass activity context into the Intent constructor. The TCPClient is not seems any activity or service.
I am using the code below in my activity class:
public static Activity list_Addresses_Activity;
And in my onCreate I used from this :
list_Addresses_Activity = this;
But it throws an error stated below:
Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)
I need to use it from static because I will use from this in my Service class.
My CloseActivies.class :
public class CloseActivies {
Activity a;
Activity b;
Activity c;
protected void CLSActivities(Activity ListAddresses, Activity ListOrder, Activity SendReports) {
a = ListAddresses;
b = ListOrder;
c = SendReports;
if (ListAddressesActivity.FlagLiveAddress && a != null) {
Log.e("ADASFSDAGWEG", "X");
a.finish();
ListAddressesActivity.FlagLiveAddress = false;
}
if (ListOrderActivity.FlagLiveOrder && b != null) {
Log.e("ADASFSDAGWEG", "Y");
b.finish();
ListOrderActivity.FlagLiveOrder = false;
}
if (SendReportsActivity.FlagSendReport && c != null) {
Log.e("ADASFSDAGWEG", "Z");
c.finish();
SendReportsActivity.FlagSendReport = false;
}
}
protected void CLSActivities() {
if (ListAddressesActivity.FlagLiveAddress && a != null) {
Log.e("ADASFSDAGWEG", "X");
a.finish();
ListAddressesActivity.FlagLiveAddress = false;
}
if (ListOrderActivity.FlagLiveOrder && b != null) {
Log.e("ADASFSDAGWEG", "Y");
b.finish();
ListOrderActivity.FlagLiveOrder = false;
}
if (SendReportsActivity.FlagSendReport && c != null) {
Log.e("ADASFSDAGWEG", "Z");
c.finish();
SendReportsActivity.FlagSendReport = false;
}
}
}
It will cause a memory leak as your service class is working on a separate thread and passing a static reference to your activity will keep the instance in memory even if the activity is dismissed and not garbage collected, a safer way to do this is passing a reference of your activity as a parameter to your service and storing it in a weakreference something like this
public class MyIntentService extends IntentService {
private final WeakReference<Context> mContextWeakReference;
public MyIntentService() {
super("MyIntentService");
}
public static void startActionFoo(Context context) {
mContextWeakReference = new WeakReference<>(context);
Intent intent = new Intent(context, MyIntentService.class);
context.startService(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
Context context = mContextWeakReference.get();
if(context != null) {
//do your work as since context is not null means
//activity is still present and if activity is dismissed
//context will come null
}
}
}
If you need activity reference for one of its static variable you can pass it in intent extras, or you want to call a static function of activity, a broadcast receiver would be a better choice to do this.
If you are starting service from activity and use some data of activity in that service. You can pass them in intent.
Intent intent = new Intent(this,MyService.class);
intent.putExtra("data", "some_value");
startService(intent);
I want to start an activity through IntentService, but the catch is the activty name or the class name will be passed as parameter to the IntentService.
Following are my code blocks...
public class Runner {
Context context;
public void startActivity() {
Intent intent = new Intent(context, ActivityLauncher.class);
intent.putExtra("caller", "Runner");
//CameraActivity is my activity which i want to start
// I will be giving other activities also in other parts of my code
intent.putExtra("class",CameraActivity.class);
context.startService(intent);
}
}
Now the code for ActivityLauncher Service is as follows.....
public class ActivityLauncher extends IntentService {
public ActivityLauncher(String name) {
super("ActivityLauncher");
}
protected void onHandleIntent(Intent intent) {
try{
Bundle b = intent.getExtras();
Class<?> c = (Class<?>) b.get("class");
Intent mainActivityIntent = new Intent(getBaseContext(), c.getClass());
mainActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String intentType = intent.getExtras().getString("caller");
if(intentType == null)
return;
if(intentType.equals("Runner"))
getApplication().startActivity(mainActivityIntent);
} catch (Exception localException) {
Log.d("TAG", localException.getMessage());
}
}
}
Please tell me how can i improve my code. and how can i get the solution.
I have a service that I'm using to send SOAP Webservice calls. Everything is working perfectly and it never crashes, but I kinda think it should.
My problem is that when I have long running queries (10-50 sec.) onDestroy() is called before my workerthread is done (and I call stopSelfResult). Could it be that System.out.println isn't executed right away/out of sync (cached) in the LogCat window?
The is how a start the service through QueryBase class:
QueryBase someService = new QueryBase(myActivity);
someService.execute(...);
My QueryBase Class
public class QueryBase {
private WeakReference<Activity> currentActivity = null;
private static class ResponseHandler extends Handler {
private QueryBase mQueryBase;
public ResponseHandler(QueryBase vQueryBase) {
mQueryBase = vQueryBase;
};
public void handleMessage(Message message) {
Bundle extras = message.getData();
mQueryBase.handleResult(message.arg1,message.arg2,extras.getInt("FRAMEID"),extras.getString("RESPONSE"));
mQueryBase=null;
};
};
public QueryBase(Activity vActivity) {
currentActivity = new WeakReference<Activity>(vActivity);
}
/***************************************************************************
* Start the service
**************************************************************************/
public boolean execute(Activity vActivity, int cmdID, int frameID, String serverAddress, int requestType, String request) {
// Valid activity
if (vActivity==null) return false;
// Test to see if network is connected
if (!isOnline(vActivity)) return false;
Intent webService = new Intent(vActivity, WebService.class);
final ResponseHandler responseHD = new ResponseHandler(this);
Messenger messenger = new Messenger(responseHD);
webService.putExtra("QUERYRESULT_MESSENGER",messenger);
webService.putExtra("CMDID", cmdID);
webService.putExtra("FRAMEID",frameID);
webService.putExtra("SERVER_ADDRESS",serverAddress);
webService.putExtra("REQUEST_TYPE",requestType);
webService.putExtra("REQUEST",request);
vActivity.startService(webService);
return true;
}
/***************************************************************************
* Is my Android connected?
**************************************************************************/
private Boolean isOnline(Activity vActivity) {
ConnectivityManager connMgr = (ConnectivityManager) vActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) return true;
else return false;
}
/***************************************************************************
* Get current Activity
**************************************************************************/
public Activity getCurrentActivity() {
Activity ac = currentActivity.get();
if (ac!=null) {
if ((ac.isFinishing()) || (ac.activityDestroyed)) {
return null;
};
}
return ac;
};
/***************************************************************************
* XML result from webservice
**************************************************************************/
public void handleResult(int resultCode, int cmdID, int frameID, String response) {
System.out.println("DEFAULT HANDLER: ResultCode: " + resultCode);
};
}
My WebService Class
public class WebService extends Service {
public static final int WS_RT_BLOOSOAP = 0;
public static final int WS_RT_RSS = 1;
public static final int WS_RESULT_OK = 0;
public static final int WS_RESULT_UNABLE_TO_CONNECT = 2;
public static final int WS_RESULT_INVALID_REQUEST = 3;
public static final int WS_RESULT_UNKNOWN_ERROR = 999;
static private SparseBooleanArray workList=null; // Only one job with the same frameID is allowed to run
#Override
public void onCreate() {
System.out.println("#### WebService onCreate");
if (workList==null) workList = new SparseBooleanArray();
}
#Override
public void onDestroy() {
System.out.println("#### WebService onDestroy");
}
/***************************************************************************
* Start working
**************************************************************************/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("WebService Start ID=" + startId);
final int currentID = startId;
final Intent currentIntent = intent;
Runnable workerRunnable = new Runnable() {
public void run() {
System.out.println("WebService Thread Start - ID=" + currentID);
int resultCode;
Bundle responseExtras = new Bundle();
resultCode = serverRequest(currentIntent,responseExtras);
sendResponse(currentIntent,resultCode,responseExtras);
System.out.println("WebService Thread End - ID=" + currentID);
Bundle extras = currentIntent.getExtras();
if (extras != null) {
int frameID = extras.getInt("FRAMEID");
System.out.println(">>>>>>> PUT FALSE " + frameID);
workList.put(frameID, false);
};
stopSelfResult(currentID);
}
};
if (intent!=null) {
Bundle extras = intent.getExtras();
if (extras != null) {
int frameID = extras.getInt("FRAMEID");
Boolean found = workList.get(frameID,false);
if (!found) {
System.out.println(">>>>>>> PUT TRUE FRAMEID=" + frameID);
workList.put(frameID, true);
Thread workerThread = new Thread(workerRunnable);
workerThread.start();
} else {
System.out.println(">>>>>>> Allready running FRAMEID=" + frameID);
}
};
};
return Service.START_STICKY;
};
/***************************************************************************
* No binding
**************************************************************************/
#Override
public IBinder onBind(Intent intent) {
return null;
}
/***************************************************************************
* Send webservice request and return result in responseExtras
**************************************************************************/
private int serverRequest(Intent intent, Bundle responseExtras) {
...
};
/***************************************************************************
* Send response back to service caller using Messenger.send()
**************************************************************************/
private boolean sendResponse(Intent intent, int resultCode, Bundle responseExtras) {
...
};
Your service is stopped if you call stopSelfResult() with the latest startId. So if the service gets started with an intent for startId=1 and another intent with startId=2 and the second is finished before the first, you call stopSelfResult(2) before you finished for startId=1. The service gets destroyed immediately if you call stopSelfResult() with the latest startId and no other intents are pending.
Hold the latest startId. Add all startIds you wish to process in an array (e.g. List<Integer> runningStartIds) and remove them when you've finished processing them. After removing on finishing, compare the current startId with the latest one and do not call stopSelfResult() if runningStartIds is not empty. So you will end up calling stopSelfResult() only for the latest startId, when all intents were processed and no more intents are pending.
Should work, although I haven't posted an example.
.:EDIT:.
Explenation:
The next Intent may come in as fast as you return from onStartCommand() regardless of what you're doing in the background.
.:EDIT:.
Not an Improvement(Improvement:
Thinking about that, in fact you only have to keep the mLastStartId. Just skip calling stopSelfResult() until the finished startId matches mLastStartId.)
Unfortunately, it always can be happen. Actually, android application components' life cycle aren't synchronized w/ any type of worker threads as default.
So, you may need to check the status of Service manually, for example you can have one boolean flag to indicate if a service is working or not. Another handy approach is using IntentService instead of using normal service, it handles worker thread and life-cycle features by itself.
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService ");
}
#Override
protected void onHandleIntent(Intent intent) {
// This callback-method is called inside worker thread,
// so you can do some long-time network job here.
SystemClock.sleep(30000); // 30 seconds
// In this timing the service will be stopped automatically.
}
}
I've looked at a number of other threads with similar titles, and none seem to cover my problem. So, here goes.
I'm using the Google market expansion files (apkx) library and sample code, with a few modifications. This code relies on receiving callbacks from a service which handles background downloading, licence checks etc.
I have a bug where the service doesn't get correctly attached, which results in a softlock. To make this more unhelpful, this bug never happens on some devices, but occurs about two thirds of the time on other devices. I believe it to be independent of Android version, certainly I have two devices running 2.3.4, one of which (a Nexus S) doesn't have the problem, the other (an HTC Evo 3D) does.
To attempt to connect to the service, bindService is called and returns true. OnBind then gets called as expected and returns a sensible value but (when the bug occurs) onServiceConnected doesn't happen (I've waited 20 minutes just in case).
Has anyone else seen anything like this? If not, any guesses for what I might have done to cause such behaviour? If no-one has any thoughts, I'll post some code tomorrow.
EDIT: Here's the relevant code. If I've missed anything, please ask.
Whilst adding this code, I found a minor bug. Fixing it caused the frequency of the problem I'm trying to solve to change from 2 times in 3 to about 1 time in 6 on the phone I'm testing it on; no idea about effects on other phones. This continues to suggest to me a race condition or similar, but I've no idea what with.
OurDownloaderActivity.java (copied and changed from Google sample code)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//Test the licence is up to date
//if (current stored licence has expired)
{
startLicenceCheck();
initializeDownloadUI();
return;
}
...
}
#Override
protected void onResume() {
if (null != mDownloaderClientStub) {
mDownloaderClientStub.connect(this);
}
super.onResume();
}
private void startLicenceCheck()
{
Intent launchIntent = OurDownloaderActivity.this
.getIntent();
Intent intentToLaunchThisActivityFromNotification = new Intent(OurDownloaderActivity
.this, OurDownloaderActivity.this.getClass());
intentToLaunchThisActivityFromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP);
intentToLaunchThisActivityFromNotification.setAction(launchIntent.getAction());
if (launchIntent.getCategories() != null) {
for (String category : launchIntent.getCategories()) {
intentToLaunchThisActivityFromNotification.addCategory(category);
}
}
// Build PendingIntent used to open this activity from Notification
PendingIntent pendingIntent = PendingIntent.getActivity(OurDownloaderActivity.this,
0, intentToLaunchThisActivityFromNotification,
PendingIntent.FLAG_UPDATE_CURRENT);
DownloaderService.startLicenceCheck(this, pendingIntent, OurDownloaderService.class);
}
initializeDownloadUI()
{
mDownloaderClientStub = DownloaderClientMarshaller.CreateStub
(this, OurDownloaderService.class);
//do a load of UI setup
...
}
//This should be called by the Stub's onServiceConnected method
/**
* Critical implementation detail. In onServiceConnected we create the
* remote service and marshaler. This is how we pass the client information
* back to the service so the client can be properly notified of changes. We
* must do this every time we reconnect to the service.
*/
#Override
public void onServiceConnected(Messenger m) {
mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
}
DownloaderService.java (in Google market expansion library but somewhat edited )
//this is the onBind call that happens fine; the value it returns is definitely not null
#Override
public IBinder onBind(Intent paramIntent) {
return this.mServiceMessenger.getBinder();
}
final private IStub mServiceStub = DownloaderServiceMarshaller.CreateStub(this);
final private Messenger mServiceMessenger = mServiceStub.getMessenger();
//MY CODE, derived from Google's code
//I have seen the bug occur with a service started by Google's code too,
//but this code happens more often so is more repeatably related to the problem
public static void startLicenceCheck(Context context, PendingIntent pendingIntent, Class<?> serviceClass)
{
String packageName = serviceClass.getPackage().getName();
String className = serviceClass.getName();
Intent fileIntent = new Intent();
fileIntent.setClassName(packageName, className);
fileIntent.putExtra(EXTRA_LICENCE_EXPIRED, true);
fileIntent.putExtra(EXTRA_PENDING_INTENT, pendingIntent);
context.startService(fileIntent);
}
#Override
protected void onHandleIntent(Intent intent) {
setServiceRunning(true);
try {
final PendingIntent pendingIntent = (PendingIntent) intent
.getParcelableExtra(EXTRA_PENDING_INTENT);
if (null != pendingIntent)
{
mNotification.setClientIntent(pendingIntent);
mPendingIntent = pendingIntent;
} else if (null != mPendingIntent) {
mNotification.setClientIntent(mPendingIntent);
} else {
Log.e(LOG_TAG, "Downloader started in bad state without notification intent.");
return;
}
if(intent.getBooleanExtra(EXTRA_LICENCE_EXPIRED, false))
{
//we are here due to startLicenceCheck
updateExpiredLVL(this);
return;
}
...
}
}
//MY CODE, based on Google's, again
public void updateExpiredLVL(final Context context) {
Context c = context.getApplicationContext();
Handler h = new Handler(c.getMainLooper());
h.post(new LVLExpiredUpdateRunnable(c));
}
private class LVLExpiredUpdateRunnable implements Runnable
{
LVLExpiredUpdateRunnable(Context context) {
mContext = context;
}
final Context mContext;
#Override
public void run() {
setServiceRunning(true);
mNotification.onDownloadStateChanged(IDownloaderClient.STATE_LVL_UPDATING);
String deviceId = getDeviceId(mContext);
final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));
// Construct the LicenseChecker with a Policy.
final LicenseChecker checker = new LicenseChecker(mContext, aep,
getPublicKey() // Your public licensing key.
);
checker.checkAccess(new LicenseCheckerCallback() {
...
});
}
}
DownloaderClientMarshaller.java (in Google market expansion library)
public static IStub CreateStub(IDownloaderClient itf, Class<?> downloaderService) {
return new Stub(itf, downloaderService);
}
and the Stub class from the same file:
private static class Stub implements IStub {
private IDownloaderClient mItf = null;
private Class<?> mDownloaderServiceClass;
private boolean mBound;
private Messenger mServiceMessenger;
private Context mContext;
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ONDOWNLOADPROGRESS:
Bundle bun = msg.getData();
if ( null != mContext ) {
bun.setClassLoader(mContext.getClassLoader());
DownloadProgressInfo dpi = (DownloadProgressInfo) msg.getData()
.getParcelable(PARAM_PROGRESS);
mItf.onDownloadProgress(dpi);
}
break;
case MSG_ONDOWNLOADSTATE_CHANGED:
mItf.onDownloadStateChanged(msg.getData().getInt(PARAM_NEW_STATE));
break;
case MSG_ONSERVICECONNECTED:
mItf.onServiceConnected(
(Messenger) msg.getData().getParcelable(PARAM_MESSENGER));
break;
}
}
});
public Stub(IDownloaderClient itf, Class<?> downloaderService) {
mItf = itf;
mDownloaderServiceClass = downloaderService;
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
//this is the critical call that never happens
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mServiceMessenger = new Messenger(service);
mItf.onServiceConnected(
mServiceMessenger);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mServiceMessenger = null;
mBound = false;
}
};
#Override
public void connect(Context c) {
mContext = c;
Intent bindIntent = new Intent(c, mDownloaderServiceClass);
bindIntent.putExtra(PARAM_MESSENGER, mMessenger);
if ( !c.bindService(bindIntent, mConnection, 0) ) {
if ( Constants.LOGVV ) {
Log.d(Constants.TAG, "Service Unbound");
}
}
}
#Override
public void disconnect(Context c) {
if (mBound) {
c.unbindService(mConnection);
mBound = false;
}
mContext = null;
}
#Override
public Messenger getMessenger() {
return mMessenger;
}
}
DownloaderServiceMarshaller.java (in Google market expansion library, unchanged)
private static class Proxy implements IDownloaderService {
private Messenger mMsg;
private void send(int method, Bundle params) {
Message m = Message.obtain(null, method);
m.setData(params);
try {
mMsg.send(m);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public Proxy(Messenger msg) {
mMsg = msg;
}
#Override
public void requestAbortDownload() {
send(MSG_REQUEST_ABORT_DOWNLOAD, new Bundle());
}
#Override
public void requestPauseDownload() {
send(MSG_REQUEST_PAUSE_DOWNLOAD, new Bundle());
}
#Override
public void setDownloadFlags(int flags) {
Bundle params = new Bundle();
params.putInt(PARAMS_FLAGS, flags);
send(MSG_SET_DOWNLOAD_FLAGS, params);
}
#Override
public void requestContinueDownload() {
send(MSG_REQUEST_CONTINUE_DOWNLOAD, new Bundle());
}
#Override
public void requestDownloadStatus() {
send(MSG_REQUEST_DOWNLOAD_STATE, new Bundle());
}
#Override
public void onClientUpdated(Messenger clientMessenger) {
Bundle bundle = new Bundle(1);
bundle.putParcelable(PARAM_MESSENGER, clientMessenger);
send(MSG_REQUEST_CLIENT_UPDATE, bundle);
}
}
private static class Stub implements IStub {
private IDownloaderService mItf = null;
final Messenger mMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REQUEST_ABORT_DOWNLOAD:
mItf.requestAbortDownload();
break;
case MSG_REQUEST_CONTINUE_DOWNLOAD:
mItf.requestContinueDownload();
break;
case MSG_REQUEST_PAUSE_DOWNLOAD:
mItf.requestPauseDownload();
break;
case MSG_SET_DOWNLOAD_FLAGS:
mItf.setDownloadFlags(msg.getData().getInt(PARAMS_FLAGS));
break;
case MSG_REQUEST_DOWNLOAD_STATE:
mItf.requestDownloadStatus();
break;
case MSG_REQUEST_CLIENT_UPDATE:
mItf.onClientUpdated((Messenger) msg.getData().getParcelable(
PARAM_MESSENGER));
break;
}
}
});
public Stub(IDownloaderService itf) {
mItf = itf;
}
#Override
public Messenger getMessenger() {
return mMessenger;
}
#Override
public void connect(Context c) {
}
#Override
public void disconnect(Context c) {
}
}
/**
* Returns a proxy that will marshall calls to IDownloaderService methods
*
* #param ctx
* #return
*/
public static IDownloaderService CreateProxy(Messenger msg) {
return new Proxy(msg);
}
/**
* Returns a stub object that, when connected, will listen for marshalled
* IDownloaderService methods and translate them into calls to the supplied
* interface.
*
* #param itf An implementation of IDownloaderService that will be called
* when remote method calls are unmarshalled.
* #return
*/
public static IStub CreateStub(IDownloaderService itf) {
return new Stub(itf);
}