Question

I'm having a few issues with the last couple of pieces on my iOS app built with Appcelerator Titanium.

The app sample below shows one of my windows which allows the user to tap a view (which contains a word), which flips around to show the same word in a different language. The user can then tap the same view again and it animates back to the original position showing the original word.

When the user wants to move onto another word, they simple swipe on the view and it brings in the next word.

Here are the issues i'm experiencing;

  1. If a user swipes super fast through loads of words, then taps to flip, it crashes.
  2. If a user taps the view to flip the view around sometimes the second word flashes up before the animation takes place, it should only be seen as the view comes around into view.

and

3) The user can opt to drop the word, which when tapped performs a database update and then reloads the function and brings a new word in. Great for the first time you use it, but on the 2nd, 3rd, 4th time, the alertbox pops up multiple times rather than once.

Now, I suspect I'm doing something wrong here, but I can't work it out, i've moved code around to make sure labels aren't displaying before they should, but it keeps happening.

Can anyone shed any light on 1 or all of my points? I'm about to lose my mind!

I'm using Titanium 3.20 for iOS

Many thanks

Simon

var win = Titanium.UI.currentWindow;

var selectedlanguage = Ti.App.Properties.getString('langSelect');

// detect height
if (Titanium.Platform.displayCaps.platformHeight == 480) {
    var MVTOP = 115;
    var tapTOP = 83;
    var swipeTOP = 275;
} else {
    var MVTOP = 165;
    var tapTOP = 133;
    var swipeTOP = 325;
}

var masterView = Ti.UI.createView({
    backgroundColor: '#FFF',
    top: MVTOP,
    width: 300,
    height: 140,
    opacity: 0.7
});

var state = true;


win.add(masterView);

var front = Ti.UI.createView({
    backgroundColor: '#FFF',
    top: 0,
    left: 0,
    width: 300,
    height: 140,
    opacity: 1.0,
    touchEnabled: false
});

var back = Titanium.UI.createView({
    backgroundColor: '#FFF',
    top: 0,
    left: 0,
    width: 300,
    height: 140,
    opacity: 1.0,
    touchEnabled: false
});


if (win.section == 'word_expressions') {
    var label1 = Ti.UI.createLabel({
        //text: verb_german,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 20
        },
        top: 50
    });

    var label2 = Ti.UI.createLabel({
        //text: verb_english,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 20
        },
        top: 50
    });

} else {
    var label1 = Ti.UI.createLabel({
        //text: verb_german,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 30
        },
        top: 50
    });

    var label2 = Ti.UI.createLabel({
        //text: verb_english,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 30
        },
        top: 50
    });
}



var dropButton = Ti.UI.createButton({
    width: 120,
    height: 41,
    right: 15,
    bottom: 15,
    title: 'drop word',
    backgroundColor: '#fd0100',
    color: '#FFF',
    font: {
        fontSize: 15
    },
    opacity: 1.0
});
win.add(dropButton);


function loadWords() {

    // get the section to query for the database
    var wordSection = win.section;

    // get a random pair of words
    var db = Ti.Database.open('germanV6');

    var rows = db.execute('SELECT * FROM Words WHERE ' + wordSection + ' = 1 AND word_dropped = 0 ORDER BY RANDOM() LIMIT 1');

    var x = 0;
    while (rows.isValidRow()) {

        if (selectedlanguage == 'en') {
            var word_1 = rows.fieldByName('word_english');
            var word_2 = rows.fieldByName('word_german');
        } else if (selectedlanguage == 'de') {
            var word_2 = rows.fieldByName('word_english');
            var word_1 = rows.fieldByName('word_german');
        }
        var word_id = rows.fieldByName('word_id');

        rows.next();
    }

    // close database
    rows.close();



    var state = true;

    label1.text = word_1;

    front.add(label1);
    masterView.add(front);



    label2.text = word_2;

    back.add(label2);


    masterView.addEventListener('click', function (e) {
        switch (state) {
        case true:
            Ti.API.info('true');
            masterView.animate({
                view: back,
                transition: Ti.UI.iPhone.AnimationStyle.FLIP_FROM_LEFT
            });
            break;
        case false:
            Ti.API.info('false');
            label1.text = word_1;
            masterView.animate({
                view: front,
                transition: Ti.UI.iPhone.AnimationStyle.FLIP_FROM_RIGHT
            });
            break;
        }
        state = !state;
    });



    var eventListener = function () {
        // update the DB to tell it the word has been dropped
        var dbDelete = Ti.Database.open('germanV6');
        var rowsDelete = dbDelete.execute('UPDATE Words SET word_dropped=1 WHERE word_id=' + word_id);


        // pop an alert to notify the user the word has been dropped
        var alertDialog = Titanium.UI.createAlertDialog({
            title: 'Word Dropped',
            message: 'This word has been dropped!' + word_id,
            buttonNames: ['OK']
        });
        // show the message
        alertDialog.show();

        // load in a new word
        //loadWords();
        alertDialog.addEventListener('click', function (j) {
            loadWords();
        });
    };

}

