Slow loading of layout
Asked Answered
A

2

10

I have a super class which is in a library. This library take care of initializing some basic layout components and other stuff. My problem is that it takes 1.x seconds to load the layout, and shows the default layout for a while, before setting the child-specified layout.

This is the method of my super class:

public void InitializeWindow(Activity act, int layoutResourceId, String windowTitle,
        Object menuAdapter, int slideMenuMode) {
    super.setContentView(layoutResourceId);
    super.setBehindContentView(R.layout.menu_frame);
    this.menuAdapter = menuAdapter; 
    this.slideMenuMode = slideMenuMode;
    setWindowTitle(windowTitle);
    initializeSlidingMenu();
}

This is called this way:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.InitializeWindow(this, R.layout.activity_home, "\t\tHome",
            new MenuAdapter(this, R.menu.slide_menu), SlidingMenu.TOUCHMODE_FULLSCREEN);    
}

The application works like a charm, but it takes, as I said around 1.x seconds to load the layout passed from the child-class. Why does this happen?

By request, this is my initializeSlideMenu() method:

public void initializeSlidingMenu() {
    this.setSlidingActionBarEnabled(true);
    getSlidingMenu().setBehindOffsetRes(R.dimen.actionbar_home_width);
    getSlidingMenu().setShadowWidthRes(R.dimen.shadow_width);
    getSlidingMenu().setShadowDrawable(R.drawable.shadow);
    getSlidingMenu().setTouchModeAbove(slideMenuMode);
    getSlidingMenu().setBehindScrollScale(0.25f);

    ListView v = new ListView(this);
    v.setBackgroundColor(Color.parseColor("#000000"));
    v.setAdapter((ListAdapter) menuAdapter);
    getSlidingMenu().setMenu(v);
}
Archegonium answered 11/3, 2013 at 8:28 Comment(13)
I'm a bit irritated that you call InitializeWindow a constructor. Why does your superclass not do all the stuff in onCreate()? -- What's going on in initializeSlidingMenu()?Prestidigitation
Of course, my bad too early in the morning. In the initializeSlidingMenu() I initalize the slidingmenu, please see my edit in a few seconds.Archegonium
@user370305 the baseclass doesn't have any layout, the "default" android layout is shown, like the application name in the actionbar, with a white layout.Archegonium
Ok thanks. How complex is your layout?Prestidigitation
What I have doubt is your InitializeWindow() takes to-much time to create a layout while your base class already completed the drawing view for current activity. And prepared the windows for Activity.Horoscope
The layout is not complex at all. It contains a simple TextView. That's whats bothering me.Archegonium
Have you tried @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(layoutResourceId);} In this you have to call setContentView() from Child Activity not from Base Activity's InitializeWindow().Horoscope
And remove super.setContentView(layoutResourceId); from InitializeWindow(). Just for try purpose and let me know. Because same things works in my case.Horoscope
@Horoscope slightly improved, but not what I should expect by default.Archegonium
I think this is all wild guessing now, and given the low complexity of the layout(s) I'm not with @Horoscope here. It could also be the case that you are abusing savedInstanceState; we just don't know. I would recommend you do some profiling or at least log system time after calls to third party code to narrow the search.Prestidigitation
The simple logic what I have seen is, When your InitializeWindow() Will be called in that time your Base Activity completes the configure and prepared windows. So you have to call setContentView() from Child Activity and if possible don't do much work on base class's methods so your child Activity get enough time to prepare layout after that you can call the other stuff which prepared other view options.Horoscope
Time different parts of the codeCorcovado
@Horoscope I'm not sure I understand your rationale correctly because in my view you use words which do not precisely describe what happens. But I'm tempted to ask you whether you know that the whole measuring and layout process will only start much later after the child activity's onCreate() has returned. I can see no reason why setContentView() needs to be called from the final child class, either.Prestidigitation
A
2

To avoid such problems there are three ways in general.

  1. Let your onCreate() finish after setContentView() call as early as possible. You can use postDelayed runnable to delay few initialization which may not be needed at early stages.

  2. Do some task when the view is ready, it causes the Runnable to be added to the message queue of that view.

Snippet

view.post(new Runnable() {

        @Override
        public void run() {

        }
    });

If none of the above helps consider "Optimize with stubs" link : http://android-developers.blogspot.in/2009/03/android-layout-tricks-3-optimize-with.html

Hope it helps.

Ascham answered 12/3, 2013 at 7:40 Comment(0)
C
1

I suspect that the trouble spot for you is with:

 v.setAdapter((ListAdapter) menuAdapter);

You should do this as part of an AsyncTask. It will often be very slow to execute the loading by the adapter.

Here is a snippet from a sample AsyncTask implementation:

//before starting the load, I pop up some indicators that I'm doing some loading
progressBar.setVisibility(View.VISIBLE);
loadingText.setVisibility(View.INVISIBLE);

AsyncTask<Void, Void, Void> loadingTask = new AsyncTask<Void, Void, Void>() {
        private ArrayList<Thing> thingArray;

        @Override
        protected Void doInBackground(Void... params) {
            //this is a slow sql fetch and calculate for me
            thingArray = MyUtility.fetchThings(inputValue);
            return null;
        }

        @Override
        public void onPostExecute(Void arg0) {
            EfficientAdapter myAdapter = new EfficientAdapter(MyActivity.this, thingArray);
            listView.setAdapter(myAdapter);
            //after setting up my adapter, I turn off my loading indicators
            progressBar.setVisibility(View.INVISIBLE);
            loadingText.setVisibility(View.INVISIBLE);
            RelativeLayout layout = (RelativeLayout)MyActivity.this.findViewById(R.id.spacey);
            if (layout != null) {
                LayoutInflater inflater = LayoutInflater.from(MyActivity.this);
                View view = inflater.inflate(R.layout.name_tabled_sub, layout);
                NamedTableView tableView = new NamedTableView(MyActivity.this, view);
            }
            progressBar.setVisibility(View.INVISIBLE);
            loadingText.setVisibility(View.INVISIBLE);


        }
    };
    loadingTask.execute();

You can also do "PreExecute" items with the Async task, as well as update.

Culottes answered 12/3, 2013 at 0:8 Comment(1)
I tried this, by putting the initalization of the adapter inside a Thread, I thought an asynctask for this simple operation was to complex way of getting close to solving the problem. It performance did increase, but not the way that I expect. +1 for your answer anyway.Archegonium

© 2022 - 2024 — McMap. All rights reserved.