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);
}
Tobias Moe Thorstensen
  • 8,861
  • 16
  • 75
  • 143
  • 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()`? – class stacker Mar 11 '13 at 08:33
  • Of course, my bad too early in the morning. In the `initializeSlidingMenu()` I initalize the slidingmenu, please see my edit in a few seconds. – Tobias Moe Thorstensen Mar 11 '13 at 08:37
  • @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. – Tobias Moe Thorstensen Mar 11 '13 at 08:40
  • Ok thanks. How complex is your layout? – class stacker Mar 11 '13 at 08:42
  • 1
    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. – user370305 Mar 11 '13 at 08:44
  • The layout is not complex at all. It contains a simple `TextView`. That's whats bothering me. – Tobias Moe Thorstensen Mar 11 '13 at 08:44
  • 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()`. – user370305 Mar 11 '13 at 08:46
  • And remove `super.setContentView(layoutResourceId);` from `InitializeWindow()`. Just for try purpose and let me know. Because same things works in my case. – user370305 Mar 11 '13 at 08:48
  • 1
    @user370305 slightly improved, but not what I should expect by default. – Tobias Moe Thorstensen Mar 11 '13 at 08:54
  • 2
    I think this is all wild guessing now, and given the low complexity of the layout(s) I'm not with @user370305 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. – class stacker Mar 11 '13 at 08:56
  • 1
    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. – user370305 Mar 11 '13 at 08:58
  • Time different parts of the code – eski Mar 11 '13 at 09:11
  • @user370305 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. – class stacker Mar 11 '13 at 09:16

2 Answers2

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.

Nova
  • 241
  • 6
  • 16
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.

HalR
  • 11,411
  • 5
  • 48
  • 80
  • 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. – Tobias Moe Thorstensen Mar 12 '13 at 07:37