Increasing Activity loading time - android

I have two Activities A and B. Activity A will start Activity B. Am doing some UI initialization, db query and local storage read operation in onCreate of Activity B. My problem is Activity B takes long time to come visible. Is that because of such operations in onCreate? I want at least my UI changes to visible first. Please guide me

In your onCreate perform heavy tasks in different Thread/handler/AsyncTask. For Example
public void onCreate(Bundle b){
super.onCreate(b);
setContentView(R.layout.yourlayout);
// do other gui initialization
Handler h = new Handler();
h.post(new Runnable{
public void run(){
// do your heave tasks
}
});
}

Related

Android handler and runnable nullpointer

I have a problem
I am using handler and runnable to update timer inside my app, inside my Runnable I am updating textview, after 1minut I want to show some content, everything works fine until I rotate the screen, every textview is now null, and I couldnt figure out why.
My code:
Runnable mTimer = new Runnable() {
#Override
public void run() {
textView.setText(DateFormat.format("mm:ss", timers - System.currentTimeMillis()));
test();
mHandler.postDelayed(this, TIME);
}
};
Any ideas why this might happen?
Handler probably delivers a Runnable to an Activity that was recycled. Proper use of Handler is like
private Handler mHandler;
private TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler();
setContentView(R.layout.yourView);
mTextView = findViewById(R.id.text);
}
#Override
protected void onStart() {
super.onStart();
//start updating every time Activity is started
handler.postDelayed(mTimer, oneMinuteDelay);
}
#Override
protected void onStop() {
super.onStop();
//make sure to remove all messages
handler.removeCallbacksAndMessages(null);
}
In theory, this (null views) should not happen.
When you change the screen orientation, the activity leaves the screen and becomes useless, but it still exists and references the views. Your runnable references the instance of activity that has created it, so the activity cannot die while the runnable is still there. At least, so it was. Which Android version do you use?
It seems I understand what you mean. You mean null contents in the views. You have to create a static variable, say, lastInstance:
class MyActivity extends Activity {
static MyActivity lastInstance;
void onCreate(...) {
...
lastInstance = this;
}
// no need to reference an instance of any Activity, so static
static class MyRunnable implements Runnable {
#Override
public void run() {
lastInstance.textView.setText(DateFormat.format("mm:ss", timers - System.currentTimeMillis()));
lastInstance.test();
mHandler.postDelayed(this, TIME);
}
}
static Runnable mTimer = new MyRunnable();
}
I do not recommend android:configChanges="screenSize|keyboardHidden|orientation" because this is not the only case when Android recreates an Activity, so this way you will not fix any bugs, you will just make them more difficult to reproduce.
For this thing you have to specify in your manifest with the specified line in your activity tag then your issue will be fixed.
i.e,
<activity android:name="your activity"
android:configChanges="screenSize|keyboardHidden|orientation">
</activity>
Then it will work for you on rotating the screen also.
Edited Answer
Better check that textview If it is null create a reference and then add the data it may fix your issue. or meanwhile you can pass your old data from onSavedInstance();
and you can get the data from onCreate(SavedInstance savedinstance)
here it will returns that prevoius data what you are setted in onsavedInstance Method.
try this for data exchange it will work
After rotate your activity recreates, so textView is null.
Please remove the handler code from the runnable. Also first create object of handler then write the handlers post delayed method where you want. Main use of handler is to update UI from thread.
If the Activity doesn't crash when you turn round the device, it means that the textView is there. If you see nulls on the screen it is the content of the textView that is being set as null.
In the text, the only variable I see is timers.
Where is this variable defined and where is it being set?
First check that you properly initialize the handler as below :
handler = new Handler();
The null pointer error may come if you not initialize the handler.

which Operation will perform first in onStart or onCreate in Android

I want to perform one data base Operation once. I want to do this when My Activity is Visible. Where shall I puty my LoadDatabase() function
LoadDatabase();
this is my oncreate of activity
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.retrospectscan);
}
this is my onStart
#Override
protected void onStart()
{
super.onStart();
}
Where Shall I put my LoadDatabase Code ? So that It will operated only if activity is fully Visible.
If Any other Approach is there please help me.
The complete activity lifecycle is here:
Though loading from database may be lengthy task , you can try doing it in AsyncTask or in onStart.
You can also use it on onResume. This depends on your application use.
user2737044
use Application context and load your database in application context create().
2nd thing is that, In activity onCreate() call first then it will call onstart().

Does the handler use the bind thread If i use a handler from anoter activity?

