Android: Gcm is Getting Hanged due to Thread Notify and Wait - android

In my demo project i am using a GCM for receiving the push message. I need to process the push message i am receiving in a synchronised way.. Once i received my push i need to do some task and send the acknowledgement to my server(the ack. is sent by a Async task).My project is working fine in normal scenario's, but if i switch off my Data Connectivity and if i give 10 push message and then i switch on my Phone's Data connectivity , My GCM is getting Hanged as it receives message as a bunch and after that it is not processing my push. Plz help to solve this problem
MyGCMService.java
public class MyGCMService extends GCMBaseIntentService{
.....
public GCMIntentService() {
...
myThreadClass =new MyThreadClass();
}
#Override
protected void onRegistered(Context context, String registrationId) {
....
}
#Override
protected void onUnregistered(Context context, String registrationId) {
....
}
#Override
protected void onMessage(Context context, Intent intent) {
try{
// System.out.println("*********** 4-3- "+String.valueOf(myThreadClass.getState()).equals("NEW"));
if(String.valueOf(myThreadClass.getState()).equals("NEW"))
myThreadClass.start();
}catch(Exception e){
}
synchronized (myThreadClass) {
...
myThreadClass.wait();
}
}
#Override
protected void onDeletedMessages(Context context, int total) {
...
}
#Override
public void onError(Context context, String errorId) {
....
}
#Override
protected boolean onRecoverableError(Context context, String errorId) {
....
}
public void OnDestroy() {
super.onDestroy();
}
}
MyTreadClass.java
public class MyThreadClass extends Thread {
MyThreadClass myThreadClass;
String LOG_TAG = MyThreadClass.class.getSimpleName();
public void run() {
synchronized (this) {
Looper.prepare();
performAction();
notify();
}
}
public MyThreadClass() {
myThreadClass=this;
}
public void performMDMAction() {
//Doing Some task and Sending Ack. through Async task
}
}
Once this thread Hangs my GCMBaseIntentService, the Override OnMessage() function is not called..
Thanks in Advance

You really shouldn't use low level synchronization methods such as wait and notify. They are very tricky to correctly use.
If you want to perform an asynchroneous task in an Android app, perhaps AsyncTask would be suitable to your needs. If not, consider using the java.util.concurrent package.

Related

Firebase: onDisconnect() in a service

