Permalink
Browse files

* Closes #504 Sporadically missing instance variable

* Added test for Activity without onCreate
  • Loading branch information...
1 parent 566586c commit e5410fcd9e962ea51cbfcf0cd2f7d0c6c3a5eaa0 @donv donv committed Oct 15, 2013
View
@@ -1,2 +1,2 @@
-source 'https://rubygems.org/'
+source 'http://rubygems.org/'
gemspec
@@ -60,11 +60,24 @@ public void onCreate(Bundle bundle) {
}
}
- // FIXME(uwe): What is this for?
- public boolean rubotoAttachable() {
- return true;
+ public void onDestroy() {
+ if (ScriptLoader.isCalledFromJRuby()) {
+ super.onDestroy();
+ return;
+ }
+ if (!JRubyAdapter.isInitialized()) {
+ Log.i("Method called before JRuby runtime was initialized: RubotoActivity#onDestroy");
+ super.onDestroy();
+ return;
+ }
+ String rubyClassName = scriptInfo.getRubyClassName();
+ if (rubyClassName == null) {
+ super.onDestroy();
+ return;
+ }
+ ScriptLoader.callOnDestroy(this);
}
- // EMXIF
+
/****************************************************************************************
*
@@ -86,6 +86,24 @@ public int onStartCommand(android.content.Intent intent, int flags, int startId)
}
}
+ public void onDestroy() {
+ if (ScriptLoader.isCalledFromJRuby()) {
+ super.onDestroy();
+ return;
+ }
+ if (!JRubyAdapter.isInitialized()) {
+ Log.i("Method called before JRuby runtime was initialized: RubotoActivity#onDestroy");
+ super.onDestroy();
+ return;
+ }
+ String rubyClassName = scriptInfo.getRubyClassName();
+ if (rubyClassName == null) {
+ super.onDestroy();
+ return;
+ }
+ ScriptLoader.callOnDestroy(this);
+ }
+
/****************************************************************************************
*
@@ -272,6 +272,8 @@ public static synchronized boolean setUpJRuby(Context appContext, PrintStream ou
addLoadPath(scriptsDirName(appContext));
put("$package_name", appContext.getPackageName());
+ runScriptlet("::RUBOTO_JAVA_PROXIES = {}");
+
initialized = true;
} catch (ClassNotFoundException e) {
handleInitException(e);
@@ -1,6 +1,7 @@
package org.ruboto;
import java.io.IOException;
+import java.util.Map;
import android.app.ProgressDialog;
import android.content.Context;
@@ -52,7 +53,6 @@ public static void loadScript(final RubotoComponent component) {
JRubyAdapter.put("$java_instance", component);
rubyClass = JRubyAdapter.runScriptlet("class << $java_instance; self; end");
} else if (JRubyAdapter.isRubyOneNine()) {
- JRubyAdapter.runScriptlet("Java::" + component.getClass().getName() + ".__persistent__ = true");
rubyClass = JRubyAdapter.runRubyMethod(component, "singleton_class");
} else {
throw new RuntimeException("Unknown Ruby version: " + JRubyAdapter.get("RUBY_VERSION"));
@@ -67,7 +67,6 @@ public static void loadScript(final RubotoComponent component) {
Log.d("Script contains class definition");
if (rubyClass == null && hasBackingJavaClass) {
Log.d("Script has separate Java class");
- JRubyAdapter.runScriptlet("Java::" + component.getClass().getName() + ".__persistent__ = true");
rubyClass = JRubyAdapter.runScriptlet("Java::" + component.getClass().getName());
}
Log.d("Set class: " + rubyClass);
@@ -116,16 +115,40 @@ public void run() {
}
public static final void callOnCreate(final RubotoComponent component, Object... args) {
+ persistObjectProxy(component);
if (component instanceof android.content.Context) {
Log.d("Call onCreate on: " + component.getScriptInfo().getRubyInstance());
// FIXME(uwe): Simplify when we stop support for snake case aliasing interface callback methods.
if ((Boolean)JRubyAdapter.runScriptlet(component.getScriptInfo().getRubyClassName() + ".instance_methods(false).any?{|m| m.to_sym == :onCreate}")) {
JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onCreate", args);
- } else if ((Boolean)JRubyAdapter.runScriptlet(component.getScriptInfo().getRubyClassName() + ".instance_methods(false).any?{|m| m.to_sym == :on_create}")) {
+ } else if ((Boolean)JRubyAdapter.runScriptlet(component.getScriptInfo().getRubyClassName() + ".instance_methods(true).any?{|m| m.to_sym == :on_create}")) {
JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "on_create", args);
+ } else {
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onCreate", args);
}
// EMXIF
}
}
+ public static final void callOnDestroy(final RubotoComponent component) {
+ String rubyClassName = component.getScriptInfo().getRubyClassName();
+ if ((Boolean)JRubyAdapter.runScriptlet(rubyClassName + ".instance_methods(false).any?{|m| m.to_sym == :onDestroy}")) {
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onDestroy");
+ } else if ((Boolean)JRubyAdapter.runScriptlet(rubyClassName + ".instance_methods(true).any?{|m| m.to_sym == :on_destroy}")) {
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "on_destroy");
+ } else {
+ JRubyAdapter.runRubyMethod(component.getScriptInfo().getRubyInstance(), "onDestroy");
+ }
+ releaseObjectProxy(component);
+ }
+
+ private static void persistObjectProxy(RubotoComponent component) {
+ JRubyAdapter.runScriptlet("Java::" + component.getClass().getName() + ".__persistent__ = true");
+ ((Map)JRubyAdapter.get("RUBOTO_JAVA_PROXIES")).put(component.getScriptInfo().getRubyInstance(), component.getScriptInfo().getRubyInstance());
+ }
+
+ private static void releaseObjectProxy(RubotoComponent component) {
+ ((Map)JRubyAdapter.get("RUBOTO_JAVA_PROXIES")).remove(component.getScriptInfo().getRubyInstance());
+ }
+
}
View
@@ -135,7 +135,7 @@ def generate_subclass_or_interface(params)
def generate_core_classes(params)
hash = {:package => 'org.ruboto'}
%w(method_base method_include implements force).inject(hash) {|h, i| h[i.to_sym] = params[i.to_sym]; h}
- hash[:method_exclude] = params[:method_exclude].split(',').push('onCreate').push('onBind').push('onStartCommand').join(',')
+ hash[:method_exclude] = params[:method_exclude].split(',').push('onCreate').push('onDestroy').push('onBind').push('onStartCommand').join(',')
%w(android.app.Activity android.app.Service android.content.BroadcastReceiver).each do |i|
name = i.split('.')[-1]
@@ -0,0 +1,17 @@
+require 'ruboto/widget'
+
+ruboto_import_widgets :LinearLayout, :TextView
+
+class NoOnCreateActivity
+ def onResume
+ super
+ set_title File.basename(__FILE__).chomp('_activity.rb').split('_').
+ map { |s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
+
+ self.content_view = linear_layout :orientation => :vertical,
+ :gravity => android.view.Gravity::CENTER do
+ text_view :id => 42, :text => title, :text_size => 48.0,
+ :gravity => android.view.Gravity::CENTER
+ end
+ end
+end
@@ -0,0 +1,15 @@
+activity org.ruboto.test_app.NoOnCreateActivity
+
+setup do |activity|
+ start = Time.now
+ loop do
+ @text_view = activity.findViewById(42)
+ break if @text_view || (Time.now - start > 60)
+ sleep 1
+ end
+ assert @text_view
+end
+
+test('activity starts without onCreate implemented') do |activity|
+ assert_equal 'No On Create', @text_view.text.to_s
+end
@@ -5,17 +5,19 @@
class StartupExceptionActivity
def onCreate(bundle)
super
- setTitle File.basename(__FILE__).chomp('_activity.rb').split('_').map { |s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
+ setTitle File.basename(__FILE__).chomp('_activity.rb').split('_').
+ map { |s| "#{s[0..0].upcase}#{s[1..-1]}" }.join(' ')
self.content_view =
- linear_layout :orientation => :vertical, :gravity => android.view.Gravity::CENTER do
- @text_view = text_view :id => 42, :text => title, :text_size => 48.0, :gravity => android.view.Gravity::CENTER
+ linear_layout :orientation => :vertical, :gravity => :center do
+ @text_view = text_view :id => 42, :text => title, :text_size => 48.0,
+ :gravity => :center
end
intent = android.content.Intent.new
- intent.setClassName($package_name, 'com.example.android.lunarlander.LunarLander')
+ intent.setClassName($package_name, 'com.example.UndeclaredActivity')
startActivity(intent)
rescue Exception
- puts "************************ Exception creating activity: #{$!}"
+ puts "Expected exception creating activity: #{$!}"
puts $!.backtrace.join("\n")
end
@@ -10,6 +10,6 @@
assert @text_view
end
-test('super called correctly') do |activity|
- assert_equal 'Startup OK', activity.find_view_by_id(42).text.to_s
+test('activity starts with caught exception') do |activity|
+ assert_equal 'Startup OK', @text_view.text.to_s
end
@@ -7,7 +7,7 @@ def setup
generate_app
Dir.chdir APP_DIR do
File.open('Gemfile.apk', 'w') do |f|
- f << "source 'https://rubygems.org/'\n\n"
+ f << "source 'http://rubygems.org/'\n\n"
f << "gem 'gosu_android', :git => 'https://github.com/Garoe/gosu-android.git'"
end
end
View
@@ -64,6 +64,7 @@ def test_gen_class_activity_with_lowercase_should_fail
# APK was 8755.5KB. PLATFORM: STANDALONE, ANDROID_TARGET: 15, JRuby: 1.7.5
# APK was 8770.2KB. PLATFORM: STANDALONE, ANDROID_TARGET: 16, JRuby: 1.7.5
# APK was 6337.3KB. PLATFORM: STANDALONE, ANDROID_TARGET: 10, JRuby: 9000.dev
+ # APK was 6556.7KB. PLATFORM: STANDALONE, ANDROID_TARGET: 16, JRuby: 9000.dev
def test_new_apk_size_is_within_limits
apk_size = BigDecimal(File.size("#{APP_DIR}/bin/RubotoTestApp-debug.apk").to_s) / 1024
@@ -77,8 +78,8 @@ def test_new_apk_size_is_within_limits
'1.7.3' => 7400.0,
'1.7.4' => 8500.0,
'1.7.5' => 8800.0,
- '9000' => 6400.0,
- }[JRUBY_JARS_VERSION.to_s] || 6400.0
+ '9000.dev' => 6600.0,
+ }[JRUBY_JARS_VERSION.to_s] || 6600.0
version << ", JRuby: #{JRUBY_JARS_VERSION.to_s}"
else
upper_limit = {

0 comments on commit e5410fc

Please sign in to comment.