0

My app shell read data from a file on the device. I create the tables but they are not instantly shown (i create them in the onCreate() method). Maybe you can give me a hint were i can start scraping my data from the web, because when i do it in my main activity it will jump over the first step to show my data from the database.

I am trying to get notified by my main activity when its completely drawn (when the user can see the UI).

I realized that this way:

view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener) [...]

is not working, because when this method is called i am not able to see my view on the device. So i logged some variables in this method to get more information about this view:

log("isActivated: " + linearLayout.isActivated()); --> returned false
log("isEnabled: " + linearLayout.isEnabled()); --> returned true
log("isInTouchMode: " + linearLayout.isInTouchMode()); --> returned true
log("isShown: " + linearLayout.isShown()); --> returned true

I mentioned that the only variable which is not true, was view.isActivated(). Can you tell me whats the best way to wait for your application till everything its drawn (hopefully not above API 11).

Edit: some code if you wanna see

public class MainActivity extends Activity {

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

        List<Group> groups = null;
        String path = getFilesDir() + separator + STORAGE_FILE;
        File storageFile = new File(path);

        try {
            InternalGroupStorage storage = new InternalGroupStorage();
            if (storageFile.exists()) {
                log("Load groups from storage: " + path);
                groups = storage.loadGroupStorage(path);
                createGroupTables(groups);
                log("Tables created");
            }
        }
        catch (JSONException e) {
            scrapeGroupsFromWeb();
            log("JSONException occured: groups going to be scraped from weg now.");
            e.printStackTrace();
        }

    }

    private void scrapeGroupsFromWeb() {
        try {
            GroupScraperTask task = new GroupScraperTask();
            List<Group> groups = task.execute("A", "B", "C", "D", "E", "F", "G", "H").get();

            if (groups == null) {
                return;
            }
            log("Groups were scraped.");
            InternalGroupStorage groupStorage = new InternalGroupStorage();
            String path = getFilesDir() + separator + STORAGE_FILE;
            FileOutputStream fos = new FileOutputStream(path);
            groupStorage.saveGroupStorage(fos, groups);
            createGroupTables(groups);
            log("Tables created.");
        }
        catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private void createGroupTables(List<Group> groups) {
        GroupTable groupTable = new GroupTable();

        groupTable.createGroupTable(this, groups, 0, (TableLayout) findViewById(R.id.tableA));
        groupTable.createGroupTable(this, groups, 1, (TableLayout) findViewById(R.id.tableB));
        groupTable.createGroupTable(this, groups, 2, (TableLayout) findViewById(R.id.tableC));
        groupTable.createGroupTable(this, groups, 3, (TableLayout) findViewById(R.id.tableD));
        groupTable.createGroupTable(this, groups, 4, (TableLayout) findViewById(R.id.tableE));
        groupTable.createGroupTable(this, groups, 5, (TableLayout) findViewById(R.id.tableF));
        groupTable.createGroupTable(this, groups, 6, (TableLayout) findViewById(R.id.tableG));
        groupTable.createGroupTable(this, groups, 7, (TableLayout) findViewById(R.id.tableH));
    }

    @Override
    protected void onResume() {
        super.onResume();
        log("resume");
        scrapeGroupsFromWeb();
    }
}

onResume(); is called before my tables are drawn!

edit2 added this in my onCreate():

final LinearLayout layout = (LinearLayout) findViewById(R.id.LinearLayout1);
        ViewTreeObserver vto = layout.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                int width = layout.getMeasuredWidth();
                int height = layout.getMeasuredHeight();
                log("draw?");
                scrapeGroupsFromWeb();

            }
        });

Its only drawn after my scrapeGroupsFromWeb() in my onGlobalLayout()

