Scala&Android下的開發trait經驗分享

前一段時間寫了一個在Android中加入AdMob的博客,詳見http://my.oschina.net/noahxiao/blog/61987android

還有一個用Scala開發Android應用-使用trait與implicit優化Activity,詳見http://my.oschina.net/noahxiao/blog/61720sql

首先說明一下,我在android下是採用scala語言開發的。並不想討論太多語言的好壞。只是把我開發時的經驗與你們分享一下。數據庫

class ScalaAndroidActivity extends Activity with AdMobAdvertising with TestDataSource1 with TestDataSource2

你們先不要暈scala語言的繼承關係是能夠這樣寫的。with...

一、trait AdMobAdvertising

package org.noahx.common

import FindView._
import android.app.Activity
import android.widget.LinearLayout
import com.google.ads.AdView
import com.google.ads.AdSize
import com.google.ads.AdRequest
import android.os.Bundle

trait AdMobAdvertising extends Activity with FindView {

  def adLinearLayout: LinearLayout
  
  def adUnitId:String="a14xxxxxxxxxx"

  lazy val adView = new AdView(this, AdSize.BANNER, adUnitId)

  override def onCreate(savedInstanceState: Bundle) = {
    super.onCreate(savedInstanceState)

    adLinearLayout.addView(adView)
    adView.loadAd(new AdRequest())
  }

  override def onDestroy() = {
    if (adView != null) {
      adView.destroy()
    }
    super.onDestroy()
  }

}

以上就是我寫的trait,這樣咱們能夠不用太多考慮AdMob自己,只要實現adLinearLayout這個方法就能夠了。來看看Activityapp

package org.noahx.scalaandroid

import android.app.Activity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.view.View
import org.noahx.common.FindView._
import android.widget.LinearLayout
import com.google.ads.AdView
import com.google.ads.AdSize
import com.google.ads.AdRequest
import org.noahx.common.AdMobAdvertising

class ScalaAndroidActivity extends Activity with AdMobAdvertising {

  lazy val text = findView[TextView](R.id.text1)
  lazy val button = findView[Button](R.id.button1)

  override def adLinearLayout = findView[LinearLayout](R.id.adLinearLayout) //注意這裏決定AdMob放在哪一個LinearLayout中

  override def onCreate(savedInstanceState: Bundle) = {
    setContentView(R.layout.main)  //這個要放在super以前

    super.onCreate(savedInstanceState)

    button.onClick { view: View =>
      text.setText("hello scala1!!!")
    }

  }

}

用這樣一個AdMobAdvertising的trait只要在想加入AdMob的Activity中with一下,指定一個LinearLayout就能夠了。ide

是否是看上去很乾淨優化

固然若是你的adUnitId號是變更的也能夠override掉,在Activity中加入以下代碼this

override def adUnitId="xxxxxxxxxxxxxxxx"

  

二、trait BaseDataSource

在作完上面的模式後我在想,是否是訪問sqlite數據時也能夠這樣來寫呢google

咱們先看看BaseDataSource.net

package org.noahx.common

import android.app.Activity
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.os.Bundle

trait BaseDataSource extends Activity {

  def getSQLiteOpenHelper(): SQLiteOpenHelper

  val sqliteOpenHelper = getSQLiteOpenHelper()

  var database: SQLiteDatabase = null
  
  def getDatabase()=database

  private def open() = {
    database = sqliteOpenHelper.getWritableDatabase()
  }

  private def close() = {
    database.close()
  }

  override def onCreate(savedInstanceState: Bundle) = {
    super.onCreate(savedInstanceState)
    open()
  }

  override def onResume() = {
    open()
    super.onResume()
  }

  override def onPause() {
    close()
    super.onPause()
  }

  override def onDestroy() = {
    close()
    super.onDestroy()
  }

}

咱們能夠看到這個也是繼承Activity,裏面已經定義好了什麼時候建立鏈接,什麼時候關閉鏈接。缺乏的只是getSQLiteOpenHelper沒有實現

下面咱們來看看SQLiteOpenHelper,這個目前自己沒什麼特色。scala

package org.noahx.scalaandroid
import android.database.sqlite.SQLiteOpenHelper
import android.database.sqlite.SQLiteDatabase.CursorFactory
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.util.Log

class TestSQLiteOpenHelper(context: Context, dbName: String, cFactory: CursorFactory, ver: Int) extends SQLiteOpenHelper(context: Context, dbName: String, cFactory: CursorFactory, ver: Int) {