That's the cuestion , i have:
Activity A
Activity B
From A i want to communicate with B , then i use a Handler created on B to do it this way:
ActivityB.handlerB.sendMessage(msg);
Then what i don't know if it would use the ActivityA thread , or the ActivityB thread .
In order to let ActivityB Thread do the work , Is it well done?
Unless ActvityB created handlerB using a non-default Looper, all messages sent to handlerB will only deliver their messages on the same thread that handlerB was created within.
So, for example, if ActivityB created handler in a very typical way, from an activity event callback, handlerB will deliver its messages to the default UI thead.
So, if ActivityB is made like this, ActivityA is safe to call handlerB.sendMessage():
public class ActivityB extends Activity {
Handler handlerB;
public void onCreate(Bundle bundle) {
this.handlerB = new Handler() {
public void handleMessage(Message message) {
;; // Do something
}
};
}
}
So, for most circumstances, your answer is: Yes.

How to force main Acivity to wait for subactivity in Android?

I am calling a subactivity from main activity. This subactivity should take few numbers from user (i'm using Edit text control to achieve this), save them to static variable in another class and terminate. I want main activity to wait for subactivity but both are just running simultaneously. Even doing sth like that doesn't help:
Thread t = new Thread(new Runnable(){
public void run(){
Log.v("==================", "run "+new Date());
startActivityForResult(new Intent(ctx,myCustomSubactivity.class),1);
} });
Log.v("==================", "calling run "+new Date());
t.start();
try {
t.join();
} catch (InterruptedException e) {Log.v("==================", "can't join");}
Log.v("==================", "back from activity "+new Date());
do you know how to force main activity to wait? Thread.wait() method is not supported in Android(program throws error).
May be I'm missing something but why don't just use startActivityForResult and onActivityResult mechanism? You could get result from you subactivity from intent it was resulted with.
Edit: BTW as far as I understand, if you will run Object.wait() from Activity code if will hold UI tread whitch can result in Application not responding error.
I agree with Nikolay this is definitely the android way to do this.
Start the subactivity with startActivityForResult in the sub activity use setResult to add an result code and an intent with all the numbers you need in the data bundle.
In your first activity overwrite onActivityResult and retrieve the numbers from the Intent.
If you use the static variable this seems easier in the first moment but it is very insecure and there are some cases this may not work. If your program is send to the background your activities will be saved but if the phone runs low on memory the system will close your program and after the user resumes it everything looks like the moment the user left it but the static variables will be recreated to their initialization value.
Try to get used to the way the android activity lifecycle works. Using this approach will result in fewer used memory and a much better user experience.
Check out the Notepad example, it covers exactly this situation. And as others have said, the Android way is to have your first activity start up your second activity (not sub-activity!) and asynchronously listen for a response (not pause or wait, no need for joining, etc.).
Well... you can do it like this (btw, there's not straight forward way):
Have a singleton class, let's call it Monitor:
public class Singleton
{
private Singleton() { }
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
public class ParentActivity extends Activity
{
private void startAndWait()
{
Intent i = new Intent();
// initialize i
startActivityForResult(i);
Singleton si = Singleton.getInstance();
synchronized(si)
{
si.wait();
}
//do remaining work
}
}
public class ChildActivity extends Activity
{
protected void onCreate(Bundle savedInstance)
{
//do all the work
Singleton si = Singleton.getInstance();
synchronized(si)
{
si.notify();
}
}
}
I'm not here to judge if it's a good pattern or not but if you really need an activity to wait for a sub-activity, you can try this approach:
define an object (lock) over which the two activities get synchronized; this can (should) also work as the object to exchange data between those two activities and thus should be defined as static
in parent activity, start an async task (as the UI main thread cannot be in waiting state)
in the async task, start your sub-activity
the async task waits on the lock till it gets notified
the sub-activity does whatever it needs and notifies the waiting thread when it finishes
I did a similar thing in my app and IMHO had a good reason for this (not to bother a user with login screen upon app start or resume, the app tries to re-use credentials stored in a secured place and only in case it fails, it shows this login screen. So yes, basically any activity in my app can get "paused" and waits till the user provides correct credentials in the login activity upon which the login screen finishes and the app continues exactly where it got paused (in the parent activity).
In the code it would be something like this:
ParentActivity:
public class ParentActivity extends Activity {
private static final String TAG = ParentActivity.class.getSimpleName();
public static class Lock {
private boolean condition;
public boolean conditionMet() {
return condition;
}
public void setCondition(boolean condition) {
this.condition = condition;
}
}
public static final Lock LOCK = new Lock();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.parent_layout);
// do whatever logic you need and anytime you need to stat sub-activity
new ParentAsyncTask().execute(false);
}
private class ParentAsyncTask extends AsyncTask<Boolean, Void, Boolean> {
#Override
protected Boolean doInBackground(Boolean... params) {
// do what you need and if you decide to stop this activity and wait for the sub-activity, do this
Intent i = new Intent(ParentActivity.this, ChildActivity.class);
startActivity(i);
synchronized (LOCK) {
while (!LOCK.conditionMet()) {
try {
LOCK.wait();
} catch (InterruptedException e) {
Log.e(TAG, "Exception when waiting for condition", e);
return false;
}
}
}
return true;
}
}
}
ChildActivity:
public class ChildActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.child_layout);
// do whatever you need in child activity, but once you want to finish, do this and continue in parent activity
synchronized (ParentActivity.LOCK) {
ParentActivity.LOCK.setCondition(true);
ParentActivity.LOCK.notifyAll();
}
finish();
// if you need the stuff to run in background, use AsyncTask again, just please note that you need to
// start the async task using executeOnExecutor method as you need more executors (one is already occupied), like this:
// new ChildAsyncTask().executeOnExecutor(ChildAsyncTask.THREAD_POOL_EXECUTOR, false);
}
}

