Aplicación Android basada en Java -> cambiar a Scala
Tengo una aplicación Java Android que quiero cambiar a Scala. Tengo muchos fragmentos y quiero saber cuál es la mejor manera de hacer esto en Scala.
Esta es mi clase de fragmento Java MyFragment
:
- ¿Qué idiomas están maduros para desarrollar aplicaciones nativas en Android
- Acelerar el proceso dex con archivos jar, ¿es posible?
- Dependencia no resuelta en sbt-android-plugin 0.6.0-SNAPSHOT?
- Scala Android AsyncTask no llamará a la devolución de llamada publishProgress, "onProgressUpdate"
- Android sin Java
public class MyFragment extends Fragment { private WebView myWebView; private TextView myTextView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View myView = inflater.inflate(R.layout.my_view, container, false); myWebView = (WebView) myView.findViewById(R.id.my_webview); myWebView.loadUrl("http://www.google.com/"); myTextView = (TextView) myView.findViewById(R.id.my_textview); myTextView.setText("Google.com"); return myView; } }
Siempre tengo esta estructura de base: algunos elementos de interfaz de usuario privados que instanciar en onCreateView
, hacer algunas cosas y devolver la vista (No se muestra aquí: en otros métodos on*
también hago algunas acciones con los elementos de la interfaz de usuario).
He encontrado algunos artículos que hacen un lazy val
como se describe aquí: http://blog.andresteingress.com/2011/09/20/programming-android-with-scala/ Pero en mi caso, esto no funciona, porque tengo fragmentos y no actividades. Primero tengo que inflar la vista principal myView
y luego puedo obtener los elementos de la interfaz de usuario de la misma.
¿Cuál es la mejor manera de hacer esto en Scala?
— ACTUALIZACIÓN —
Mi código Scala se parece a esto en este momento:
class MyFragment extends Fragment { private var myTextView: TextView = null override def onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle): View = { val myView = inflater.inflate(R.layout.my_view, container, false) val myWebView = myView.findViewById(R.id.my_webview).asInstanceOf[WebView] myWebView.loadUrl("http://www.google.com/") myTextView = myView.findViewById(R.id.my_textview).asInstanceOf[TextView] myTextView.setText("Google.com") myView } }
Entonces, ¿qué puedo mejorar aquí? myTextView
es una private var
porque tengo que acceder a ella varios métodos en este Fragmento. Parece que no puedo hacer las cosas explicadas aquí: http://blog.andresteingress.com/2011/09/20/programming-android-with-scala/ con lazy val
TypedActivity
y la conversión implícita de OnClickListener
, porque yo uso fragmentos . Entonces, ¿cómo puedo deshacerme del código original con .asInstanceOf[T]
y hacerla más parecida a Scala?
- Uso de constantes Java desde Scala en Android
- Android studio dalvik vm no puede encontrar la clase
- ¿Cómo extender ImageView en una aplicación Android Scala?
- Cómo excluir archivos R * .class de una compilación proguard
- Problema: "Extracción" de JSON usando ascensor-json en una aplicación Android (Scala)
- Scala en Android: java.lang.NoSuchMethodError: java.lang.String.isEmpty
- Guardando colección extranjera en ORMLite con Robospice y Scala
- Desarrollo sustancial de Android en Scala
Sobre la base de su código actualizado sólo puedo hacer alguna sugerencia para ser más "scala-ish"
Utilice Option
lugar de null
para sus miembros
private var myWebView: Option[WebView] = None private var myTextView: Option[TextView] = None
Para evitar el casting explícito de tus vistas en el código, debes moverlo a otra parte, pero no puedes deshacerte de él, porque la API original de Android no te da ninguna pista del tipo de tiempo de ejecución o compilación de los objetos devueltos. . Para superar este problema, el post que mencionó utiliza recursos personalizados mecanografiados y un rasgo que maneja los tipos de estos.
case class TypedResource[T](id: Int) object TR { object id { val my_webview = TypedResource[TextView](R.id.my_webview) val my_textview = TypedResource[WebView](R.id.my_textview) //... you must put here all your typed views referenced by id } } trait TypedViewHolder { def view: View //the method explicitly casts to the needed resource type based on the argument def findView[T](tr: TypedResource[T]): T = view.findViewById(tr.id).asInstanceOf[T] } object TypedResource { //this will implicitly convert your views to a corresponding TypedViewHolder //this lets you avoid explicit type cast to get your view implicit def view2typed(v: View): TypedViewHolder = new TypedViewHolder { def view = v } }
Ahora podemos usar el código anterior
val myView = inflater.inflate(R.layout.my_view, container, false) val myWebView = myView.findView(TR.id.my_webview) myWebView.loadUrl("http://www.google.com/") val myTextView = myView.findView(TR.id.my_textview) myTextView.setText("Google.com")
Juntando ambas cosas
class MyFragment extends Fragment { private var myWebView: Option[WebView] = None private var myTextView: Option[TextView] = None override def onCreateView( inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle): View = { //imports the implicit conversion import TypedResource._ val myView = inflater.inflate(R.layout.my_view, container, false) myWebView = Some(myView.findView(TR.id.my_webview)) //now we're using options, so we must call methods on the inner value //we can use Option.map(...) to do it [see http://www.scala-lang.org/api/current/index.html#scala.Option] myWebView.map(_.loadUrl("http://www.google.com/")) myTextView = Some(myView.findView(TR.id.my_textview)) //same as above myTextView.map(_.setText("Google.com")) myView } }
Espero que esto te ayude. No soy experto en Android, así que sólo puedo llegar tan lejos.
¿Por qué no escribes simplemente el fragmento en Scala sin molestarse en "la mejor manera de hacer esto en Scala" ? Puede que no haya ninguno.
Comenzaría con la eliminación de public
de la definición de clase e incluyendo las otras TypedActivity
– TypedActivity
del artículo – en la actividad. Luego, configure el entorno de desarrollo – el IDE – y ejecute la aplicación. Si funciona, ya está terminado (con el primer paso en la migración). No creo que necesites lazy val
desde el principio.
Haga pequeños pasos para que la migración sea más fácil.
- Cambiar la posición de TextView dinámicamente usando java en RelativeLayout android
- El uso de preferencias compartidas para el inicio de sesión persistente, ¿es esa vulnerabilidad?