// fire the function and load our words into play
loadWords();


var tapLabel = Ti.UI.createLabel({
    width: 200,
    top: tapTOP,
    text: 'tap to flip',
    textAlign: 'center',
    color: '#FFF',
    font: {
        fontSize: 15
    }
});

var swipeLabel = Ti.UI.createLabel({
    width: 320,
    top: swipeTOP,
    text: 'swipe for next word',
    textAlign: 'center',
    color: '#FFF',
    font: {
        fontSize: 15
    }
});

win.add(tapLabel);
win.add(swipeLabel);


var grammarButton = Ti.UI.createButton({
    width: 120,
    height: 41,
    left: 15,
    bottom: 15,
    title: 'verb tables',
    backgroundColor: '#ffff01',
    color: '#000',
    font: {
        fontSize: 15
    },
    opacity: 1.0
});

win.add(grammarButton);




swipeLabel.addEventListener('swipe', function (e) {

    // reload the new word
    loadWords();

});


masterView.addEventListener('swipe', function (e) {


    // reload the new word
    loadWords();

});

grammarButton.addEventListener('click', function (e) {
    var newWin = Titanium.UI.createWindow({
        url: 'verb_table.js',
        backgroundImage: '/images/background_random.jpg',
        backgroundColor: '#FFF',
        barColor: '#000',
        translucent: true,
        color: '#FFF',
        navTintColor: '#FFF',
        titleControl: Ti.UI.createLabel({
            text: 'Verb Table',
            color: '#FFF'
        }),
        statusBarStyle: Titanium.UI.iPhone.StatusBar.LIGHT_CONTENT,
        backButtonTitle: ''
    });
    newWin.nav = win.nav;
    win.nav.openWindow(newWin, {
        animated: true
    });
});
Was it helpful?

Solution

loadWords() adds an event listener to masterView every time it is called. Probably the source of the crash. Do the Ti.API.info calls build up over time of using the app? I'd expect you should see it popping out 1 then 2 then 3... as it runs along.

Is there missing code? The eventListener function is defined, but I can't find where it is called. This function then has another listener that then calls loadWords again adding more listeners. the name of the function eventListener was difficult to look for because all the addEventListener references come up in a search because they match. I'd change the name of that function to something more distinct. It might be getting called in there, but I gave up looking for it.

There is something up with this code. I would expect that the var label1 and var label2 aren't the ones you are adding to the view later on, but I would expect them to go out of scope when they leave your blocks {}. I would move the var label1 and var label2 outside this if-else and just have label1 = Ti.UI... and the label2 = Ti.UI.. in there.

var label1;
var label2;
if (win.section == 'word_expressions') {
    label1 = Ti.UI.createLabel({ // FIX
        //text: verb_german,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 20
        },
        top: 50
    });

    label2 = Ti.UI.createLabel({  // FIX
        //text: verb_english,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 20
        },
        top: 50
    });

} else {
    label1 = Ti.UI.createLabel({  // FIX
        //text: verb_german,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 30
        },
        top: 50
    });

    label2 = Ti.UI.createLabel({ // FIX 
        //text: verb_english,
        text: '',
        textAlign: 'center',
        color: '#000',
        font: {
            fontSize: 30
        },
        top: 50
    });
}
front.add(label1);
back.add(label2);

Variable Scrope http://msdn.microsoft.com/en-us/library/bzt2dkta(v=vs.94).aspx

I would say you need to rethink the loadWords function. It is perhaps doing way too much and the source of all the issues. The masterView.addEventListener should be moved out. The alertDialog should be setup a different way as well. Perhaps moving that code to generate the alert outside of the omni function loadWords.

The database is opened repeatedly inside loadWords, but never closed. You did close the row, but forgot the db.

front.add and back.add aren't necessary in the loadWords function, you should have these after the If-Else statement where you are defining them. Keep the code in there that updates, their .text properties.

Looking closer at the label definitions you are defining them exactly the same aside from the font size. I would fix that to only change the font inside the IF-ELSE.

Fix the place where you detect height as well. Move all the var [variable names] out of the block and define them once. In the IF-ELSE then assign them the correct values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top