Android studio:修订间差异

来自OSSmedia
第245行: 第245行:
==时间日期选择==  
==时间日期选择==  
<TimePicker  
<TimePicker  
android:id="@+id/ptime"  
android:id="@+id/ptime"
android:layout_width="310dp"  
 
android:layout_height="347dp"  
android:layout_width="310dp"
app:layout_constraintEnd_toEndOf="parent"  
 
app:layout_constraintStart_toStartOf="parent"  
android:layout_height="347dp"
 
app:layout_constraintEnd_toEndOf="parent"
 
app:layout_constraintStart_toStartOf="parent"
 
app:layout_constraintTop_toBottomOf="@+id/button2" />  
app:layout_constraintTop_toBottomOf="@+id/button2" />  
    
    
textView.setText(ptime.hour.toString()+":"+ptime.minute.toString())  
textView.setText(ptime.hour.toString()+":"+ptime.minute.toString())  
    
    
<DatePicker  
<DatePicker
android:id="@+id/pdate"  
 
android:layout_width="358dp"  
android:id="@+id/pdate"
android:layout_height="428dp"  
 
android:layout_marginTop="20dp"  
android:layout_width="358dp"
app:layout_constraintEnd_toEndOf="parent"  
 
app:layout_constraintHorizontal_bias="0.566"  
android:layout_height="428dp"
app:layout_constraintStart_toStartOf="parent"  
 
android:layout_marginTop="20dp"
 
app:layout_constraintEnd_toEndOf="parent"
 
app:layout_constraintHorizontal_bias="0.566"
 
app:layout_constraintStart_toStartOf="parent"
 
app:layout_constraintTop_toBottomOf="@+id/button2" />  
app:layout_constraintTop_toBottomOf="@+id/button2" />  
    
    

2024年3月14日 (四) 13:26的版本


项目中引用MPChartLib

1、 将MPChartLib文件夹拷贝到项目根目录

2、在根目录里的settings.gradle里增加include ':app', ':MPChartLib'

3、将文件MPChartLib.aar拷贝到libs文件夹里

4、在build.grade(app)中增加

dependencies { implementation project(':MPChartLib') }

设置app自动启动

增加权限

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

注册消息接收

<receiver android:name=".BootBroadcastReceiver">

<intent-filter>

<action android:name="android.intent.action.BOOT_COMPLETED" />

</intent-filter>

</receiver>

消息接收函数

class BootBroadcastReceiver: BroadcastReceiver() {

override public fun onReceive(context: Context, intent: Intent) {

val mBootIntent = Intent(context, MainActivity::class.java)

mBootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

context.startActivity(mBootIntent)

}

}

获取位置信息(kotlin)

val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

val location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)

If (location != null) {

val sb = StringBuffer()

sb.append('实时的位置信息:经度:')

sb.append(location.longitude) sb.append('纬度:')

sb.append(location.latitude) sb.append('高度:')

sb.append(location.altitude) sb.append('速度:')

sb.append(location.speed) sb.append('方向:')

sb.append(location.bearing) sb.append('精度:')

sb.append(location.accuracy)

Toast.makeText(applicationContext, sb.toString(), Toast.LENGTH_LONG).show() }

添加权限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

发送Notification消息(kotlin)

fun sendNotification(channel_id:String ,channle_name:String,nTitle:String,nContentText:String,id:Int){

var notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

var notification: Notification? = null

//val intent = Intent(Intent.ACTION_VIEW, Uri.parse('http://www.baidu.com/'))

//val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

//如需链接到网站使用注释代码

val intent = Intent()

intent.setClass(this@MainActivity, MainActivity::class.

val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

val mChannel = NotificationChannel(channel_id, channle_name, NotificationManager.IMPORTANCE_LOW) notificationManager.createNotificationChannel(mChannel)

notification = Notification.Builder(this) .setChannelId(channel_id) .setContentTitle(nTitle) .setContentText(nContentText)

.setContentIntent(pendingIntent) .setSmallIcon(R.drawable.house).build()

}

else {

val notificationBuilder = NotificationCompat.Builder(this)

.setContentTitle(nTitle)

.setContentText(nContentText)

.setSmallIcon(R.drawable.house)

.setOngoing(true)

//.setChannel(id)//无效

notification = notificationBuilder.build() }

notificationManager.notify(id, notification) }