Android AsyncTask context behavior

I've been working with AsyncTasks in Android and I am dealing with an issue.
Take a simple example, an Activity with one AsyncTask. The task on the background does not do anything spectacular, it just sleeps for 8 seconds.
At the end of the AsyncTask in the onPostExecute() method I am just setting a button visibility status to View.VISIBLE, only to verify my results.
Now, this works great until the user decides to change his phones orientation while the AsyncTask is working (within the 8 second sleep window).
I understand the Android activity life cycle and I know the activity gets destroyed and recreated.
This is where the problem comes in. The AsyncTask is referring to a button and apparently holds a reference to the context that started the AsyncTask in the first place.
I would expect, that this old context (since the user caused an orientation change) to either become null and the AsyncTask to throw an NPE for the reference to the button it is trying to make visible.
Instead, no NPE is thrown, the AsyncTask thinks that the button reference is not null, sets it to visible. The result? Nothing is happening on the screen!
Update: I have tackled this by keeping a WeakReference to the activity and switching when a configuration change happens. This is cumbersome.
Here's the code:
public class Main extends Activity {
private Button mButton = null;
private Button mTestButton = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mButton = (Button) findViewById(R.id.btnStart);
mButton.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View v) {
new taskDoSomething().execute(0l);
}
});
mTestButton = (Button) findViewById(R.id.btnTest);
}
private class TaskDoSomething extends AsyncTask<Long, Integer, Integer>
{
#Override
protected Integer doInBackground(Long... params) {
Log.i("LOGGER", "Starting...");
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 0;
}
#Override
protected void onPostExecute(Integer result) {
Log.i("LOGGER", "...Done");
mTestButton.setVisibility(View.VISIBLE);
}
}
}
Try executing it and while the AsyncTask is working change your phones orientation.
AsyncTask is not designed to be reused once an Activity has been torn down and restarted. The internal Handler object becomes stale, just like you stated. In the Shelves example by Romain Guy, he simple cancels any currently running AsyncTask's and then restarts new ones post-orientation change.
It is possible to hand off your Thread to the new Activity, but it adds a lot of plumbing. There is no generally agreed on way to do this, but you can read about my method here : http://foo.jasonhudgins.com/2010/03/simple-progressbar-tutorial.html
If you only need a context and won't use it for ui stuff you can simply pass the ApplicationContext to your AsyncTask.You often need the context for system resources, for example.
Don't try to update the UI from an AsyncTask and try to avoid handling configuration changes yourself as it can get messy. In order to update the UI you could register a Broadcast receiver and send a Broadcast.
You should also have the AsyncTask as a separate public class from the activity as mentioned above, it makes testing a lot easier. Unfortunately Android programming often reinforces bad practices and the official examples are not helping.
This is the type of thing that leads me to always prevent my Activity from being destroyed/recreated on orientation change.
To do so add this to your <Activity> tag in your manifest file:
android:configChanges="orientation|keyboardHidden"
And override onConfigurationChanged in your Activity class:
#Override
public void onConfigurationChanged(final Configuration newConfig)
{
// Ignore orientation change to keep activity from restarting
super.onConfigurationChanged(newConfig);
}
To avoid this you can use the answer givin here: https://stackoverflow.com/a/2124731/327011
But if you need to destroy the activity (different layouts for portrait and landscape) you can make the AsyncTask a public class (Read here why it shouldn't be private Android: AsyncTask recommendations: private class or public class?) and then create a method setActivity to set the reference to the current activity whenever it is destroyed/created.
You can see an example here: Android AsyncTask in external class

Categories

Resources