# 頁面跳轉
要記得先setOnclickLisnter
在寫入code
注意是第二頁是用新增Activity不是layout
```
val intent = Intent(this,頁面名稱::class.java)
startActivity(intent)
```
# 登入系統實作
第一步:創建kotlin/class 並命名DBHelper
第二步:在class DBHelper後加上
(context: Context):SQLiteOpenHelper(context,"Userdata",null,1)
按alt + enter會自動新增onCreate跟onUpgrade
第三步在onCreate及onUpgrade打入以下code
```
override fun onCreate(p0: SQLiteDatabase?) {
p0?.execSQL("create table Userdata
(username TEXT primary key,password TEXT)")
}
override fun onUpgrade
(p0: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
p0?.execSQL("drop table if exists Userdata")
}
```
第四步建立insertData(功能=將帳號及密碼存入Userdata中)
```
fun insertdata(username: String,password:String): Boolean {
val p0 =this.writableDatabase
val cv =ContentValues()
cv.put("username",username)
cv.put("password",password)
val result =p0.insert("Userdata",null,cv)
if (result==-1.toLong()){
return false
}
return true
}
```
第五步建立checkserpass(查詢帳密是否在資料庫內)
```
fun checkserpass(username: String,password: String): Boolean {
val p0 = this.writableDatabase
val query ="select * from Userdata where username
='$username'and password ='$password'"
val cursor = p0.rawQuery(query,null)
if (cursor.count<=0){
cursor.close()
return false
}
cursor.close()
return true
}
```
再來回到XML檔,新增一個登入 一個註冊 一個為登入後的頁面
先做註冊,拉3個EDITTEXT 一個是帳號一個是密碼,一個是再次輸入密碼
注意!!!!!每個edittext都要設定id
```
private lateinit var uname: EditText
private lateinit var pword : EditText
private lateinit var cpword:EditText
private lateinit var signupbtn:Button
private lateinit var db:DBHelper
private lateinit var ftvtn:FloatingActionButton
先宣告每個button及edittext跟資料庫
---
class signupActivity : AppCompatActivity() {
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup)
uname =findViewById(R.id.editTextpersonname)
pword =findViewById(R.id.editTextpersonPassword1)
cpword =findViewById(R.id.editTextpersonPassword2)
db= DBHelper(this)
ftvtn=findViewById(R.id.floatingActionButton3)
signupbtn=findViewById(R.id.button2)
signupbtn.setOnClickListener{
val unametext = uname.text.toString()
val pwordtext = pword.text.toString()
val cpwordtext = cpword.text.toString()
val savedata = db.insertdata(unametext,pwordtext)
findviewbyid每個變數名稱
並將edittext的值傳為字串
---
if (TextUtils.isEmpty(unametext)||TextUtils.isEmpty(pwordtext)||TextUtils.isEmpty(cpwordtext)){
Toast.makeText(this,"Add username password & confirmpassword",Toast.LENGTH_SHORT).show()
//當帳號或密碼其中之一為空,
創建toast訊息 add username password& confirmpassword
}else{if (pwordtext==cpwordtext){
if (savedata==true){
Toast.makeText(this,"signup successful",Toast.LENGTH_SHORT).show()
//當密碼等於再次輸入密碼顯示登入成功並跳轉到登入頁面
val intent =Intent(this,loginActivity::class.java)
startActivity(intent)
}
else{
Toast.makeText(this,"user exists",Toast.LENGTH_SHORT).show()
}
}
else{
Toast.makeText
(this,"password not match",Toast.LENGTH_SHORT).show()
}
}
}
ftvtn.setOnClickListener{
val intent =Intent(this,MainActivity::class.java)
startActivity(intent) //返回button
}
}
}
---
```
再來做登入頁面
拉兩個edittext並給其id
```
private lateinit var loginbtn:Button
private lateinit var edituser: EditText
private lateinit var editpword: EditText
private lateinit var dbh:DBHelper
private lateinit var ftbtn: FloatingActionButton **//宣告名稱及其對應物件**
class loginActivity : AppCompatActivity() {
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
loginbtn = findViewById(R.id.button)
edituser =findViewById(R.id.editTextText2)
editpword = findViewById(R.id.editTextTextPassword2)
dbh = DBHelper(this)
ftbtn =findViewById(R.id.floatingActionButton)
loginbtn.setOnClickListener{
val useredtx = edituser.text.toString()
val passedtx = editpword.text.toString()
將每個名稱對到各自id並將輸入方塊的值轉為字串
---
if(TextUtils.isEmpty(useredtx)||TextUtils.isEmpty(passedtx))
{Toast.makeText
(this,"please enter username and password",Toast.LENGTH_SHORT).show()
當輸入方塊其中之一為空顯示please enter username and password
}
else{
val checkuser = dbh.checkserpass(useredtx,passedtx)
使用dbhelper的checkserpass功能去將輸入值與資料庫比對
if (checkuser==true){ Toast.makeText
(this,"login successful",Toast.LENGTH_SHORT).show()
val intent =Intent(this,AfterenterActivity::class.java)
startActivity(intent)
}
else{
Toast.makeText
(this,"wrong username or password",Toast.LENGTH_SHORT).show()
}
}
}
ftbtn.setOnClickListener{
val intent =Intent(this,MainActivity::class.java)
startActivity(intent)
}
}
}
```
# Drawer
在 Android Studio 中使用 Kotlin 創建 Drawer(抽屜)的一般步驟包括:
創建一個新的專案:
開啟 Android Studio,選擇 "Start a new Android Studio project",並按照提示填寫應用程式的名稱、套件名稱等資訊。
選擇 Activity 樣板:
在 "Phone and Tablet" 中選擇 "Empty Activity" 或 "Navigation Drawer Activity",點擊 "Finish"。
設計佈局檔(layout):
在 res/layout 資料夾中找到 activity_main.xml,這是主活動的佈局。通常,使用 DrawerLayout 作為根元素,內含 NavigationView 和主要內容的 FrameLayout。
例如,一個簡單的 activity_main.xml 可能如下所示:
```
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- 主要內容區域 -->
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="?android:attr/actionBarSize" />
<!-- Drawer 抽屜 -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/nav_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
```
設計 Drawer 內容:
在 res/menu 資料夾中建立 nav_menu.xml,定義 Drawer 中的選單項目。
在 res/layout 資料夾中建立 nav_header_main.xml,定義 Drawer 的標頭(可選)。
在 MainActivity 中處理 Drawer:
在 MainActivity.kt 中設置 Drawer 相關的邏輯,包括 Drawer 的開啟、關閉,以及選單項目的點擊事件。
```
import android.os.Bundle
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.drawerlayout.widget.DrawerLayout
import com.google.android.material.navigation.NavigationView
class MainActivity : AppCompatActivity() {
private lateinit var drawerLayout: DrawerLayout
private lateinit var navView: NavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
drawerLayout = findViewById(R.id.drawer_layout)
navView = findViewById(R.id.nav_view)
// 建立 ActionBarDrawerToggle 並設置 DrawerLayout
val toggle = ActionBarDrawerToggle(
this, drawerLayout, R.string.navigation_drawer_open,
R.string.navigation_drawer_close
)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
// 處理 NavigationView 中的選單項目點擊事件
navView.setNavigationItemSelectedListener { menuItem ->
when (menuItem.itemId) {
R.id.nav_item1 -> {
// 處理選單項目1的點擊事件
true
}
R.id.nav_item2 -> {
// 處理選單項目2的點擊事件
true
}
else -> false
}
}
}
}
```
上述程式碼中,ActionBarDrawerToggle 負責與 ActionBar 連動,setNavigationItemSelectedListener 處理 NavigationView 中選單項目的點擊事件。
這是一個簡單的 Drawer 的建立過程。你可以根據自己的需求進一步自定義 Drawer 的內容和行為。
# Splash screen
在Android Studio中使用Kotlin创建一个Splash Screen(启动屏)是相对简单的。以下是一个简单的示例,帮助你创建一个基本的Splash Screen:
打开Android Studio,创建一个新的Kotlin项目。
在res/layout文件夹中创建一个新的XML文件,命名为activity_splash.xml,并添加以下内容:
```
<!-- res/layout/activity_splash.xml -->
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".SplashActivity">
<!-- Add your splash screen content here, such as logo, text, etc. -->
</RelativeLayout>
```
在layout中加入splash screen要顯示之畫面
建立一個splash Activity並設置timer3秒後intent回主畫面
```
// src/main/java/com/yourpackage/SplashActivity.kt
package com.yourpackage
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
class SplashActivity : AppCompatActivity() {
private val SPLASH_TIME_OUT: Long = 3000 // 设置启动屏展示时间,单位为毫秒
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
Handler().postDelayed({
// 在延时后启动主Activity
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
// 关闭当前Activity
finish()
}, SPLASH_TIME_OUT)
}
}
```
修改AndroidManifest.xml文件,把splash Activity設為啟動Activity:
```
<activity android:name=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
```
# Json檔讀取及寫入
先創名為Assets的資料夾並存入json檔
並在MainActivity中 onCreate中寫入read_json()
並創建funtcion read_json()
並定義json為String給予預設值null
在class後先宣告arr及type
```
var arr = arrayListOf<String>()
var type = arrListOf<String>()
```
```
val json :String?=null
try{
val inputStream : InputStream = assets.open("json檔檔名")
json = inputStream.bufferedReader().use(it.readText())
var jsonarr = JSONArray(json)
for(i in 0...jsonarr.length()-1)
{
var jsonobj = jsonarr.getJSONObject(i)
arr.add(jsonobj.getString("name")) //將json檔中的name部分做顯示
type.add(jsonobj.getString("type"))//將json檔中的type部分做顯示
}
var adpt=
ArrayAdapter(this,android.R.layout.simple_list_item_1,arr)
//Apapter(適配器)
json_list.adapter =adpt
json_list.onItemClickListener
= AdapterView.OnItemClickListener(parent, view ,position, id
-> Toast.makeText(applicationContext,"Type Slected is"
+ type[position],toast.length_long).show()
//當listview被按下時顯示該陣列中的type
}
catch(e : IOException){ //json_text為=Listview的id
json_text.text = json
}
```
# Spinner
在activity中寫入spinner元件
```
<Spinner
android:id="@+id/spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@android:layout/simple_spinner_item" />
```
並在onCreate中將選項存入languages中
```
val languages = arrayOf("英语", "西班牙语", "法语", "德语", "意大利语")
```
建立一個adapter用來填充Spinner
```
val adapter = ArrayAdapter<String>
(this, android.R.layout.simple_spinner_item, languages)
```
將適配器設為Spinner
```
spinner.adapter = adapter
```
設置點擊監聽器onSlectedlinster
```
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
val selectedItem = parent.getItemAtPosition(position) as String
Toast.makeText(this@MainActivity, "选择的项目:$selectedItem", Toast.LENGTH_SHORT).show()
}
override fun onNothingSelected(parent: AdapterView<*>) {
// Do nothing
}
}
```
full code
```
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val languages = arrayOf("英语", "西班牙语", "法语", "德语", "意大利语")
val adapter = ArrayAdapter<String>
(this, android.R.layout.simple_spinner_item, languages)
spinner.adapter = adapter
spinner.onItemSelectedListener
= object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>,
view: View, position: Int, id: Long) {
val selectedItem = parent.getItemAtPosition(position) as String
Toast.makeText(this@MainActivity, "选择的项目:$selectedItem",
Toast.LENGTH_SHORT).show()
}
override fun onNothingSelected(parent: AdapterView<*>) {
// Do nothing
}
}
}
}
```
# 限制EditText的輸入格式(手機號碼)
首先先宣告editText並findviewById到對應物件的id
並設置輸入監聽系統
```
editText.addTextChanged
(object: TextWatcher{
override fun beforeTextChanged
(s: CharSequence?, start: Int, count:Int, after :Int){
}
override fun onTextChanged
(s: CharSequence?,start: Int,before: int, count:Int){
}
override funafterTextChanged(s: Editable?) {
// 在文本变化之后执行的操作
val phoneNumberPattern
= Regex("^09\\d{2}-\\d{3}-\\d{3}$")
if (s != null && !s.toString().matches(phoneNumberPattern)) {
// 如果不符合指定的手机号格式,显示错误消息
editText.error = "请输入正确的手机号格式(例如:09XX-XXX-XXX)"
} else {
// 如果符合格式,清除错误消息
editText.error = null
}
})
```
# RecyclerView

