3

我有一个想要更改为 Scala 的 Java Android 应用程序。我有很多片段,我想知道在 Scala 中执行此操作的最佳方法是什么。

这是我的 Java 片段类MyFragment

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;
    }
}

我总是有这个基本结构:我在其中实例化的一些私有 UI 元素onCreateView,做一些事情并返回视图(此处未显示:在其他on*方法中,我也对 UI 元素执行一些操作)。

我发现了一些lazy val与此处描述的类似的文章:http: //blog.andresteingress.com/2011/09/20/programming-android-with-scala/ 但就我而言,这不起作用,因为我有片段和不是活动。首先我必须给主视图充气myView,然后我才能得到它的 UI 元素。

在 Scala 中执行此操作的最佳方法是什么?

- - 更新 - -

我的 Scala 代码现在看起来像这样:

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
  }
}

那么,我可以在这里改进什么?myTextViewprivate var因为我必须在这个 Fragment 中访问它的几个方法。似乎我不能做这里解释的东西:http: //blog.andresteingress.com/2011/09/20/programming-android-with-scala/lazy val TypedActivity隐式转换OnClickListener,因为我使用片段。那么如何摆脱样板代码.asInstanceOf[T]并使其更像 Scala 呢?

4

2 回答 2

4

根据您更新的代码,我只能提出一些更“scala-ish”的建议


使用Option而不是null为您的成员

private var myWebView: Option[WebView] = None
private var myTextView: Option[TextView] = None

为了避免在代码中显式转换您的视图,您需要将其移至其他位置,但您不能摆脱它,因为原始的 android API 不会为您提供有关返回对象的运行时或编译时类型的任何线索. 为了克服这个问题,您提到的帖子使用了定制的类型化资源和处理这些类型的特征。

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 }
}

现在我们可以使用上面的代码

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")

把这两件事放在一起

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
  }
}

我希望这能够帮到你。我不是android专家,所以我只能做到这一点。

于 2013-03-11T16:40:51.920 回答
2

您为什么不简单地在 Scala 中编写片段而不用担心“在 Scala 中执行此操作的最佳方式”?可能没有。

public将从类定义中删除并TypedActivity在活动中包括其他好东西 - 从文章中开始。然后,设置开发环境 - IDE - 并运行应用程序。如果它有效,那么您就完成了(迁移的第一步)。我认为你lazy val从一开始就不需要 's 。

做一些小步骤,使迁移更容易。

于 2013-03-04T04:03:18.943 回答