Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TIMOB-13020 First pass attempt to unroll and keep propertyChanged in a single UI callback. #3959

Merged
merged 1 commit into from
Mar 19, 2013
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
72 changes: 66 additions & 6 deletions android/titanium/src/java/org/appcelerator/kroll/KrollProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -574,17 +574,77 @@ public void setProperty(String name, Object value)
message.sendToTarget();
}
}


public class KrollPropertyChangeSet extends KrollPropertyChange {
public int entryCount;
public String[] keys;
public Object[] oldValues;
public Object[] newValues;

public KrollPropertyChangeSet(int capacity) {
super(null,null,null);
entryCount = 0;
keys = new String[capacity];
oldValues = new Object[capacity];
newValues = new Object[capacity];
}

public void addChange(String key, Object oldValue, Object newValue){
keys[entryCount] = key;
oldValues[entryCount] = oldValue;
newValues[entryCount] = newValue;
entryCount ++;
}

public void fireEvent(KrollProxy proxy, KrollProxyListener listener) {
if (listener == null) {
return;
}
for (int i = 0; i < entryCount; i++) {
listener.propertyChanged(keys[i], oldValues[i], newValues[i], proxy);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think just creating an arraylist of KrollPropertyChange and passing it over to the main thread is cleaner so we don't have to introduce a new class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was either subclass KrollPropertyChange (seen here) or to add a new event ID and change the handler code to handle this new eventID that would iterate over the arrayList. The subclass was the smaller change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other change is probably smaller.. All you need to do is add a case for something like MSG_MODEL_PROPERTIES_CHANGED, loop through the arraylist, and call fireEvent on each KrollPropertyChange.

}

@Kroll.method
public void applyProperties(Object arg)
{
if (arg instanceof HashMap) {
HashMap props = (HashMap) arg;
if (!(arg instanceof HashMap)) {
Log.w(TAG, "Cannot apply properties: invalid type for properties", Log.DEBUG_MODE);
return;
}
HashMap props = (HashMap) arg;
if (modelListener == null) {
for (Object name : props.keySet()) {
setPropertyAndFire(TiConvert.toString(name), props.get(name));
setProperty(TiConvert.toString(name), props.get(name));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this would be a behavior change. Currently if there is no model listener, we don't set the properties at all since the changes won't be applied anyways (propertyChanged won't be fired). I guess the question is, do we want to set the property even if the changes aren't applied? I'm on the fence, but leaning towards no.... what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actions that setPropertyAndFire does is to 1) setProperty and 2) if shouldFireChange(), trigger firePropertyChanged. firePropertyChanged, if modelListener == null, does nothing. So we can guarantee that there is no behavior change because we already know modelListener is null, thus setPropertyAndFire does no functional actions beyond setProperty. setProperty DOES do something even when modelListener is null, namely properties.put().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok forgot we set the property first, and then do the modelListener check.

}
} else {
Log.w(TAG, "Cannot apply properties: invalid type for properties", Log.DEBUG_MODE);
return;
}
if (TiApplication.isUIThread()) {
for (Object key : props.keySet()) {
String name = TiConvert.toString(key);
Object value = props.get(key);
Object current = getProperty(name);
setProperty(name, value);
if (shouldFireChange(current, value)) {
modelListener.propertyChanged(name, current, value, this);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just call setAndFireProperty() instead of doing all this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setAndFireProperty has a lot of checks that we can aggregate, such as TiApplication.isUIThread() and checking on modelListener. Part of the optimization was to remove redundant, unnecessary checks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}
return;
}

KrollPropertyChangeSet changes = new KrollPropertyChangeSet(props.size());
for (Object key : props.keySet()) {
String name = TiConvert.toString(key);
Object value = props.get(key);
Object current = getProperty(name);
setProperty(name, value);
if (shouldFireChange(current, value)) {
changes.addChange(name, current, value);
}
}
if (changes.entryCount > 0) {
getMainHandler().obtainMessage(MSG_MODEL_PROPERTY_CHANGE, changes).sendToTarget();
}
}

Expand Down