I am making a project in which i have to
configure realtime internet connection status
of one client app even if app is in background.
I Have to display it on
ServerSide that weather specific device is connected to internet or
not
I am using Firebase to perform this scenerio but it's not working.
ConnectionService
public class ConnectionService extends Service implements ConnectivityReciever.ConnectivityRecieverListner {
public static final int notify = 5000;
private Handler mHandler=new Handler();
private Timer mTimer = null;
FirebaseDatabase db;
DatabaseReference dbRef;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
dbRef=FirebaseDatabase.getInstance().getReference(Common.DEVICE_NAME).child("online");
MyApplication.getInstance().setConnectivtyListner(ConnectionService.this);
boolean isConnected=ConnectivityReciever.isConnected();
checkConnection(isConnected);
if(mTimer!=null){
mTimer.cancel();
}else{
mTimer=new Timer();
mTimer.scheduleAtFixedRate(new TimeDisplay(),0,notify);
}
}
private void checkConnection(boolean isConnected) {
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(ConnectionService.this, "Service is destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public void onNetworkConnectionChanged(boolean isConnected) {
if(isConnected){
dbRef.onDisconnect().setValue("true");
Toast.makeText(ConnectionService.this, "online", Toast.LENGTH_SHORT).show();
}
if(!isConnected){
dbRef.onDisconnect().setValue(ServerValue.TIMESTAMP);
Toast.makeText(ConnectionService.this, "offline", Toast.LENGTH_SHORT).show();
}
}
//class TimeDisplay for handling task
class TimeDisplay extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
MyApplication.getInstance().setConnectivtyListner(ConnectionService.this);
boolean isConnected=ConnectivityReciever.isConnected();
checkConnection(isConnected);
// display toast
Toast.makeText(ConnectionService.this, "Service is running", Toast.LENGTH_SHORT).show();
}
});
}
private void checkConnection(boolean isConnected) {
if(isConnected){
dbRef.setValue("true");
Toast.makeText(ConnectionService.this, "online", Toast.LENGTH_SHORT).show();
}
if(!isConnected){
dbRef.child("online").onDisconnect().setValue(ServerValue.TIMESTAMP);
Toast.makeText(ConnectionService.this, "offline", Toast.LENGTH_SHORT).show();
}
}
}
}
Applicaiton
public class MyApplication extends Application {
public static MyApplication mInstance;
DatabaseReference dbRef;
#Override
public void onCreate() {
super.onCreate();
mInstance=this;
Common.DEVICE_NAME = android.os.Build.MODEL;
FirebaseApp.initializeApp(this);
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
public static synchronized MyApplication getInstance(){
return mInstance;
}
public void setConnectivtyListner(ConnectivityReciever.ConnectivityRecieverListner listner){
ConnectivityReciever.connectivityReceiverListener = listner;
}
}
I have tried all of methods but nothing worked.
Help will be arreciated.
Thanks
if you have registered your service with menifest.xml & your returning start_sticky, it should work but there's an alternative way also, you can write an api to ping the server(call it in a service after a specific interval), and save the time stamp with TRUE(if isConnected), so now the timestamp is saved along with boolean value true, let's suppose now the connection is OFF or cell is dead, since no updation will be sent to server, right?
now it comes the magic of reciver/admin app(where you want to show this online status graphically), now write another API that will fetch that saved response with timestamp & also get the current time when this fetching API will be triggered, find the difference b/w these two time stamps & impose a condition here `
(here difference is in seconds cuz we are using timestamps)
if(timeDifference>60)`
{
echo "true";
}
else
echo "false";
in this way you can get real time online/offline status
on reciver app you ca set
if(response.equals("true"))
{
textView.setText("ONLINE")
}
else
{
textView.setText("OFFLINE")
}
further you can read this post answer too
Save Response to Server When Network Connection goes OFF
Have you registered your Service within your Manifest.xml?
And for your service to be "sticky" you should override your onStartCommand to return START_STICKY

Infinite loop or idle code in IntentService class of Android

I'm asking this question because my Java knowledge is really low... I need
need to use this new API 27 USSD feature... Below if What I'm trying to do :
public class MyService extends IntentService {
// BEGIN of MyService Class properties ****
public static boolean jobInProgress = true;
private Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg); // I guess this will be on some message queue somewhere
}
};
TelephonyManager tm;
// END of properties *************************************
// BEGIN of MyService class abstract class methods implementation
class MyCallback extends TelephonyManager.UssdResponseCallback{
Context serviceContext;
MyCallback (Context serviceContext){
this.serviceContext = serviceContext;
}
public void onReceiveUssdResponse (TelephonyManager telephonyManager,
String request,
CharSequence response){
//Here since it's a System callback I guess my this.tm == telephonyManager parameter right ?
Toast.makeText(serviceContext, "Response from network is : " + response, Toast.LENGTH_LONG).show();
MyService.jobInProgress = false;
}
public void onReceiveUssdResponseFailed (TelephonyManager telephonyManager,
String request,
int failureCode){
Toast.makeText(serviceContext, "USSD request failed with code " + failureCode, Toast.LENGTH_LONG).show();
MyService.jobInProgress = false;
}
}
// END of abstract methods implementation******************
//BEGIN of MyService Class methods
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service is created.", Toast.LENGTH_LONG).show();
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service is destroyed", Toast.LENGTH_LONG).show();
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
doJob();
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
}
private void doJob(){
//Get the instance of TelephonyManager
this.tm =(TelephonyManager)getSystemService(this.TELEPHONY_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
//Don't know How to use sendUssdRequest second and thrid arguments. Below is what I have tried with no success
this.tm.sendUssdRequest("#105*2#",new MyCallback(this),myHandler);
}
//END of class methods*****************************
}
The golad I'm trying to achieve is to runn the USSD request and print the result in a Toast. When I launch the service, it says service created as expected, it goes into the doJob() method as expected, but after that, nothing else happens... The app does not even crash... Just as if after enterring doJob() no instructions was written...
Can you help me make this code work ?
The reason its not working is beacuse you are using Handler and infinite loop together.
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it. So when you do following:
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
It will block the worker Thread and also the Handler. As a result nothing happens.
The solution would be to use normal Service and avoid any looping.
Remember from Android O you cannot endlessly run your service in background. This approach will work if your app is in Foreground. Use foreground Service if you want to make it work reliably.
Here is how I solved it following Sagar's answer :
Instead of :
#Override
protected void onHandleIntent(#Nullable Intent intent) {
doJob();
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
}
I did this :
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
doJob();
}
});
t.start();
while(jobInProgress){
//I hang here to not call onDestroy to quickly...
}
}
and my Handler changed to this :
private Handler myHandler = new Handler(Looper.getMainLooper())
public void handleMessage(Message msg) {
super.handleMessage(msg); // I guess this will be on some message queue somewhere
}
};

