前一段时间写了一个在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...
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"
在做完上面的模式后我在想,是不是访问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())
后台打印结果如下