禁止使用http链接解决方法

访问网络时报异常

Cleartext HTTP traffic to not permitted

在<application标签里增加android:usesCleartextTraffic="true"即可

bitmap缩小显示

var matrix = Matrix()

matrix.postScale(0.3f,0.3f)//长和宽放大缩小的比例

val resizeBmp = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true)

textview 连续左移

设置一下参数,自动连续左移动

android:ellipsize="marquee"

android:focusable="auto"

android:focusableInTouchMode="true"

android:marqueeRepeatLimit="marquee_forever"

android:scrollHorizontally="true"

android:singleLine="true"

useAndroidx Error

编译报错

This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled.

在gradle.propeties文件里增加如下语句,允许AnsiroidX

android.useAndroidX=true

post获取数据(kotlin)

Thread(Runnable {

val toMain1 = mAppMesHandler.obtainMessage()

toMain1.arg1 = 1

var conn: HttpURLConnection? = null

var urlString = "http://server/new.php"

try {

conn = URL(urlString).openConnection() as HttpURLConnection

conn.requestMethod = "POST" // 指定POST请求

conn.doOutput = true // 设置请求过程可以传递参数给服务器

// post请求参数

val param = String.format("name=%s&age=%s&action=%s", "fengxueyan", "23", "query") DataOutputStream(conn.outputStream).use { os ->

os.writeBytes(param)

}

conn.connect()

conn.inputStream.use { input ->

val data = input.bufferedReader().readText() toMain1.obj = data.toString()

}

}

catch (e: Exception) {

toMain1.obj = e.toString()

}

finally {

conn?.disconnect()

}

mAppMesHandler.sendMessage(toMain1) }).start()


//访问网络必须使用线程,而且线程不允许更新UI

val mAppMesHandler = object : Handler() {

override fun handleMessage(msg: Message) {

if(msg.arg1 == 1){

var hList0 = msg.obj as String textView.setText(hList0)

// Toast.makeText(applicationContext,hList0,Toast.LENGTH_LONG).show()

}

}

}

时间日期选择

<TimePicker android:id="@+id/ptime"

android:layout_width="310dp"

android:layout_height="347dp"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@+id/button2" />

textView.setText(ptime.hour.toString()+":"+ptime.minute.toString())

<DatePicker

android:id="@+id/pdate"

android:layout_width="358dp"

android:layout_height="428dp"

android:layout_marginTop="20dp"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintHorizontal_bias="0.566"

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toBottomOf="@+id/button2" />

textView.setText(pdate.year.toString()+"-"+(pdate.month+1).toString()+"-"+pdate.dayOfMonth.toString())

多个Fragment和Activity的简易数据交换方法(kotlin)

动态创建多个Fragment后,和Activity数据交换有很多种方式,消息方式简单快捷,代码量少