Proper way of using a Service with a BroadcastReceiver & LocalBroadcastManager

I'm not sure if my current approach is the proper way to use a Service: I would like to listen to a LocalBroadcastManager in the background (no Activity involved) and query some WebServices upon receiving an Intent. Could you please have a look at my code below and tell me if this is "good" or "bad" in regards of a robust code design? Of course I'd like to reduce the device resource utilisation to a minimum.
Originally, I had an IntentService in my mind but I didn't figure out how to start it from a BroadcastReceiver (you can't register a BroadcastReceiver in the manifest if it just listens to LocalBroadcasts).
public class WebRequestService extends Service {
#Override
public void onCreate() {
BroadcastReceiver mLocalMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
new getCurrentValues().execute();
}
};
IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
LocalBroadcastManager.getInstance(this).registerReceiver(mLocalMessageReceiver, messageFilter);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onDestroy() {}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private class getCurrentValues extends AsyncTask<Void, Void, ResultDTO> {
#Override
protected ResultDTO doInBackground(Void... params) {
// do some magic
return resultDTO;
}
protected void onPostExecute(ResultDTO result) {
if (result != null) {
Intent messageIntent = new Intent();
messageIntent.setAction("currentValuesUpdated");
messageIntent.putExtra("result", result);
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
}
}
} }
Thank you very much

Call Asynctask when a push notification appears

My requirement is when a push notification comes in my device, I need to call an Asynctask. The app can be running in background. I shouldn't click the notification, instead when it comes I need to call Asynctask. Is that possible?
In your GCMIntentService just override onMessage(..) method this method called when push notification is comming in device.
#Override
protected void onMessage(Context context, Intent intent) {
mContext = context;
final String message = intent.getStringExtra("message");
Log.e(TAG, "GCM Received message : "+message);
AsyncTask<Void, Void, Void> DatabaseOperationTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// do your Database Operation here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
};
DatabaseOperationTask.execute();
}
Yes it is possible
you have GCMIntentService which have the method
#Override
protected void onMessage(Context context, Intent intent)
{
}
this method receives message and generate notification you can execute your async task in this method if you need any context the service has its own context

Sticky Service Management