unrated
  • 252
  • 4
  • 22
  • Why do you need to have your view visible to the user before starting anything else? The view exists on return from `setContentView(R.layout.activity_main);` whether it's visible or not. Even if it isn't visible, you can still access elements of that view and set their contents etc etc. – Squonk Jun 18 '14 at 19:10
  • You are calling `scrapeGroupsFromWeb` in `onResume` and in `onCreate`. – TyMarc Jun 18 '14 at 19:11
  • possible duplicate of [How can you tell when a layout has been drawn?](http://stackoverflow.com/questions/7733813/how-can-you-tell-when-a-layout-has-been-drawn) – loeschg Jun 18 '14 at 19:12
  • @TyMarc I only call `scrapeGroupsFromWeb` in `onCreate` when there is a JSONException catched. – unrated Jun 18 '14 at 19:17
  • @loeschg I also tried that. When the `onGlobalLayout` is called my tables are created but not drawn. – unrated Jun 18 '14 at 19:18
  • Yeah, that's what it does. But even if the `JSONException` is not called, you still call `createGroupTables` in `onCreate` and in `scrapeGroupsFromWeb`. That way, even if you don't have an exception, it will be called two times. – TyMarc Jun 18 '14 at 19:27
  • @TyMarc Between the time its called it should already be drawn one time, after i called it again it should be redrawn. I dont get the problem. – unrated Jun 18 '14 at 19:34
  • @unrated : You haven't answered my question. Why does the layout need to be visible to the user before you start using it? – Squonk Jun 18 '14 at 19:47
  • @Squonk Sry, missed your comment. I want to load data from an internal database. Then i want to present my data in my app. After they are shown i want to refresh my data automatically from the web. I want to do that because the refreshing takes a while when the connection is bad. – unrated Jun 18 '14 at 19:51
  • @unrated : It seems you're fixating on something which may be a problem caused by another part of your code. As I said, the layout actually exists (in memory) after `setContentView(...)` returns even if it isn't visible to the user. You can access any part of the layout using `findViewById(...)` even if the user can't see the layout. The process of creation, starting, resuming is synchronous - you won't see anything until the `Activity` is resumed, i.e., running. – Squonk Jun 18 '14 at 19:58
  • @unrated : I've just realised you are using the `get()` method of an `AsyncTask` - don't ever do this. The method is absolutely pointless and I have no idea why the Android devs added it to `AsyncTask`. It basically turns an asynchronous operation into a synchronous one. In other words it will block your UI thread which is why you're seeing the behaviour you describe. – Squonk Jun 18 '14 at 20:10
  • @Squonk Merry me! That was the problem <3 – unrated Jun 18 '14 at 21:16

2 Answers2

1

Generally this is done by adding a ViewTreeObserver to the view. See this SO post: https://stackoverflow.com/a/7735122/413254

LinearLayout layout = (LinearLayout)findViewById(R.id.YOUR_VIEW_ID);
ViewTreeObserver vto = layout.getViewTreeObserver(); 
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
    @Override 
    public void onGlobalLayout() { 
        this.layout.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
        int width  = layout.getMeasuredWidth();
        int height = layout.getMeasuredHeight(); 

    } 
});
Community
  • 1
  • 1
loeschg
  • 29,961
  • 26
  • 97
  • 150
  • I added this and i call my function ´scrapeGroupsFromWeb()` in there. But its only drawn after my ´scrapeGroupsFromWeb()` in my `onGlobalLayout()` – unrated Jun 18 '14 at 19:37
0

@loeschg answer worked for me, but a little detail I want to add, to help the prospect answer seekers in the future:

  • the "LinearLayout" in

    LinearLayout layout = (LinearLayout)findViewById(R.id.YOUR_VIEW_ID);
    

works with all the layout there is I believe, I'm using FrameLayout myself.

  • Get an "android:id=@+id/your_id_here in your corresponding xml file if you don't know how to findViewById.
  • Do not get rid of removeGlobalOnLayoutListener(this);unless you want to have this call back invoked everytime something happens to the layout.

Oh and SEO: layout, complete, finish, drawn, after, callback, listener

mastisa
  • 1,875
  • 3
  • 21
  • 39