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

私は常にこの基本構造を持っています: でインスタンス化しonCreateView、いくつかのことを行い、ビューを返すいくつかのプライベート UI 要素 (ここには示されていません: 他の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
  }
}

では、ここで何を改善できますか?この Fragment でいくつかのメソッドにアクセスする必要myTextViewがあるためです。private varここで説明されていることはできないようです: http://blog.andresteingress.com/2011/09/20/programming-android-with-scala/ withlazy val TypedActivityと暗黙の変換OnClickListener、私はフラグメントを使用しているためです。では、ボイラープレート コードを削除し.asInstanceOf[T]て、より Scala に近づけるにはどうすればよいでしょうか?

4

2 に答える 2

4

更新されたコードに基づいて、より「スケーラ風」になるように提案することしかできません


メンバー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
  }
}

これがお役に立てば幸いです。私はアンドロイドの専門家ではないので、ここまでしかできません。

于 2013-03-11T16:40:51.920 に答える
2

「Scala でこれを行う最善の方法」を気にせずに、単純に Scala でフラグメントを記述してみませんか? ないかもしれません。

クラス定義から削除publicし、他のグッズ (TypedActivity記事から) をアクティビティに含めることから始めます。次に、開発環境 (IDE) をセットアップし、アプリケーションを実行します。それが機能する場合は、完了です (移行の最初のステップで)。lazy val最初から 's は必要ないと思います。

移行が容易になるように、小さな手順を実行します。

于 2013-03-04T04:03:18.943 に答える