I've got a Sticky Service (returns START_STICKY from onStartCommand) which executes some code in an AsyncTask, but I'm having some problems with how and when to start, bind, stop, unbind. I only want the service around whilst the parent activity is alive, I don't want it hanging around in the background when the app has been closed, but I need the service to survive an orientation change. I currently don't need the service to be active for the entire duration of the activity being active, so I call stopSelf() after the main work is done in my AsyncTask in the Service and then start the Service again when needed. Sometimes I'll need to interrupt the work the service is doing, cancel the AsyncTask and start again with different data. The problem is that no matter what I do - I can't seem to get it solid throughout all the different possible scenarios. Can anyone have a look through and tell me what I'm doing wrong?
My Service is :
public class ChordCalculatorService extends Service {
private final IBinder mBinder = new LocalBinder();
private AsyncTask<SearchData, SearchStatusData, List<Item>> currentTask;
#Override
public void onCreate() {}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* 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 {
public ChordCalculatorService getService() {
return ChordCalculatorService.this;
}
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public SearchData getSearchData() {
return searchData;
}
public void startWork() {
if (currentTask != null && currentTask.getStatus() == Status.RUNNING) {
currentTask.cancel(true);
}
if(searchData != null) {
Worker task = new Worker();
currentTask = task.execute(new SearchData[] { searchData });
} else {
Message msg = handler.obtainMessage(ERROR, "No search data set");
handler.sendMessage(msg);
}
}
class Worker extends AsyncTask<SearchData, SearchStatusData, List<Item>> {
// ... code ...
#Override
protected void onPostExecute(List<Item> result) {
Message msg = handler.obtainMessage(COMPLETE, new StatusData(Status.STATUS_FINISHED, result));
handler.sendMessage(msg);
stopSelf();
}
}
}
Currently I have the Service being started when my custom View is created:
public class MyCustomView extends BasicFretBoardView {
private ServiceConnection conn;
private MyService myService;
private boolean isServiceStarted;
private boolean isServiceBound;
public MyCustomView(Context context, AttributeSet attr) {
super(context, attr);
startService();
}
public void startService() {
Intent serviceIntent = new Intent(getContext(), MyService.class);
conn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((LocalBinder) service).getService();
myService.registerHandler(serviceHandler);
}
#Override
public void onServiceDisconnected(ComponentName name) {
myService = null;
}
};
// Explicitly start the service. Don't use BIND_AUTO_CREATE, since it
// causes an implicit service stop when the last binder is removed.
getContext().startService(serviceIntent);
getContext().bindService(serviceIntent, conn, 0);
isServiceStarted = true;
isServiceBound = true;
}
public void stopService() {
if (isServiceStarted) {
Intent serviceIntent = new Intent(getContext(), MyService.class);
getContext().stopService(serviceIntent);
isServiceStarted = false;
}
unBindService();
}
public void unBindService() {
if(isServiceBound) {
getContext().unbindService(conn);
isServiceBound = false;
}
}
// gets called based on some user interaction
private void startServiceWork() {
if(!isServiceStarted) {
startService();
} else {
myService.cancelCalcalation();
}
myService.setData(data);
myService.startWork();
}
}
and stopping the service is handled in the Activity:
public class CustomChordActivity extends Activity {
// ... code ...
#Override
public void onBackPressed() {
super.onBackPressed();
}
#Override
protected void onPause() {
if(isFinishing()) {
chordsView.stopService();
}
super.onPause();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onDestroy() {
chordsView.unBindService();
super.onDestroy();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
}
}
It seems that you want your task to run on demand, maybe an IntentService would be a more suitable option. When you need work to be done, (startServiceWork()), you just start the service and that kicks off your AsyncTask. The service will then finish after the task has finished.
Now, regarding orientation changes, you would have to implement a Broadcast Receiver whose intent filter is "android.intent.action.CONFIGURATION_CHANGED". (I assume that you want the service to do work when the orientation changes) Place the Broadcast Receiver, within your activity/main ui thread. This will in effect make the hosting process of your Broadcast Receiver to be the main application process making it safer to start the service from within the Broadcast Receiver.

Categories

Resources