先加入recyclerView的implementation
```
implementation
("androidx.recyclerview:recyclerview:1.3.2")
implementation
("androidx.recyclerview:recyclerview-selection:1.1.0")
```
建立dataModel.kt
```
data class Item(val name:String, val img:Int)
val myItemList = arrayListOf<item>()
for(i in 0..5){
myItemList.add(Item)("Wang,R.drawable.your_img")
}
```
建立一個layout檔
```
<ImageView
android:id"@+id/imgv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@drawable/xxxxxx"/>
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="30dp"
android:text="xxxxxx"/>
```
創建MyAdapter.kt
```
class MyAdapter:RecyclerView.Adapter<MyAdapter.mViewHolder>() {
var unAssignList = listOf<Item>()
inner class mViewHolder(itemView:View):RecyclerView.ViewHolder
(itemView){
//把layout檔的元件們拉進來,指派給當地變數
val icon = itemView.imgv
val name = itemView.tv_name
fun bind(item: Item){
//綁定當地變數與dataModel中的每個值
icon.setImageResource(item.img)
name01.text = item.name
}
}
override fun onCreateViewHolder(parent:ViewGroup,viewType: Int)
:mViewHolder {
//載入項目模板
val inflater = LayoutInflater.from(parent.context)
val example = inflater.inflate(R.layout.item_example,
parent, false)
return mViewHolder(example)
}
override fun getItemCount() = unAssignList.size
override fun onBindViewHolder(holder: mViewHolder, position: Int)
{
//呼叫上面的bind方法來綁定資料
holder.bind(unAssignList[position])
}
//更新資料用
fun updateList(list:ArrayList<Movement>){
unAssignList = list
}
}
```
在layout中放入recyclerview
```
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/r_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
```
```
class MainActivity : AppCompatActivity() {
val mAdapter = MyAdapter()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAdapter.updateList(myItemList) //傳入資料
r_view.layoutManager = LinearLayoutManager(this)
r_view.adapter = mAdapter
}
```
# viewpager with json
先建立一個view_layout作為模板
我們主要是透過更改view_layout中的textview來實現換頁資訊也跟著換的效果