在Activity中定义消息处理 val mMainHandler = object : Handler() {

   override fun handleMessage(msg: Message) { 
       if (msg.arg1 == 1) { 
           val sVerRes = msg.obj as String 
           Toast.makeText(applicationContext, sVerRes, Toast.LENGTH_LONG).show() 
       } 
 

}


在Fragment里定义消息handle private var aHandle:Handler? = null


建立初始化函数,将Activity的消息handle传入 fun setHandler(AHandler: Handler?) {

   try {    
       aHandle = AHandler 
   } catch (e: Exception) { 
  throw ClassCastException(context.toString()  
   } 
 

}

Activity向Fragment传递数据直接定义函数 Fragment向Activity传递数据发送消息 val toMain1 = aHandle!!.obtainMessage() toMain1.obj = “message or data” toMain1.arg1 = 1

aHandle!!.sendMessage(toMain1)

实现扫码二维码(kotlin)

dependencies增加引用 implementation 'com.hongyelinggu:scancode:1.0.0'

申请相机权限 <uses-permission android:name="android.permission.CAMERA"/> val REQUEST_EXTERNAL_STORAGE = 1234 if (ActivityCompat.checkSelfPermission(this, "android.permission.CAMERA") != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_EXTERNAL_STORAGE) } else{

}

执行扫描 startActivityForResult(Intent(this@MainActivity, CommonScanActivity::class.java), 1)

返回结果字符串 override fun onActivityResult(requestCode:Int, resultCode:Int, data:Intent?){ super.onActivityResult(requestCode, resultCode, data) val rCode = data!!.extras!!.getString(Constant.REQUEST_SCAN_MODE) //得到新Activity关闭后返回的数据 Toast.makeText(applicationContext, rCode, Toast.LENGTH_LONG).show() }

读取写入文本文件(kotlin)

写入文件

val fn = filesDir.toString() + "文件名.txt" var fff = "文本内容" try { val tfw = FileWriter(fn) tfw.write(fff) tfw.close()

Toast.makeText(applicationContext, "保存成功", Toast.LENGTH_LONG).show() } catch (e: Exception) { Toast.makeText(applicationContext, e.toString(), Toast.LENGTH_LONG).show() }

读取文件 val fn = filesDir.toString() + "文件名.txt" try { val fb = FileReader(fn) val tv2:TextView = findViewById(R.id.textView2) tv2.setText(fb.readText()) //显示到TextView fb.close() } catch(e:Exception){ Toast.makeText(applicationContext, e.toString(), Toast.LENGTH_LONG).show() }

如果路径访问需要权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>

//获取sd卡读写权限 //val REQUEST_EXTERNAL_STORAGE = 1234 if (ActivityCompat.checkSelfPermission(this, "android.permission.WRITE_EXTERNAL_STORAGE") != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions(this, arrayOf(WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE), REQUEST_EXTERNAL_STORAGE) } else{

}

多项选择对话框 kotlin

val builder = AlertDialog.Builder(this) builder.setTitle("请选择") builder.setIcon(R.drawable.ic_launcher_foreground) builder.setCancelable(true)

val items = arrayOf("第一项", "第二项", "第三项") var selected = booleanArrayOf(true, false, true)


builder.setMultiChoiceItems(items, selected) { dialog, which, isChecked -> // dialog.dismiss(); // Toast.makeText(this@MainActivity, items[which] + isChecked, Toast.LENGTH_SHORT).show()

}

//此代码实现输入文本对话框 //val filename :EditText = EditText(this) //builder.setView(filename)

builder.setPositiveButton(" 确定发送 ") { dialogInterface, i -> val tw: TextView = findViewById(R.id.textView1) var sd = "" for (i in 0 until items.count()) { if (selected[i]) sd += items[i] } tw.setText(sd) Toast.makeText(this@MainActivity, sd, Toast.LENGTH_SHORT).show()

//tw.setText(filename.text.toString()) } builder.setNegativeButton("取消发送") { dialogInterface, i -> // finish()


} builder.show()

OptionsMenu kotlin

app 右键 new=》android resouce file resouce type 选择Menu 创建菜单项目,编辑ID和title //显示菜单 override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.mainmanu,menu) return true // return super.onCreateOptionsMenu(menu) } //处理菜单点击响应 override fun onOptionsItemSelected(item: MenuItem): Boolean {

if(item?.itemId == R.id.menu_exit){ finish() } if(item?.itemId == R.id.menu_upate){ Toast.makeText(this,"system update",Toast.LENGTH_LONG).show() }

return super.onOptionsItemSelected(item)

}

ContextMenu kotlin

app 右键 new=》android resouce file resouce type 选择Menu 创建菜单项目,编辑ID和title

override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) { 
super.onCreateContextMenu(menu, v, menuInfo) 
menuInflater.inflate(R.menu.menupop,menu) 
menu!!.setHeaderTitle("请选择")  
} 

