strange behaviour asynctask - android

I've got a class called Download which extends the AsyncTask.
The OnPreExecute method does the following :
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
this.dialog.setTitle("Check updates...");
this.dialog.show();
}
The dialog listed is instantied in the constructor of the class and has the following charateristics:
dialog = new ProgressDialog(activity);
dialog.setCancelable(false);
In the doInBackground method I'll do a lot of network operations and I'll call the progress update method every time I'm able to download an image from a desired url :
protected void onProgressUpdate(String... values)
// TODO Auto-generated method stub
super.onProgressUpdate(values);
//call the onprogress update
publishProgress("1000");
//do a lot of stuff with the network
}
In the onprogressupdate I'll dismiss the first dialog created and I'll show another one:
protected void onProgressUpdate(String... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
if(values[0].equals("1000")){
dialog.dismiss();
progress_brand.show();
progress_brand.setProgress(progress_brand.getProgress()+1);
if(progress_brand.getProgress() == progress_brand.getMax()){
progress_brand.dismiss();
}
}
}
So basically : at the start of the asynctask I'm showing a dialog with a title "check updates" ... then I'll search for those updates in the doinbackground method and if I'll find some, I'll use the publish progress to dismiss the "old dialog" and create a new one with the ProgressDialog.STYLE_HORIZONTAL. This last dialog is updated everytime I'll download something from the net.
So here's the problem. If I'll run the application with eclipse and then during a download I'll pause the application everything works fine. If I re-enter the application in a second time I can see that the download continues perfectly and I can see the second progress bar continuing to update itself as expected.
If however I make a signed apk --> install the application through that apk --> start the app --> put it on pause during a download -->re-enter the app, then the first dialog is showed again and the download can't proceed properly.
I've seen from the logcat that if I'll run the app from eclipse the onpreexecute method is called only once, even if I'll exit and re-enter in the app.
However if I'll install the app through the apk the onpreexecute method is called everytime I'll exit and then re-start the app.
Why is that happening? I've tried to clean the project and other basic operations to see if the problem was the creation of that apk, but with no results.

no, you do not use ProgressDialog in your AnyTask
try this (for example)
public class Updated extends Activity {
/**
* ProgressDialog which is shown
*/
private ProgressDialog progessDialog_g;
private boolean downloadUses = false;
/**
* Instance of the BroadcastReceiver
*/
private BroadcastReceiver receiver_g;
private IntentFilter iFilter;
protected ServiceConnection mServerConn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
}
public void onServiceDisconnected(ComponentName name) {
}
};
private Intent sI;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.progress);
progessDialog_g = new ProgressDialog(this);
// Reads and sets the settings for the ProgressDialog
// Create the IntentFilter for the different broadcast messages
iFilter = new IntentFilter(
ProgressService.PROGRESS_DIALOG_BROADCAST_FINISH);
// Creates the BroadcastReceiver
receiver_g = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (ProgressService.PROGRESS_DIALOG_BROADCAST_FINISH
.equals(intent.getAction())) {
// Finishs the ProgressDialog
progessDialog_g.cancel();
Finish();
}
}
};
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onResume() {
sI = new Intent(this, ProgressService.class);
this.bindService(sI, mServerConn, Context.BIND_AUTO_CREATE);
this.startService(sI);
// Registers the BroadcastReceiver
registerReceiver(receiver_g, iFilter);
if (downloadUses) {
downloadUses = false;
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
progessDialog_g.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progessDialog_g.setMessage("you messege");
progessDialog_g.show();
new DownloadJSONTask(this, sI)
.execute(Initialize.server_url+"/changes/update/1");
}
super.onResume();
}
#Override
protected void onPause() {
this.stopService(new Intent(this, ProgressService.class));
this.unbindService(mServerConn);
unregisterReceiver(receiver_g);
super.onPause();
}
private void Finish() {
Intent in = new Intent(this, RegionsActivity.class);
startActivity(in);
downloadUses = true;
}
}
}
and
public class ProgressService extends IntentService {
public static final String PROGRESS_DIALOG_BROADCAST_FINISH = "Dialog.Progress.MyKey.Finish";
public ProgressService() {
super("ExampleProgressService");
}
/**
* Send the finish message.
*/
private void closeProgressActivity() {
Intent intent = new Intent(PROGRESS_DIALOG_BROADCAST_FINISH);
sendBroadcast(intent);
}
#Override
protected void onHandleIntent(Intent intent) {
// extractVariablesFromIntentAndPrepare(intent);
String action = intent.getStringExtra("Action");
if ("0".equals(action)) {
closeProgressActivity();
}
}
}
and in you AnyTask
sI.putExtra("Action", "0");
context.startService(sI);
and in you manifest
<service android:name=".Intent.ProgressService" />

