前一段时间写了一个在Android中加入AdMob的博客,详见http://my.oschina.net/noahxiao/blog/61987
还有一个用Scala开发Android应用-使用trait与implicit优化Activity,详见http://my.oschina.net/noahxiao/blog/61720
首先说明一下,我在android下是采用scala语言开发的。并不想讨论太多语言的好坏。只是把我开发时的经验与大家分享一下。
class ScalaAndroidActivity extends Activity with AdMobAdvertising with TestDataSource1 with TestDataSource2
大家先不要晕scala语言的继承关系是可以这样写的。with...
1、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这个方法就可以了。来看看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
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就可以了。
是不是看上去很干净
当然如果你的adUnitId号是变动的也可以override掉,在Activity中加入如下代码
override def adUnitId="xxxxxxxxxxxxxxxx"
2、trait BaseDataSource
在做完上面的模式后我在想,是不是访问sqlite数据时也可以这样来写呢
我们先看看BaseDataSource
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,这个目前本身没什么特点。
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())
后台打印结果如下