重载函数

override fun onContextItemSelected(item: MenuItem): Boolean { 
   if(item.itemId == R.id.media_route_menu_item1){ 
   Toast.makeText(this,"11111111",Toast.LENGTH_LONG).show() 
 } 
 return super.onContextItemSelected(item) 
} 
 

onCreate

val bt_menu: Button = findViewById(R.id.button_menu) 
registerForContextMenu(bt_menu) 
bt_menu.setOnClickListener { 
openContextMenu(it) 
}

如果在list view item弹出菜单,直接

val tv_houseList = findViewById(R.id.listview_house_list) as ListView
registerForContextMenu(tv_houseList) 

这样长按item自动会弹出菜单

androidstudio使用WebView显示网页(kotlin)

val wset = wview1.settings
  wset.javaScriptEnabled = true
     wview1.setWebViewClient(object : WebViewClient() {
           override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
               view.loadUrl(url)
               return true
           }
       })
wview1.loadUrl(“http://www.baidu.com”)

在AndroidManifest.xml增加

android:usesCleartextTraffic="true"

需要添加网络权限

如果需要支持网页弹出alert:

wview1.setWebChromeClient (object : WebChromeClient() 
   override fun onJsAlert(view: WebView,url: String,message: String,result: JsResult):Boolean{
         return super.onJsAlert(view, url, message, result)
    }
 })

androidstudio使用viewPager显示多张图片并关联tabLayout(kotlin)

val mImgId = intArrayOf(R.drawable.h1, R.drawable.h2, R.drawable.h3)

    val mList = ArrayList()
   var tabName : Array = Array(3,{""})
      tabName[0] = "TAB1"
      tabName[1] = "TAB2"
      tabName[2] = "TAB3"
       vpage.setAdapter(object : PagerAdapter() {
          override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
            container.removeView(mList.get(position))
          }
          override fun instantiateItem(container: ViewGroup, position: Int): Any {
             val imageView = ImageView(this@MainActivity)
            imageView.setImageResource(mImgId[position])
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP)
            container.addView(imageView)
             mList.add(imageView)
             return imageView
          }
          override fun getCount(): Int {
             return mImgId.size
          }
          override fun isViewFromObject(view: View, `object`: Any): Boolean {
             return view === `object`
          }
          override fun getPageTitle(position:Int):CharSequence{
              return tabName[position]
          }
      })
      tabcus.setupWithViewPager(vpage)

使用ViewPager2和TabLayout实现多frgment切换

private fun initTab(){
       val viewpage = findViewById(R.id.viewpage2) as ViewPager2
       viewpage.adapter = object : FragmentStateAdapter(this){
           override fun getItemCount(): Int {
               return  3
           }
           override fun createFragment(position: Int): Fragment {
               return when(position){
                   0 -> myFragment()
                   1 -> hlistFragment()
                   else -> hlistFragment()
               }
           }
       }
       val tabmain = findViewById(R.id.tabLayout) as TabLayout
       TabLayoutMediator(
           tabmain,
           viewpage,
           object : TabLayoutMediator.TabConfigurationStrategy{
               override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
                   when(position){
                       0 -> tab.text = "资源汇总"
                       1 -> tab.text = "我的房源"
                       else -> tab.text = "房源资源库"
                   }
               }
           }).attach()

xml文件

<com.google.android.material.tabs.TabLayout
<androidx.viewpager2.widget.ViewPager2

建立Fragement list 用于访问每个动态创建的Fragment

var list_frm:ArrayList<Fragment> = ArrayList()
            override fun createFragment(position: Int): Fragment {
                when(position){
                   0 -> {
                       val fg =  myFragment()
                       list_frm.add(fg )
                       return fg
                   }
                   1 -> {
                       val fg =  hlistFragment()
                       list_frm.add(fg)
                       return fg
                   }
                   else -> {
                       val fg =  hlistFragment()
                       list_frm.add(fg)
                       return fg
                   }
               }
           }

