I'm having an issue with an acitivity for an android app, to make it simple I let there be three activities : the main M, the one that answers A and the one I start C.
So M starts A using startActivityOnResult, then A sends result to M and from there M starts S.
But for some reason, the layout of S doesn't update until the main method I call from there is finished (and when that method is finished the activity goes back to M anyway, so basically I only see the layout if I make the activity S not give the result and stand there doing nothing).
Here is some of the code :
In M starting S :
Intent intent = new Intent(MainActivity.this, getCamFind.class);
intent.putExtra("path", mCurrentPhotoPath);
startActivityForResult(intent, CAMFIND_REQUEST_CODE);
In S :
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_getcamfind);
receivedIntent = getIntent();
Log.d(TAG, "Received string : " + receivedIntent.getStringExtra("path"));
}
public void onStart(){
super.onStart();
try {
postCamResult(receivedIntent.getStringExtra("path"));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
So here the main method I was talking about is postCamResult, it basically connects to a server using retrofit. At the end of this method is where I would usually put the few lines to send back the result intent. The problem being the layout waits for this method to finish for some reason ? so if I don't send the result intent, it will, after doing all the server related stuff, finally print my layout, but you know, I'd like my layout to appear as soon as I open the activity!
Thank you in advance !
The Android documentation for the Activity lifecycle states that the visible lifetime of an Activity is between onStart() and onStop(), so the layout you set will be rendered after the onStart method is done.
If you put your postCamResult() inside onResume() you should be fine.
Still connecting to a server on the UI Thread is a bad idea, you should start a seperate thread for that, otherwise you might get an anr.
Related
So I am creating an app where I get the string from my AsyncTask which I have created as a subclass in my MainActivity class in order to get the variables I receive from the internet. And according to variables I get I change the images accordingly after every 5 seconds. Now the task is successful but on activity refresh I keep getting the default layout I created in activity_main.xml and again it changes to the one I want.
Posting my code below.
Thread thread = new Thread() { //thread I am running every 5 secs
#Override
public void run() {
try {
synchronized (this) {
wait(5000);
syncapp sa = new syncapp(); //AsyncTask to get String from Internet
sa.execute();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent mainActivity = new Intent(getApplicationContext(), MainActivity.class); //Creating intent to restart the activity (Need a workaround if possible)
startActivity(mainActivity);
}
;
};
thread.start();
}
public void setImage(String str) //Function I will call to change Image
{
vacancy =0;
b = a.toCharArray();
for (int i = 0; i < 6; i++)
if (b[i] == '0'){
iv[i].setImageResource(R.drawable.img2);
vacancy++;}
else if (b[i] == '1') {
iv[i].setImageResource(R.drawable.img1);
}
Log.i("abc ", a);
tv.setText("InBackGround" + str);
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/* for(int i =0;i<6;i++) {
outState.putChar("imv"+(i+1), b[i]);
}*/
outState.putString("a",a); //Getting a from the internet (php file)
Log.i("Saved State", "Activity A - Saving instance state");
}
Now what I want is if you have a better method to do this thing. Eg. In a Stock market application the prices keep on changing. The same way I want my image to change according to the data I get.
If this is the only method then how do I save changes I make
(eg. like in the code above setImageResource to img2) permanently.
If I can use something else ImageView.
I have already used onSaveInstanceState But as I am taking values from the internet I don't know I am not able to use them.
So first of all.. when working with UI elements such as Views, Widgets, you would want to avoid spawning your own threads, as View can be touched only from the thread it was created from.
Second.. you would also want to avoid sleeping inside your worker thread - basically just use the Handler class (from android.os) and post a delayed Runnable, like so: https://stackoverflow.com/a/20784353/2102748. Just be sure to stop all work on that particular handler when your Activity stops, like so: https://stackoverflow.com/a/3627399/2102748
Third - you should perhaps load the photo immediately (on the same AsyncTask or thread) if that is the only thing you need, but be sure to post the "set bitmap to view" work to the handler you created.
Hope this helps.
I have a outGoingCall broadcast receiver.
basically I want it to intercept any outgoing call and show a dialog for certain pre-defined numbers.
so I made this broadcast init an activity which inits an FragmentDialog which init a AlertDialog.
When the user click "no"
I want to stop the call from happening.
I know setResultData(null); in the broadcast should do it.
But how can I pass the dialog result to the broadcast ?
there is no onActivityResult() in a broadcast.
I know how to pass it till the activity only.
fragmentDialog code:
public class YesNoDialogFragment extends DialogFragment {
private YesNoDialogFragmentListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
// Instantiate the NoticeDialogListener so we can send events to the
// host
mListener = (YesNoDialogFragmentListener) activity;
} catch (ClassCastException e) {
// The activity doesn't implement the interface, throw exception
throw new ClassCastException(activity.toString()
+ " must implement NoticeDialogListener");
}
}
here is my activity code:
public class MainActivity extends FragmentActivity implements
YesNoDialogFragmentListener {
public static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showYesNoDialog();
}
#Override
public void onDialogPositiveClick() {
// how to send result to receiver ??
finish();
}
here is my receiver code:
#Override
public void onReceive(final Context context, final Intent intent) {
Log.v(Constants.LOGTAG, "OutgoingCallReceiver onReceive");
if (intent.getAction()
.equals(OutgoingCallReceiver.OUTGOING_CALL_ACTION)) {
Log.v(Constants.LOGTAG,
"OutgoingCallReceiver NEW_OUTGOING_CALL received");
// get phone number from bundle
String phoneNumber = intent.getExtras().getString(
OutgoingCallReceiver.INTENT_PHONE_NUMBER);
if ((phoneNumber != null)
&& phoneNumber
.equals(OutgoingCallReceiver.ABORT_PHONE_NUMBER)) {
Toast.makeText(
context,
"NEW_OUTGOING_CALL intercepted to number 123-123-1234 - aborting call",
Toast.LENGTH_LONG).show();
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
SharedPreferences sharedPreferences = context
.getSharedPreferences(Constants.SHARED_PREF_NAME,
Context.MODE_PRIVATE);
boolean isBloacked = sharedPreferences.getBoolean(
Constants.IS_NUMBER_BLOCKED, true);
if (isBloacked) {
// dialog and then:
setResultData(null);
}
}
as you can see i tried to share the activity result via shared preferences, how come the code is async and the setResultData(null); is called before the dialog is shown?
from what I know there is no way to end the call besides setResultData(null);
You have to go through an activity (or a fragment) and then pass it to the receiver. Whenever you start a dialog, it has a parent activity, and that is where the result is sent. Just add something to your activity that passes the result on to your receiver.
You might actually consider altering your design to put more of your logic into the activity. Receivers are generally intended to be pretty lightweight objects that receive notification of something, pass it on to somewhere else. and then go away. Anyway, I obviously don't know your code, so maybe this doesn't make sense.
EDIT
Sorry, I understand your problem better now. I'm used to only working with setResultData when one activity has launched another activity, and the 2nd one wants to send something back to the 1st one. But you are using it to stop an ordered broadcast, right?
Unfortunately, Android does now allow you to do what you are trying to do. This section of the doc specifically says that you cannot show a dialog from within a broadcast:
http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle
I think what you need to do is always return setResultData(null) right after starting your activity. If the user then clicks "no" in your dialog, then you are done. But if the user clicks "yes" (I'm assuming there is a "yes") then you would have to go ahead and make the call, and make sure you don't catch it again in your receiver.
Does that make sense? Sorry for my confusion earlier.
I've been playing around with an app I created.
Activity A(1st Activity) has a button that executes an AsyncTask. This AsyncTask's doInBackground() performs calculations on selected values in Activity A, and its onPostExecute() starts Activity B.
I click the button, then before Activity B can be started I press back to destroy Activity A.
The app closes, then relaunches with Activity B populated with calculations from my AsyncTask.
this awesome blog explains memory leaks with Threads when the screen is rotated, and I'm applying those lessons here with my AsyncTask and back button press. However, I'm still a little confused.
Pressing back on an Activity destroys it.
My asynctask is running on an activity that was destroyed, should throw a NPE since it's accessing list elements inside that activity.
But it didn't. What does destroyed really mean then? I thought it meant that the Activity A reference and its view hierarchy would be set to null to allow the garbage collector to sweep it up sometime and recycle the memory. The blog states it didn't, hence the memory leak.
So wait, Activity A didn't get destroyed? But I saw it disappear...
This is a conceptual question rather than a code question so far, but as requested:
private class MyAsyncTask extends AsyncTask<ArrayList<Train>, Void, Void> {
protected void onPreExecute() {
// Runs on the UI thread before doInBackground
spinWait.setVisibility(ProgressBar.VISIBLE);
waitMsg.setText("Calculating Schedules....");
spinWait.bringToFront();
waitMsg.bringToFront();
}
#Override
protected Void doInBackground(ArrayList<Train>... lolTrains) {
try {
calcSchedules(lolTrains[0]);
} catch (Exception e) {
Log.d("DEBUG", "Calculating schedules failed, " + e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(Void v) {
// This method is executed in the UIThread
spinWait.setVisibility(View.GONE);
waitMsg.setVisibility(View.GONE);
// if schedules is empty, show error dialog
if (schedules.size() == 0) {
// show msg, etc
} else {
Intent i = new Intent(getBaseContext(), ResultsActivity.class);
i.putExtra("results", schedules);
startActivity(i);
}
}
}
public void MethodInActivityA(View v) {
new MyAsyncTask().execute(memberVarInActivityA);
}
When you destroyed your activity, you did not destroy you AsyncTask (which is basically kind of a Thread), to do that try
asyncTask.cancel(true);
on your onDestroy(); method
hope this helps
On your onPostExecute(), When start new activity call finsih() followed by startActivity(i). This finish() internally call onDestroy. Here you need to clear Asynctask manually because Asynctask is inner class of your Activity. Even activity was destroyed this inner class holds the reference of activity. You need manually clear the reference by asyncTask.cancel().
I setted up simple application with 2 activities. I had problem in first activity. It is used just for displaing logo for 3 seconds and then launching second activity. Problem is that it doesn't load the layout, it waits 3 seconds and then load second activity. The code is here:
public class StartActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_screen);
final Intent myAct = new Intent(this, MyActivity.class);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
startActivity(myAct);
finish();
}
}
I was able to fix this problem by creating another thread and executing waiting there. Fixed code is here:
new Thread(){
public void run(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
startActivity(myAct);
finish();
}
}.start();
So i actually fixed the problem. I just want to know why it works the second way but it doesnt work by first way becouse i don't understand it.
In the first case, you are telling the UI Thread to sleep, preventing it to draw the layout. When it finishes the sleep process, it immediately starts the next Activity. That is why you do not see the first Activity layout being shown. This approach is not recommended at all as during the sleep time, your application is not responsive to any user actions. You are recommended to use an AsyncTask or a new Thread or a Handler, using postDelayed() method but never cause the UIThread to stop doing its job (drawing and handling UI events).
In the second case, you are making the sleep() in a new Thread, not the UIThread. So, what happens is that the UI Thread is never interrupted and is allowed to draw the entire layout. At the same time, the sleep time is respected as well. Once the sleep() ends, your new Activity starts.
First method makes the UI thread sleep .This result in stopping of all the functioning and UI interaction of the activity.
The second method uses another thread .Since it's the other thread which sleeps all the UI parts of the main UI thread works fine and the code works as intended.
Actually your approach is also wrong / bad practice.
Starting new activity and finishing current should be done on main thread.
Also try to avoid final objects initialization, they may stack in memory.
Here is one of correct approaches (postDelayed() will be perform on MainThread):
public class StartActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.start_screen);
View view = findViewById(R.id.any_view_from_start_screen_layout);
view.postDelayed(new Runnable(){
public void run(){
startNewActivityAndCloseCurrent();
},3000);
}
private void startNewActivityAndCloseCurrent(){
Intent myAct = new Intent(this, MyActivity.class);
startActivity(myAct);
finish();
}
}
So I've got an activity in my android app, that runs on start.
This activity is just a page with a start button.
When I press the start button, it calls another activity and closes itself:
Intent i = new Intent(this, Dictating.class);
startActivity(i);
finish();
The other Activity is using Text-to-speech to dictate some words.
Now I've got something weird happening:
1) I listen to the dictating.
2) I press back button: dictating stops (what I want)
3) I run again the app, press the start button. Now I have my new activity running and dictating, but in the back I can hear the older Activity that resumed where it was, and continues dictating.
I would like for the new activity to start all over again, and not keep the other activity.
How can I do that ?
PS: This is an activity problem, and not a text-to-speech problem as I'm flushing the text-to-speech each time, It could not be kept in the memory
Thank you
EDIT:
Here is the onCreate of my Dictating class, there is tons of code in this class, I obviously don't want to post all my code, so here is some parts:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.streaming);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, MY_DATA_CHECK_CODE);
this.txtCurrentWord = (TextView) findViewById(R.id.txtCurrentWord);
this.btnPlayPause = findViewById(R.id.btnPlayPause);
this.btnPlayPause.setOnClickListener(this);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MY_DATA_CHECK_CODE) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// success, create the TTS instance
this.tts = new TextToSpeech(this, this);
} else {
// missing data, install it
Intent installIntent = new Intent();
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
there are a few weird things I'm doing like:
Runnable task = new Runnable() {
public void run() {
//runs on ui
runOnUiThread(new Runnable() {
public void run() {
readNextWord();
}
});
}
};
worker.schedule(task, 1, TimeUnit.SECONDS);
this delays the next word by one second, and then executes a fonction in the main ui thread. not sure if this matter
And some flushing at the end:
#Override
public void onDestroy() {
tts.shutdown();
super.onDestroy();
}
You need to add launchMode property to your activity inside AndroidManifest file, for more detail see "Using the manifest file"
This question is over a year old, but I can't believe no one ever gave you the right answer. Also, I don't think you should have accepted an answer that clearly didn't solve anything for you. By accepting such answers, you're just cluttering the StackOverflow google search results with junk for other people with the same problem.
The flushing you do at the end is completely wrong. According to the Activity lifecycle, onDestroy() is never guaranteed to be called. If you want to make sure the flushing gets done properly, do it inside of onPause().
For now the solution I'm giving you does fix the main problem you've described. However, if you do get the time to do a more complete rewrite, you'll want use a service that you bind to your activity. That will give you the finer control you require.