0

Short version: Is it perfered to set the contents of views during OnCreate(), or is it better to do this as an ASyncTask during OnCreate()? is there a something analogous to a OnPostCreate()?

I have found that when I run my app using the emulator (both default and Genymotion emulator) that starting new tasks seems really sluggish, and I often see log noticed about dropping frames (the UI thread might be doing too much work!). Sometimes the Genymotion emulator even gives a prompt that my app is non-responsive and a Wait/Force Close dialog.

I pass data between my activity as a Bundle, using Parcelable. The data is a simple collection of about a dozen ints and strings. it seems like passing this bundle is what slows things down.

When I use my Samsung physical android device, I don't notice any delay at all, but I worry about future performance hits or slower devices.

Relevant code supplied

Starts the Activity

 Intent intent = new Intent(this, edit.class);
    intent.putExtra(SoundConfig.class.getName(), sc);

    startActivityForResult(intent, buttonID);

Parcelable object

public class SoundConfig implements Parcelable {
public String mediaPath = null;
public int volume = 0;
public int viewID = 0;
public String text = null;
private int loop = 0;
private int holdable = 0;
private int fadeout = 0;
public String boardID = null;
public int colorbase = 0;
public int coloract = 0;
...
    @Override
public void writeToParcel(Parcel dest, int flags)
{
    dest.writeString(mediaPath);
    dest.writeInt(volume);
    dest.writeInt(viewID);
    dest.writeString(text);
    dest.writeInt(loop);
    dest.writeString(boardID);
    dest.writeInt(holdable);
    dest.writeInt(fadeout);
    dest.writeInt(colorbase);

}

private void readFromParcel(Parcel in)
{
    mediaPath = in.readString();
    volume = in.readInt();
    viewID = in.readInt();
    text = in.readString();
    loop = in.readInt();
    boardID = in.readString();
    holdable = in.readInt();
    fadeout = in.readInt();
    colorbase = in.readInt();
}

The Activity that receives the Bundle is where the slowness is most obvious

public class edit extends Activity implements ColorPicker.OnColorChangedListener
{

SoundConfig _state = null;
TextView _txtText = null;
TextView _txtFile = null;
SeekBar _cntrlVol = null;
CheckBox _switchLoop = null;
CheckBox _switchToggle = null;
CheckBox _switchFade = null;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_edit);

    Bundle bun = getIntent().getExtras();
    SoundConfig incomingConfig = null;
    if ( bun != null)
    {
        incomingConfig = bun.getParcelable(SoundConfig.class.getName());
    }
    else
    {
        incomingConfig = new SoundConfig();
    }

    try
    {
         setTitle("Edit:" + incomingConfig.text);
        _state = incomingConfig;
        _txtText = (TextView) findViewById(R.id.dispName);
        _txtFile = (TextView) findViewById(R.id.dispFile);
        _cntrlVol = (SeekBar) findViewById(R.id.skVolume);
        _cntrlVol.setOnSeekBarChangeListener(volumeListner);
        _switchLoop = (CheckBox) findViewById(R.id.btnSetLoop);
        _switchToggle = (CheckBox) findViewById(R.id.btnSetToggle);
        _switchFade = (CheckBox) findViewById(R.id.btnSetFade);

         ...             


        //Update the views based on info from _state
       _txtText.setText(_state.text);

       File file = new File(_state.mediaPath);
       String trimmed = file.getName().toString();
      _txtFile.setText(trimmed);
      _cntrlVol.setProgress(_state.volume);
      _switchLoop.setChecked(_state.isLoop());
      _switchToggle.setChecked(_state.isHoldable());
      _switchFade.setChecked(_state.isFadeOut());
    }
    catch(Exception err)
    {
        Log.e(tag, "Error " + err.getMessage());
    }
}

In my above code, I am wondering if I should be doing the 'Update views' block to be in an ASync task. But what throws me off, is that this is mostly all UI update stuff, and feel like it ought to be on this main UI thread? Am I wrong? What's the cleanest and most efficient way to do this? What is the right way to initialize views when passed a bundle, and are bundles a performance hit? Or is it all artifacts of the inefficient emulator?

  • I see "the UI thread might be doing too much work!" all the time in my logs. Even when i'm running something simple. I wouldnt really worry about that translating over to your app running on an actual device. I don't see how setting the views in an asynctask would help, as you still have to wait for it to finish to display your view. – Daniel H Nov 19 '14 at 20:05

1 Answers1

1

Mostly, you are dealing with emulator lag and performance problems. Real devices prioritize UI related stuff very fast, especially in newer models with more cores.

It looks like you are doing the work in the right place, although here are a couple comments:

  1. You have to do this on the UI thread. You can't "background process" UI updates.

  2. Processing the bundle has little to no impact on UI responsiveness or display timing.

  3. If you want to "test" this (because maybe you have a special situation), you can put the update in an AsyncTask and then do it maybe 10 seconds after onCreate - or even onResume - is called. onResume might be the closest thing to your "onPostCreate" concept (although you also have onStart). Look at the Activity life cycle:

http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle

onCreate is a common place to put this, however since you are passing data, you may consider using onResume but it really won't have much performance impact.

  1. If you really want to try this, you can wait until the layout is "drawn" and then update your views. You can do this with viewTreeObserver:

How can you tell when a layout has been drawn?

Tamir Abutbul
  • 7,301
  • 7
  • 25
  • 53
Jim
  • 10,172
  • 1
  • 27
  • 36