  val databaseCreateTest1 = "create table test1 (id integer primary key autoincrement, name text not null)"

  val databaseCreateTest2 = "create table test2 (id integer primary key autoincrement, name text not null)"

  def this(context: Context) = {
    this(context, "test.db", null, 1)
  }

  override def onCreate(database: SQLiteDatabase) = {
    database.execSQL(databaseCreateTest1)
    database.execSQL(databaseCreateTest2)
  }

  override def onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) = {
    Log.w(classOf[TestSQLiteOpenHelper].getName(), "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data")
    db.execSQL("DROP TABLE IF EXISTS " + "test1")
    db.execSQL("DROP TABLE IF EXISTS " + "test2")
    onCreate(db)

  }
}

下面咱們要基於BaseDataSource寫本身的DataSource了,這纔是重點

(scala語言的定義與文件名無關,能夠一個.scala文件中寫多個class,trait,object,甚至所有程序寫一個.scala文件中)

package org.noahx.scalaandroid

import org.noahx.common.BaseDataSource
import scala.collection.mutable.ListBuffer
import android.content.ContentValues

trait TestBaseDataSource extends BaseDataSource {

  def getSQLiteOpenHelper() = new TestSQLiteOpenHelper(this)

}

trait TestDataSource1 extends TestBaseDataSource {
  private val tableName = "test1"

  def createTest1(name: String) = {
    val values = new ContentValues()
    values.put("name", name)
    val insertId = database.insert(tableName, null, values)
  }

  def getTest1s(): List[String] = {
    var words = new ListBuffer[String]

    val cursor = database.query(tableName, Array("name"), null, null, null, null, null)

    cursor.moveToFirst()
    while (!cursor.isAfterLast()) {
      words += cursor.getString(0)
      cursor.moveToNext()
    }
    cursor.close()

    words.toList
  }
}

trait TestDataSource2 extends TestBaseDataSource {
  private val tableName = "test2"

  def createTest2(name: String) = {
    val values = new ContentValues()
    values.put("name", name)
    val insertId = database.insert(tableName, null, values)
  }

  def getTest2s(): List[String] = {
    var words = new ListBuffer[String]

    val cursor = database.query(tableName, Array("name"), null, null, null, null, null)

    cursor.moveToFirst()
    while (!cursor.isAfterLast()) {
      words += cursor.getString(0)
      cursor.moveToNext()
    }
    cursor.close()

    words.toList
  }
}

首先定義了TestBaseDataSource來統一設置helper,而後TestDataSource1與TestDataSource2就能夠直接使用database這個對象了

來看看最終的Activity吧

package org.noahx.scalaandroid

import android.app.Activity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.view.View
import org.noahx.common.FindView._
import android.widget.LinearLayout
import com.google.ads.AdView
import com.google.ads.AdSize
import com.google.ads.AdRequest
import org.noahx.common.AdMobAdvertising
import android.util.Log

class ScalaAndroidActivity extends Activity with AdMobAdvertising with TestDataSource1 with TestDataSource2 {

  lazy val text = findView[TextView](R.id.text1)
  lazy val button = findView[Button](R.id.button1)
  
  override def adLinearLayout = findView[LinearLayout](R.id.adLinearLayout)

  override def onCreate(savedInstanceState: Bundle) = {
    setContentView(R.layout.main)

    super.onCreate(savedInstanceState)
    
    for(i <-0 to 10){
      createTest1("test1."+i)
      createTest2("test2."+i)
    }

    button.onClick { view: View =>
      text.setText("hello scala!!!")
      
      Log.i(classOf[ScalaAndroidActivity].getName(),getTest1s().toString())
      Log.i(classOf[ScalaAndroidActivity].getName(),getTest2s().toString())
    }

  }

}

這樣的效果就是若是哪一個Activity想用TestDataSource1,就直接加到父行爲中,並在這個Activity中能夠直接調用如:createTest1這樣的方法直接操做數據庫

由如下代碼來寫數據庫

for(i <-0 to 10){
      createTest1("test1."+i)
      createTest2("test2."+i)
    }

onClick時由Log輸出結果

Log.i(classOf[ScalaAndroidActivity].getName(),getTest1s().toString())
      Log.i(classOf[ScalaAndroidActivity].getName(),getTest2s().toString())

後臺打印結果以下

相關文章
相關標籤/搜索