Related

android, how to pop a dialog from some non ui module

How to open a dialog when from some non ui module when there might be different activity in display?
Let's say there could be multiple activities stacked, Activity_A, Activity_B, Activity_C. The common service module may running on non ui thread and running into case need to popup a dialog.
It could be done by passing the handler from all active activities to the module and post message to let the activity to pop dialog.
But that need some management in terms of passing the handler and determine who is on top of the view.
Is there a better way?
You can show dailog from non-ui thread using BroadcastReceiver
Understand Flow:
public class Sample extends Activity {
BroadcastReceiver updateUIReciver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
updateUIReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//UI update here
ShowFailedDailog(null, getString(R.string.mms_sending_service_failed_txt));
}
};
IntentFilter filter = new IntentFilter();
filter.addAction("update.from.nonui");
registerReceiver(updateUIReciver, filter);
}
void ShowFailedDailog(String title, String message) {
final Dialog dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.import_backup_popup);
TextView Save = (TextView) dialog.findViewById(R.id.tOk);
Save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
TextView cancel = (TextView) dialog.findViewById(R.id.tCancel);
cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
}
NON UI:
public class NonUiSerive extends Service {
Context context;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
// ..... your tasks
if (SomeFlagUpdateTrue) {
Intent local = new Intent();
local.setAction("mms.seding.failed");
context.sendBroadcast(local);
}
}
this.stopSelf();
return 0;
}
}
Similarly register receiver all your three class it will update in every activity not restricted to one.
After try out I think the simplest is to use application context to open a activity for dialog. This way it would not care who's the current activity on top.
Intent dialogIntent = new Intent(applicationCotext, DialogActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
applicationCotext.startActivity(dialogIntent);

Android Studio: White screen on app run

I am developing an application in which i am getting white screen before splash screen when ever i run the app.
On splash screen i created database in background also i am having the push notification registration code. For push notification registration i refer this link. So my code of splash screen code is as follows:
public class SplashScreenActivity extends AppCompatActivity {
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private BroadcastReceiver mRegistrationBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
mRegistrationBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean sentToken = sharedPreferences.getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false);
if (sentToken) {
// TODO token sent to server
} else {
// TODO show error that token not sent to server
}
}
};
if (checkPlayServices()) {
// Start IntentService to register this application with GCM.
Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);
}
InitializeScreen();
}
private boolean checkPlayServices() {
GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (apiAvailability.isUserResolvableError(resultCode)) {
apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Log.i("Splash screen activity", "This device is not supported.");
finish();
}
return false;
}
return true;
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE));
}
private void InitializeScreen() {
new LoadDataBase(SplashScreenActivity.this).execute(SplashScreenActivity.this);
}
private class LoadDataBase extends AsyncTask<Context, Void, Void> {
Context context;
public LoadDataBase(Context context){
this.context = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Context... arg0) {
// Create data base from assets folder.
DatabaseHelper databaseHelper = new DatabaseHelper(arg0[0]);
try {
databaseHelper.createDataBase();
} catch (IOException e) {
e.printStackTrace();
}
// Closing the Data base.
databaseHelper.close();
return null;
}
#Override
protected void onPostExecute(Void result) {
pauseSplashScreen(context);
}
}
public void pauseSplashScreen(final Context context) {
// New Thread call.
new Thread() {
// Running Thread.
public void run() {
int count = 0;
while (count < 5) {
try {
Thread.sleep(1000);
} catch (Throwable e) {
e.printStackTrace();
}
count++;
}
Intent intent = new Intent(context, Activity2.class);
startActivity(intent);
finish();
}
}.start();
}
}
The issue is : I am getting white screen at app start before splash screen and may be that is due to push notification registration given in above link.
What should i do to avoid that white screen. Please guide me.
You are using a private inner class to create the database. And from there you call pauseSplashScreen(context). That then starts a new thread? Why?
I recommend giving the async task it's own class with a interface to give a signal back to your calling activity.
if you use
Intent intent = new Intent(context, Activity2.class);
startActivity(intent);
You don't have to call finish(), that call is better used to finish the current activity and get back to the previous one. (I get you use a thread to not block the rest of you app running, is it not better to let that thread get back to you, and then move to the next Activity?)
So, to answer your question, my guess is that the startup of your Activity takes some time, and what you see is a blanc layout loaded.
It's just because you are using the debug version, when you change to the release version, it will be gone don't wry about it!