使用BaseAdapter为listview装入数据

 class myAdapter (context: Activity,listValue:String): BaseAdapter(){
     private var ct:Activity
     private var lv:String
     init {
         ct = context
         lv = listValue
     }
     override fun getCount():Int{
         val hma_list = lv.split("^")
         return hma_list.count()
     }
     override fun getItem(position: Int):String{
         val hma_list = lv.split("^")
         return hma_list[position].toString()
     }
     override fun getItemId(position: Int):Long{
         return position.toLong()
     }
     override fun getView(position: Int, view: View?, parent: ViewGroup): View {
         val rowView = ct.layoutInflater.inflate(R.layout.layout_house_info_item, null, true)
         val hm_name = rowView.findViewById(R.id.tv_item_name) as TextView
         val hm_price = rowView.findViewById(R.id.tv_item_price) as TextView
         val hm_size = rowView.findViewById(R.id.tv_item_size) as TextView
         val hm_room = rowView.findViewById(R.id.tv_item_room) as TextView
         val hm_time = rowView.findViewById(R.id.tv_item_time) as TextView
         val hm_status = rowView.findViewById(R.id.tv_item_status) as TextView
         val hma_list = lv.split("^")
         var hma_value = hma_list[position].split("~")
         hm_name.text = hma_value[0]
         if(hma_value[12] == "2" )
             hm_price.text = hma_value[4]+"/月"
         else
             hm_price.text = hma_value[2]+"万"
         hm_size.text = hma_value[9] +"  "+ hma_value[1]+"平米"
         hm_room.text = hma_value[6]+"室"+hma_value[7]+"厅"+hma_value[8]+"卫    "+hma_value[5]+"层"
         hm_time.text = "最后跟进"+hma_value[11]
         return rowView
     }
 }

listview 操作

  val adapter = myAdapter(this,listStr)
  tv_houseList.setAdapter(adapter)

让EditText不能编辑,只读

 et_tel.keyListener = null

让WebView支持手机定位

静态申请权限

   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
   <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
   <uses-permission android:name="android.permission.ACCESS_GPS" />
   <uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
   <uses-permission android:name="android.permission.ACCESS_LOCATION" />

动态申请权限

   if (ActivityCompat.checkSelfPermission(this,
           "android.permission.WRITE_EXTERNAL_STORAGE") != PackageManager.PERMISSION_GRANTED ) {
           ActivityCompat.requestPermissions(this,
               arrayOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION), 1234)
       }

设置WebView参数

       val wview1 = findViewById(R.id.vview1) as WebView
       val wset = wview1.settings
       wset.javaScriptEnabled = true
       wset.setGeolocationEnabled(true)  //允许定位
       wview1.setWebViewClient(object : WebViewClient() {
           override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
               view.loadUrl(url)
               return true
           }
       })
       wview1.setWebChromeClient (object : WebChromeClient() {
           override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult):Boolean{
               return super.onJsAlert(view, url, message, result)
           }
           override fun onGeolocationPermissionsShowPrompt(
               origin: String?,
               callback: GeolocationPermissions.Callback?
           ) {
               val remember = true
               val builder: AlertDialog.Builder = AlertDialog.Builder(this@MainActivity)
               builder.setTitle("位置信息")
               builder.setMessage(origin + "允许获取您的地理位置信息吗?").setCancelable(true)
                           .setPositiveButton("允许",
                               DialogInterface.OnClickListener { dialog, id ->
                                   callback?.invoke(
                                       origin,
                                       true,
                                       remember
                                   )
                               })
                           .setNegativeButton("不允许",
                               DialogInterface.OnClickListener { dialog, id ->
                                   callback?.invoke(
                                       origin,
                                       false,
                                       remember
                                   )
                               })
                       val alert: AlertDialog = builder.create()
                       alert.show()
               }
           })