接這建立adapter但要注意adapter的類型是recyclerview的
接者照recyclerview adapter的格式
```
class MyAdapter(private val dataList: List<String>, private val context: Context) :
RecyclerView.Adapter<MyAdapter.ViewHolder>() {
// 创建 ViewHolder,用于保存视图引用
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textView: TextView = itemView.findViewById(R.id.textView)
}
// 创建新的 ViewHolder 实例
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.item_layout, parent, false)
return ViewHolder(view)
}
// 将数据绑定到 ViewHolder 上
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val data = dataList[position]
holder.textView.text = data
}
// 返回数据集的大小
override fun getItemCount(): Int {
return dataList.size
}
}
```
需修改的地方為datafile的地方改成data class的最外層
onCreatViewHolder的layoutInflater中的layout改成view_layout
getItemCount內放data class中的第一個list的size並return
需而外創建inner class ViewHolder
```
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textView1: TextView = itemView.findViewById(R.id.where)
val textView2: TextView=itemView.findViewById(R.id.feel)
val textView3: TextView=itemView.findViewById(R.id.max)
val textView4: TextView=itemView.findViewById(R.id.min)
val textView5: TextView =itemView.findViewById(R.id.Start)
val textView6: TextView=itemView.findViewById(R.id.End)
}
```
裡面要放你要做變更的物件(要findviewbyid)
在onbindViewHolder加入holder.apply
放入物件要更改成的東西
並在要做讓陣列中會做變更的數字換成position
## 主頁面
```
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val jsonfile = assets.open("Weather.json").bufferedReader().use { it.readText() }
val datafile = Gson().fromJson(jsonfile, weather::class.java)
Log.d("aha", datafile.cwaopendata.dataset.location[0].locationName!!)
val viewPager = findViewById<ViewPager2>(R.id.viewpager)
viewPager.adapter = MyPagerAdapter(this, datafile)
}
}
```
# Map套件
先在layout畫面中放置一個Mapview套件
並定義mapView(findviewByid)
设置应用程序的用户代理值
Configuration.getInstance().userAgentValue = "your_app_name"
設置一個ConnectView到Activity_main
// 设置地图图层为 MAPNIK
mapView.setTileSource(TileSourceFactory.MAPNIK)
// 设置初始的经纬度坐标
val initialLatLong = GeoPoint(37.7749, -122.4194)
// 将地图中心设置为初始经纬度
mapView.controller.setCenter(initialLatLong)
// 设置初始缩放级别
mapView.controller.setZoom(12.0)
# Room
## 定義data class
```
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
val age: Int
)
```
## 建立Dao
```
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<User>
@Insert
fun insert(user: User)
@Query("DELETE FROM users")
fun deleteAll()
}
```
## 建立資料庫
```
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
```
## 初始化
```
import androidx.room.Room
import android.content.Context
class MyApp : Application() {
companion object {
lateinit var database: AppDatabase
}
override fun onCreate() {
super.onCreate()
database = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "my-database"
).build()
}
}
```
## 使用
```
val userDao = MyApp.database.userDao()
// 插入用户
val user = User(1, "John", 30)
userDao.insert(user)
// 获取所有用户
val users = userDao.getAll()
```
# xml解析
先建立一個Class 並宣告其形態
```
Class horly(hous:String, temp :int,picpath:String){
privare var hours:String=""
private var temp:int =0
private var pucpath: String=""
init{
this.hours=hours
this.temp=temp
this.picpath=picpath
}
fun getHours():String{
return hours
}
fun sethours(hours:String){
this.hours=hours
}
}
以此類推
```
並在mainActivity寫入
```
fun parserXal(): ArrayList<Hourly> {
val items: ArrayList<Hourly> = ArrayList()
val parser = resources.getXml(R.xml.weather_xml)
var eventType = parser.eventType
var myIndex = -1
while (eventType != XmlResourceParser.END_DOCUMENT) {
if (eventType == XmlResourceParser.START_TAG) {
val tagName = parser.name
when (tagName) {
"element" -> {
items.add(Hourly("", 0, ""))
myIndex++
}
"temp" -> {
parser.next()
items[myIndex].setTemp(parser.text.toInt())
parser.next()
}
"hours" -> {
parser.next()
items[myIndex].setHours(parser.text)
parser.next()
}
"pic" -> {
parser.next()
items[myIndex].setPicPath(parser.text)
parser.next()
}
}
}
eventType = parser.next()
}
return items
}
```
## 在recyclerview中的範例
```
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import coil.load
import com.example.xnlparser.domain.Hourly
import com.example.xml.parser.R
class HourlyAdapter(private var items: ArrayList<Hourly>) : RecyclerView.Adapter<HourlyAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val hourtext: TextView = view.findViewById(R.id.hourtext)
val image: ImageView = view.findViewById(R.id.imageView)
val degrees: TextView = view.findViewById(R.id.degrees)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.viewholder_hourly, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val data = items.get(position)
holder.hourtext.text = data.getHours()
holder.degrees.text = data.getTemp().toString() + "°"
val drawableId = holder.itemView.resources.getIdentifier(data.getPicPath(), "drawable", holder.itemView.context.packageName)
holder.image.load(drawableId)
}
override fun getItemCount(): Int {
return items.size
}
}
```
```
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.osmdroid.config.Configuration
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.MapView
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
class MainActivity : AppCompatActivity() {
private lateinit var mapView: MapView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Configuration.getInstance().userAgentValue = "yourapp_name"
setContentView(R.layout.activity_main)
mapView = findViewById(R.id.mapView)
mapView.setTileSource(TileSourceFactory.MAPNIK)
val fileName = "taiwanEMap6.mbtiles"
val file = File(getExternalFilesDir(null), fileName)
file.outputStream().use { assets.open(fileName).copyTo(it) }
val tileProvider = OfflineTileProvider(
SimpleRegisterReceiver(this@Mappage),
arrayOf(file)
)
mapId.tileProvider = tileProvider
val initialLatLong = GeoPoint(37.7749, -122.4194)
mapView.controller.setCenter(initialLatLong)
mapView.controller.setZoom(12.0)
}
override fun onDestroy() {
super.onDestroy()
mapView.onDetach()
}
}
```