How to make a callback after the view is completely rendered ?
I am trying to call a method which takes a screen-shot of parent view.
If I write that code in onCreate() method, the app crashes due to null pointer (as no view is rendered).
for now the temporary solution I have implemented is to make a delay of 1 second before calling that method.
But, I am looking for a much more robust solution to this problem.
any suggestions and help appreciated.
thanks :)
Try this logic ... always called after the view has got focus or rendered or looses focus
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
doWhateverAfterScreenViewIsRendered();
}
I have got a better option now :)
this really gives a call-back after the layout is rendered
private class LoadActivity extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mainMethod();
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
takeScreenShot(1);
}
#Override
protected String doInBackground(String... params) {
return null;
};
}
I created the above class and then called this method for execution in onCreate()
LoadActivity loadactivity= new LoadActivity();
loadactivity.execute();
You should use the onResume() callback on your Activity, which is
Called when the activity will start interacting with the user. At this point your activity is at the top of the activity stack, with user input going to it.
Related
Several times I've had problems writing code on onCreate(). Mostly because the UI has not been sized and laid out on the screen yet (even if I place my code at the end of the function). I've looked over the activity life-cycle to see if there's anything that runs after onCreate(). There is onStart(), but the problem is that onRestart() recalls onStart(), I don't want that. So is there a way to write code between onCreate() and onStart()? OR where should I write code that runs after the UI is placed and only runs once during its process?
Not sure what exactly you need but you can "cheat" and simply store whether you have run code or not:
private boolean mInit = false;
void onStart() {
if (!mInit) {
mInit = true;
// do one time init
}
// remaining regular onStart code
}
The other way of running code when UI is placed is to use the global layout listener:
public class FooActivity extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_content);
View content = findViewById(android.R.id.content);
content.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
#Override
public void onGlobalLayout() {
// unregister directly, just interested once.
View content = findViewById(android.R.id.content);
content.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// do things here.
}
}
I am building the app, which generates and adds view dynamically. I don't know in advance what views I need to create, these can be nested layouts or simple labels, etc, depending what comes back from web services.
Everything has been well so far until I started building really complex nested layouts .I have one case where I need to add about 11 levels of Layouts dynamically. When activity starts I display ProgressDialog(ring), while views are being generated. My problem is that with this complex structure ProgressDialog freezes while views are added. This is the code, which creates the view:
private class ViewCreator implements Runnable {
public BackgroundTaskViewCreatedResponse delegate;
private View mCreatedView;
private ComponentDefinition mComponent;
private ViewCreator(ComponentDefinition component){
this.mComponent = component;
}
#Override
public void run() {
try {
if (mComponent != null){
mComponent.setLinkedData(model.getLinkedData());
mCreatedView = componentCreator.createComponent(mComponent);
}
} finally {
if (mCreatedView != null)
delegate.processFinishTask(mCreatedView);
}
}
}
Layout, which has other views in it implements BackgroundTaskViewCreatedResponse, so, when view is ready, it will be added:
#Override
public void processFinishTask(final View createdView) {
//((Activity)view.getContext()).runOnUiThread(new Runnable(){
mView.post(new Runnable(){
#Override
public void run() {
mView.addView(createdView);
}
});
}
As you can see above, I have tried to call runOnUiThread call, but this blocks the UI thread completely while view hierarchy is being generated. At the same time view.post doesn't get called out of the box, so I have made some changes to views as suggested in this SO answer. So, now my views are added, but my ProgressDialog is not running smoothly. It stops in a few occasions and then resumes. I've also tried using Android AsyncTask, but that gives the same effect as runOnUiThread
I am not very experienced with Threads, have been trying to fix this for a few days now. Please help.
You can use AsyncTask to do this/ Here is an example:
private class GenerateViews extends AsyncTask<Void,Void,Void>{
#Override
protected void onPreExecute() {
// SHOW THE SPINNER WHILE GENERATING VIEWS
spinner.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(Void... params) {
//CALL YOUR VIEW GENERATING METHOD HERE
return null;
}
#Override
protected void onPostExecute(Void result){
spinner.setVisibility(View.INVISIBLE);
}
}
You can make this class inside your class, if you want to. And then, you just call
new GenerateCalls.execute();
My application crashes after click the button, but the code executes properly.
public void makeLead(View v) throws Exception {
try {
RegisterTimer rt = new RegisterTimer();
rt.ma = this;
rt.execute(null);
} catch (Exception e) {
e.printStackTrace();
}
}
public void log(String msg)
{
final TextView tv = (TextView)findViewById(R.id.editText);
tv.append(msg);
}
private class RegisterTimer extends AsyncTask {
public MainActivity ma;
#Override
protected Object doInBackground(Object[] objects) {
ma.log("ausd");
return null;
}
}
makeLead is onClick event. Method ma.log generates an error but works properly (msg added to textEdit). When I delete ma.log, app doesn't crash. I have no logs in my AndroidStudio so I can't see error message. What's wrong ?
You can not touch the Views in a non UI Thread.
and you are appending text to TextView in a background Thread which is not allowed.
and I hope there is no problem with the initialization of MainActivity inside RegisterTimer as you are not creating the instance of Activity manually. You are in correct way with the initialization rt.ma = this. and why do you need AsyncTask just for changing the text of a TextView?
You cannot update ui from a doInbackground. Initializing ma is not required
Make AsyncTask an inner class of Activity and update ui in onPostExecute
or use interface as a callback to the activity
Edit:
To make it clear
Make asynctaks an inner class of activity. Declare textview as a instance variable. Return result in doInbackground
In Activity
TextView tv;
#Override
public void onCreate(Bundle savedInstancestate)
super.onCreate(savedInstancestate);
setContentView(R.layout.yourlayout);
tv = (TextView)findViewById(R.id.editText);
Then
#Override
protected String doInBackground(Void objects) {
// some background computation
return "ausd";
}
In onpostExecute
#Override
protected void onPostExecute(String result)
{
super.onPostExecute();
tv.append(result);
}
Also you need
private class RegisterTimer extends AsyncTask<Void,Void,String> { // args missing
As described by #Raghunandan you have not initialized ma.
next is you cannot access view in background thread.
if your thread class is inside of MainActivity class then you can use
runOnUiThread(new Runnable() {
#Override
public void run() {
ma.log("ausd");
}
});
inside doInBackground method to update view.
Your method log is public, you don't need to make an object of the MainActivity class to access it, instead you can call it directly. Also you need to add some template after your ASYNC task, if you want to pass some input to your background process, you are using ASYNC task in a wrong way.
I want to show an progresscircle while a chat is loading. So I put some progressbar in, visibility set to invisible. Now I set in onPreExecute() the visibility to visible and in onPostExecute() to invisible.
The circle is shown, but just when the chat already did load AND it doesnt disappear. Can someone tell me my mistake? :o
#Override
public void onPreExecute() {
MainActivity.pbReadChat.setVisibility(ProgressBar.VISIBLE);
}
#Override
public Map<String, ArrayList<String>> doInBackground(String... strings) {
//...
return result;
}
public void onPostExecute(Map<String, ArrayList<String>> result) {
super.onPostExecute(result);
MainActivity.pbReadChat.setVisibility(ProgressBar.INVISIBLE);
}
Edit: Now it disappears but it gets just shown after chat already did load in doInBackground()
That are the important things of my Async class I think, hope someone can help me
Your onPostExecute() is not being called because doInBackground() does not return. It can happen because of one of the reasons below:
Infinite loop.
Infinite wait for an input.
Unchecked exception.
cancel() being called on AsyncTask. In this case, onCancelled() is called instead of onPostExecute()
I am loading around 100 soundpools of small sound which I need them through out application in an activity.
When this activity starts, the screen goes blank and the background loads after loading all soundpools.
How do make it display the background I which have already added in xml through out while loading soundpools?
Use AsyncTask to handle this.
private class MyBackgroundTask extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute() {
//initialize views like progress dialog.
}
#Override
protected Boolean doInBackground(String... params) {
//Add code which you want to run in background.
//In your case, code to load sound pools
}
#Override
public void onPostExecute(Boolean success) {
//update UI with the result
}
}
And in onCreate method,
new MyBackgroundTask().execute();