Android sending messages between fragment and service

I have a fragment with a button. When clicked it tells a service to start polling sensors and then insert the sensor data into a database on a background thread. When the button is pushed again, the service will stop. When the Stop button is pushed, there may still be tasks in the executor queue that is inserting into the DB, so during this time I want to display a progress dialog, and dismiss it once the entire queue is clear. The fragment with the button looks like this:
public class StartFragment extends Fragment implements View.OnClickListener {
Button startButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_start, container, false);
startButton = (Button) view.findViewById(R.id.startButton);
startButton.setOnClickListener(this);
return view;
}
#Override
public void onClick(View v) {
if (recording has not yet started){
mainActivity.startService(new Intent(mainActivity, SensorService.class));
} else {
//I want to display a progress dialog here when the service is told to stop
//Once all executor task queue is clear, I want to dismiss this dialog
mainActivity.stopService(new Intent(mainActivity, SensorService.class));
}
}
}
When the button is clicked the first time, the following service will start:
public class SensorService extends Service implements SensorEventListener {
public static final int SCREEN_OFF_RECEIVER_DELAY = 100;
private SensorManager sensorManager = null;
private WakeLock wakeLock = null;
ExecutorService executor;
Runnable insertHandler;
private void registerListener() {
//register 4 sensor listeners (acceleration, gyro, magnetic, gravity)
}
private void unregisterListener() {
sensorManager.unregisterListener(this);
}
public BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive("+intent+")");
if (!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
Log.i(TAG, "Runnable executing...");
unregisterListener();
registerListener();
}
};
new Handler().postDelayed(runnable, SCREEN_OFF_RECEIVER_DELAY);
}
};
public void onSensorChanged(SensorEvent event) {
//get sensor values and store into 4 different arrays here
//insert into database in background thread
executor.execute(insertHandler);
}
#Override
public void onCreate() {
super.onCreate();
//get sensor manager and sensors here
PowerManager manager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
//Executor service and runnable for DB inserts
executor = Executors.newSingleThreadExecutor();
insertHandler = new InsertHandler();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startForeground(Process.myPid(), new Notification());
registerListener();
wakeLock.acquire();
return START_STICKY;
}
#Override
public void onDestroy() {
//Prevent new tasks from being added to thread
executor.shutdown();
try {
//Wait for all tasks to finish before we proceed
while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
Log.i(TAG, "Waiting for current tasks to finish");
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
if (executor.isTerminated()){
//Stop everything else once the task queue is clear
unregisterReceiver(receiver);
unregisterListener();
wakeLock.release();
dbHelper.close();
stopForeground(true);
//Once the queue is clear, I want to send a message back to the fragment to dismiss the progress dialog here
}
}
class InsertHandler implements Runnable {
public void run() {
//get sensor values from 4 arrays, and insert into db here
}
}
So I want to display the dialog on the 2nd button press. Then once it is pressed again, service will stop, and I want to wait until the queue is clear and then send a dismiss event back to the fragment to dismiss the progress dialog.
Showing the dialog is easy. I can just add progress dialog code in the onClick method of the fragment, before stopService is called
I'm having difficulty with figuring out how to send a message back in onDestroy of the SensorService to dismiss that dialog
Whats the best way of doing this without resorting to external libraries?
Is there some way that the BroadcastReceiver I'm using in SensorService can be used? Or maybe it's better to create a new Handler in the fragment and somehow pass it through to the service so it can send a message back to the fragment?
EDIT:
I have tried the following based on one of the answers below:
Added a MessageHandler class to my fragment class:
public static class MessageHandler extends Handler {
#Override
public void handleMessage(Message message) {
int state = message.arg1;
switch (state) {
case 0:
stopDialog.dismiss();
break;
case 1:
stopDialog = new ProgressDialog(mainActivity);
stopDialog.setMessage("Stopping...");
stopDialog.setTitle("Saving data");
stopDialog.setProgressNumberFormat(null);
stopDialog.setCancelable(false);
stopDialog.setMax(100);
stopDialog.show();
break;
}
}
}
Created a new instance of MessageHandler in my fragment (tried placing this in a variety of places...same results):
public static Handler messageHandler = new MessageHandler();
The service is then started from my fragment using:
Intent startService = new Intent(mainActivity, SensorService.class);
startService.putExtra("MESSENGER", new Messenger(messageHandler));
getContext().startService(startService);
In my SensorService BroadcastReceiver I create the messageHandler:
Bundle extras = intent.getExtras();
messageHandler = (Messenger) extras.get("MESSENGER");
Then I show the dialog at the very beginning of SensorService onDestroy:
sendMessage("SHOW");
and dismiss it at the very end of that same method:
sendMessage("HIDE");
My sendMessage method looks like this:
public void sendMessage(String state) {
Message message = Message.obtain();
switch (state) {
case "SHOW":
message.arg1 = 1;
break;
case "HIDE" :
message.arg1 = 0;
break;
}
try {
messageHandler.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
So I can start the Service OK, but when I press it again to stop, I get this:
java.lang.RuntimeException: Unable to stop service com.example.app.SensorService#21124f0: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Messenger.send(android.os.Message)' on a null object reference
and its referring to Line 105 of SensorService where I have messageHandler.send(message)
Thoughts on what might be wrong?
In activity:
protected BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, final Intent intent) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(intent.hasExtra("someExtraMessage")){
doSomething(intent.getStringExtra("someExtraMessage"));
}
}
});
}
};
#Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("message-id"));
}
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
}
public void doSomething(){
//...
}
Then somewhere from service:
Context context = BamBamApplication.getApplicationContext(); // Can be application or activity context.
// BamBamApplicaiton extends Application ;)
Intent intent = new Intent("message-id");
intent.putExtra("someExtraMessage", "Some Message :)");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Actually you are doing wrong from the very beginning :) all the services are running on main thread, so here you must better start all hard processing to async task to move this in background otherwise you will stuck your app, or you will get sudden unexpected crashes.
Here are you sample of async task that parses json api response in background with Typed result by parameter.
class ParseJsonInBackground<T> extends AsyncTask<String, Void, ApiResponseModel<T>> {
private ProcessResponse<T> func;
private Type inClass;
public ParseJsonInBackground(ProcessResponse<T> f, Type inClass){
this.func = f;
this.inClass = inClass;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected ApiResponseModel<T> doInBackground(String... json) {
Gson gson = new Gson();
try {
ApiResponseModel<T> result = (ApiResponseModel<T>) gson.fromJson(json[0], inClass);
return result;
}catch(Exception e){
ApiResponseModel<T> result = new ApiResponseModel<T>();
result.data = null;
result.success = false;
result.error = new ArrayList<>();
result.error.add(new ErrorModel(0, "Parsing error", "Parsing error"));
return result;
}
}
#Override
protected void onPostExecute(ApiResponseModel<T> result) {
Utils.hideLoadingProgress(mContext);
if(result != null && func != null){
if(result.success){
func.onSuccess(result);
}else{
func.onError(result);
}
}
}
}
and sample how to call:
new ParseJsonInBackground<T>(responseFunc, inClass).execute(json.toString());
make attention! - don't use any views in processing coz this will stuck main thread, make database processing in similar async task, don't write to often to database make recording with transactions.
I would propose doing this via Handler messages: you send a message from the Service to your Activity which has to register as a callback handler (implement http://developer.android.com/reference/android/os/Handler.Callback.html). Use a custom message code (message.what) and listen for it. Keep in mind to send this to the main looper of your application (from the service).
You may also check this comment which illustrates this kind of interaction with some more code: https://stackoverflow.com/a/20595215/4310905
It turns out that the code in the Edit of my original question works, but I have to shuffle around some of my code:
Bundle extras = intent.getExtras();
messageHandler = (Messenger) extras.get("MESSENGER");
The above needs to be moved to onStartCommand of SensorService instead of being in the BroadcastReceiver

Service Automatic Called on Destroying Activity

I am stuck with the problem of Activity + Service in that I have following number of Activities and Services.
Activities:
LoginActivity => OrderListActivity => AddOrderActivity => ConfirmOrderActivity
Services:
ReceivingOrderService - Receiving New Data From Server
SendingOrderService - Sending new Data to Server
Above both Service Calling from another Separate Service on duration of some interval.
CheckAutoSyncReceivingOrder - To call ReceivingOrderService (Interval 15Mins)
CheckAutoSyncSendingOrder - To call SendingOrderService (Interval 3Mins)
CheckAutoSyncReceivingOrder:
public class CheckAutoSyncReceivingOrder extends Service {
Timer timer;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
if(timer != null) {
timer.cancel();
Log.i(TAG, "RECEIVING OLD TIMER CANCELLED>>>");
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if(InternetConnection.checkConnection(getApplicationContext())) {
if(getDatabasePath(DatabaseHelper.DATABASE_NAME).exists())
startService(new Intent(CheckAutoSyncReceivingOrder.this, ReceivingOrderService.class));
} else {
Log.d(TAG, "Connection not available");
}
}
}, 0, 60000); // 1000*60*15 = 9,00,000 = 15 minutes
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(timer != null)
timer.cancel();
Log.d(TAG, "Stopping Receiving...");
}
}
CheckAutoSyncSendingOrder:
public class CheckAutoSyncSendingOrder extends Service {
Timer timer;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
if(timer != null) {
timer.cancel();
Log.i(TAG, "OLD TIMER CANCELLED>>>");
}
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
Log.i(TAG, ">>>>>>>> SENDING AUTO SYNC SERVICE >>>>>>>>");
if(InternetConnection.checkConnection(getApplicationContext())) {
if(getDatabasePath(DatabaseHelper.DATABASE_NAME).exists())
startService(new Intent(CheckAutoSyncSendingOrder.this, SendingOrderService.class));
} else {
Log.d(TAG, "connection not available");
}
}
}, 0, 120000); // 1000*120*15 = 1,800,000 = 15 minutes
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if(timer != null)
timer.cancel();
Log.d(TAG, "Stopping Sending...");
}
}
ConfirmOrderActivity#Final Task which i have called for Insert Data:
new AsyncTask<Void, Void, Integer>() {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog = new ProgressDialog(
ConfirmOrderProductActivity.this);
progressDialog.setMessage("Inserting "
+ (isInquiry ? "Inquiry" : "Order") + "...");
progressDialog.setCancelable(false);
progressDialog
.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressDialog.show();
}
#Override
protected Integer doInBackground(Void... params) {
// TODO Auto-generated method stub
int account_id = context.getSharedPreferences(PREF_DATA,
MODE_APPEND).getInt(DATA_ACCOUNT_ID, 0);
/**
* Check Whether isInquiry or not...
*/
product_type = isWeight ? 1 : 0;
if (isInquiry) {
/*
* INSERTING DATA IN INQUIRY TABLE
*/
return m_inquiry_id;
} else {
/*
* INSERTING DATA IN ORDER TABLE
*/
return m_order_id;
}
}
#Override
protected void onPostExecute(Integer m_order_id) {
// TODO Auto-generated method stub
super.onPostExecute(m_order_id);
progressDialog.dismiss();
if (dbHelper.db.isOpen())
dbHelper.close();
String title = "Retry";
String message = "There is some problem, Go Back and Try Again";
AlertDialog.Builder alert = new AlertDialog.Builder(
ConfirmOrderProductActivity.this);
if (m_order_id != -1) {
title = isInquiry ? "New Inquiry" : "New Order";
message = isInquiry ? "Your Inquiry Send Successfully." : "Your Order Saved Successfully.";
alert.setIcon(R.drawable.success).setCancelable(false);
} else {
alert.setIcon(R.drawable.fail).setCancelable(false);
}
alert.setTitle(title).setMessage(message)
.setPositiveButton("OK", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
dialog.dismiss();
startActivity(new Intent(
ConfirmOrderProductActivity.this,
FragmentChangeActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
/* Opening Left to Right Animation */
overridePendingTransition(R.anim.right_out,
R.anim.right_in);
}
});
AlertDialog alertDialog = alert.create();
alertDialog.show();
}
}.execute();
Everything is working fine as per flow of inserting records in database.
After Adding Inquiry:
Destroying Activity and Getting following Logcat:
Main Problem:
When I placed order successfully from ConfirmOrderActivity, It is displaying AlertDialog of Success Message which is cancellable false. When I Stop application from this Activity, Its calling both CheckAutoSyncReceivingOrder and CheckAutoSyncSendingOrder automatically.
Edited:
I am calling both Service from LoginActivity only, after that it
will called automatically after given intervals But Problem occurs
when I destroy ConfirmOrderActivity when dialog is shown.
I didn't know why it happens that Why its running automatically when I stop Activity Directly.
I have tried onStartCommand() with START_NON_STICKY in Service but not working. (as START_STICKY is default.)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
Is there any solution?
You need to either run your service in the foreground so when the activity is destroyed so will the service or use a bound service and manage the binding with the activity lifecycle, so it is not continually restarted when the activity is destroyed.
From this android docs tutorial Bound Services
You need to do this for each service.
public class CheckAutoSyncReceivingOrder extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
CheckAutoSyncReceivingOrder getService() {
return CheckAutoSyncReceivingOrder.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
From your activity that creates and calls the service, that when it is destroyed you want your service destroyed.
public class BindingActivity extends Activity {
CheckAutoSyncReceivingOr mService;
boolean mBound = false;
#Override
protected void onStart() {
super.onStart();
// Bind to CheckAutoSyncReceivingOr
Intent intent = new Intent(this, CheckAutoSyncReceivingOr.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to CheckAutoSyncReceivingOr, cast the IBinder and get CheckAutoSyncReceivingOr instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
And manage the service lifecycle. Restart the same service with your timer, do not create a new service.
public class ExampleService extends Service {
int mStartMode; // indicates how to behave if the service is killed
IBinder mBinder; // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
#Override
public void onCreate() {
// The service is being created
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
#Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
#Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
#Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}
Note START_NOT_STICKY will only prevent the service from restarting if the device is low on memory.
Be mindful that you where you are starting services, just start it once and allow the service to maintain it's own lifecycle until you destroy it with your activity.
This is in reply to your original unedited question, when the app was mysteriously crashing:
You need to destroy the dialog before the context window the dialog is attached to. That will cause a problem. So this is where program flow and the order of closing and cleaning up resources is important. They, frequently have to be destroyed in the reverse order they were created if they are dependent upon parent windows (which is often in the form of a particular activity).
It's difficult to trace your code, so this is a generic answer.
Make use of onPause and onDestroy in your activities.
In all your activities, manage any resources you have created within that activity and with a null check, close them down. Like you have in your service class. If you want to override the parent onDestroy, place your custom code before super.onDestroy.
protected void onDestroy() {
if(timer != null)
timer.cancel();
Log.d(TAG, "Stopping Sending...");
super.onDestroy();
}
(1)For Your Dialog:
The solution is to call dismiss() on the Dialog you created before exiting the Activity, e.g. in onDestroy(). All Windows & Dialog should be closed before leaving an Activity.
(2)For Your service autostart:
you have to look at the value the service returns from its onStartCommand method. The default value is START_STICKY which will restart the service after it is destroyed. Take a look at the onStartCommand documentation for more details:
If the process that runs your service gets killed, the Android system will restart it automatically it is default behavior.
This behavior is defined by the return value of onStartCommand() in your Service implementation. The constant START_NOT_STICKY tells Android not to restart the service if it s running while the process is "killed".
You need to Override method onStartCommand() in your service class and move all your code from onStart() method to onStartCommand() method.
According to the Android Documentation:
For started services, there are two additional major modes of
operation they can decide to run in, depending on the value they
return from onStartCommand(): START_STICKY is used for services that
are explicitly started and stopped as needed, while START_NOT_STICKY
or START_REDELIVER_INTENT are used for services that should only
remain running while processing any commands sent to them
onStart() method calls each time when service is restarted but onStartCommand() method will not called if you return START_NON_STICKY.
Don't use onStart() anymore, it's deprecated.
I hope it helps you.
Services got killed when application got killed (add logs in service onStartCommand() and onDestroy() function and try clearing app from recent list and you will see onDestroy() is called. Android will re-start service if you have returned START_STICKY intent in onStartCommand()).
There are two approaches to fix your problem.
Either make your two services as foreground service.
Instead of using CheckAutoSyncReceivingOrder and CheckAutoSyncSendingOrder to schedule start of another services, you should use AlarmManager to schedule your task.

How to resume my activity from where user has long press(shut down) power button

I am working on the application,I am having the requirement:if user long press the power button at any time and press again to start device,the activity should start from where the device was shut down.I dont know either this is a valid question or not.
I tried working with:
public class PowerMangerTestActivity extends Activity {
private static PowerManager objpowermanager;
private static PowerManager.WakeLock wl;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
callTOWakeLock();
setContentView(R.layout.main);
}//end of onCreate
public void callTOWakeLock() {
// TODO Auto-generated method stub
objpowermanager=(PowerManager)getSystemService(Context.POWER_SERVICE);
wl=objpowermanager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "******MyTag****");
//You should acquire it when your app starts,
if(wl.isHeld())
{
wl.release();
}
wl.acquire();
}
#Override
public void onDestroy() {
wl.release();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
callTOWakeLock();
}
/*#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Intent i = new Intent(this, PowerMangerTestActivity.class);
startActivity(i);
return true;
TextView tv=(TextView) findViewById(R.id.textview);
tv.setText("You press power button");
}
return super.dispatchKeyEvent(event);
}*/
}
but not getting expected behaviour.
I have tried to catch KeyEvent.KEYCODE_POWER,but not getting how to use for this scenario.
any suggestions?
thanks
This may be unacceptable to you, but you should NOT DO THIS.
It is going against a usability idea called "expected behavior".
You are doing something that a user is not expecting, and there is a good chance they are going to be pissed if you do this.
Just my two cents!
I would try and find another solution to this problem, such as caching useful data in phone storage, and recalling it when the application is resumed/started.
onPause still should be called when the power button is long pressed. The only case (as far as I know) where it won't be called is on a battery pull
It is reasonable for an emergency manager app to catch the power button event, so here's one solution, taken from Samsungs support database:
package com.samsung.lockscreenreceiver;
public class LockScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(Intent.ACTION_USER_PRESENT.equals(action)) {
// bring app to foreground
} else if(Intent.ACTION_SCREEN_OFF.equals(action) ) {
Toast.makeText(context, "screen on",Toast.LENGTH_LONG).show();
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
Toast.makeText(context, "screen off",Toast.LENGTH_LONG).show();
}
}
}
And the activity:
public class MyActivity extends Activity {
private BroadcastReceiver mReceiver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mReceiver = new LockScreenReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
intentFilter.addAction(Intent.ACTION_USER_PRESENT);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
//intentFilter.addAction(Intent.ACTION_SHUTDOWN); // won't work unless you're the device vendor
registerReceiver(mReceiver, intentFilter);
}
#Override
protected void onDestroy()
{
super.onDestroy();
unregisterReceiver(mReceiver);
}
}
You catch power on/off and bring the activity to foreground. The activity then denies all focus changes using:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
//super.onWindowFocusChanged(hasFocus);
if(!hasFocus) {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}
And you'll have to switch off screen lock, for example using:
https://play.google.com/store/apps/details?id=org.jraf.android.nolock&hl=en
The above app is not protected, so you can decompile it as usual. :)

Categories

Resources