Android 开发中积累的知识点

Android 开发中积累的知识点

  • Android使用命令行查看命令行编译问题
查看详细错误描述
gradlew compileDebugJavaWithJavac 
gradlew compileDebug --stacktrace -info
gradlew compileDebugSources --stacktrace -info
  • 导航栏和状态栏

去除导航栏
在styles中修改主题


改为

状态栏半透明全透明设置

同样在在styles中设置
true



@android:color/transparent
  • 轮播组件
https://github.com/daimajia/AndroidImageSlider
  • Fragment

1、Fragment的创建

通过布局创建


必须设置对应的name:包名+Fragment类名
TopFragment中的设置
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_top, null)
        return view
    }
    
通过代码创建
val transation = supportFragmentManager.beginTransaction()
transation.add(R.id.fragment_top, TopFragment())
transation.commit()

2、Fragment的添加、替换、移除

// 添加
supportFragmentManager.beginTransaction().add(R.id.fragment_top, topFragment).commit()
// 删除
supportFragmentManager.beginTransaction().remove(topFragment).commit()
// 替换
supportFragmentManager.beginTransaction().replace(R.id.fragment_top, BottomFragment()).commit()

3、Fragment的生命周期

override fun onAttach(activity: Activity?) {}
override fun onCreate(savedInstanceState: Bundle?) {}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {}
override fun onActivityCreated(savedInstanceState: Bundle?) {}
override fun onStart() {}
override fun onResume() {}
override fun onPause() {}
override fun onStop() {}
override fun onDestroyView() {}
override fun onDestroy() {}
override fun onDetach() {}

4、Fragment和Activity通讯

在Activity中获取Fragment对其中的控件做处理
val topFragment = supportFragmentManager.findFragmentById(R.id.fragment_top)
val editView = topFragment?.view?.findViewById(R.id.edit_text)
editView?.text = "点击了${count}次按钮"

在Fragment中获取Activity中的控件做处理操作
val textView = activity?.findViewById(R.id.text_activity)
textView?.text = "修改成功"

通过设置监听处理事件,Fragment只负责发出事件,通知Activity处理
1.在Fragment中创建一个接口,提供一个接口方法
2.在Fragment中,设置activity为监听者,触发事件的时候调用接口方法,并传递参数
3.在Activity中实现接口方法,处理事件

5、利用Fragment搭建常用APP框架,切换Fragment的性能问题

利用add、replace切换Fragment的时候会导致Fragment重新初始化
解决办法:没有添加过的Fragment添加,添加过的利用显示和隐藏来控制

val transaction = supportFragmentManager.beginTransaction()
if (lastIndex >= 0) {
    val lastFragment = fragments[lastIndex]
    // 隐藏上一个Fragment
    transaction.hide(lastFragment)
}
val currentFragment = fragments[index]
// 是否添加过,没有就添加,否则显示
if (currentFragment.isAdded) {
    transaction.show(currentFragment)
} else {
    transaction.add(R.id.main_content, currentFragment)
}
transaction.commit()
lastIndex = index
  • EventBus 事件总线笔记

EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。

使用步骤:

发送消息:先注册,再发送消息
1、注册
EventBus.getDefault().register(this)
2、解注册
EventBus.getDefault().unregister(this)
3、构造消息类
class MessageEvent(name: String, msg: String) {
    var name: String = ""
    var message: String = ""
    init {
        this.name = name
        this.message = msg
    }
}
4、发送消息
EventBus.getDefault().post(MessageEvent("zhangsan", "发送消息"))
5、接收消息
@Subscribe(threadMode = ThreadMode.MAIN)
    public fun getEventMessage(event: MessageEvent) {
        event_bus_recive.text = "接收到event数据name = ${event.name} - msg = ${event.message}"
}
ThreadMode.MAIN 表示这个方法在主线程中执行
ThreadMode.BACKGROUND 表示该方法在后台执行,不能并发处理
ThreadMode.ASYNC 也表示在后台执行,可以异步并发处理。
ThreadMode.POSTING 表示该方法和消息发送方在同一个线程中执行

粘性事件:可以先发送消息,再注册
区别主要是发送和接收
发送粘性事件
EventBus.getDefault().postSticky(MessageEvent("王五", "发送粘性消息"))
接收粘性消息
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public fun getEventMessageSticky(event: MessageEvent) {
        event_bus_recive.text = "接收到粘性事件event数据name = ${event.name} - msg = ${event.message}"
}

源码分析流程:

注册源码流程
1、通过反射或注解获取所有的订阅方法
2、将当前订阅者添加到Eventbus总的事件订阅者的集合中
3、将当前订阅者所有订阅的事件类型添加到typeBySubscriber中
发送源码分析
1、得到要发送的事件类型
2、根据事件类型获取所有订阅者,并循环向每个订阅者发送。
解注册源码分析
1、通过typeBySubscriber获取当前订阅者所有的事件类型
2、循环遍历每一个事件类型,并删除当前订阅者的订阅的方法

参考
http://www.cnblogs.com/all88/archive/2016/03/30/5338412.html
  • 图片加载框架Picasso
val uri = Uri.parse(imageString)
Picasso.get().load(uri).into(image_view)

Picasso.get().load(uri).into(image_view, object: Callback {
    override fun onSuccess() {
        Log.e("Picasso", "onSuccess")
    }
    override fun onError(e: Exception?) {
        Log.e("Picasso", "onError e = ${e?.message}")
    }
})
  • 重命名打包配置
在gradle中的android节点配置
// westone_diskink_1.1.0.5_20190905_release
applicationVariants.all { variant ->
    variant.outputs.all {
        def date = new Date().format("yyyyMMdd" , TimeZone.getTimeZone("GMT+08"))
        def fileName = "westone_diskink_" + "${defaultConfig.versionName}_${date}_" + "release.apk"
        outputFileName = fileName
    }
}
  • 将工程制作成Module

1、在主工程中导入另一个项目工程
Android 开发中积累的知识点_第1张图片

2、修改module工程中的配置

1、build.gradle中
apply plugin: 'com.android.application' 修改为 apply plugin: 'com.android.library'
编译版本配置最好改为和主工程一致
2、AndroidManifest中去掉配置

        
        
 
 3、将Module中和主工程重名的资源都修改

3、添加Module依赖
打开Open Module Settings配置
Android 开发中积累的知识点_第2张图片

4、编译项目,在主工程中调用Module功能

? Module
companion object {
    fun launch(context: Context) {
        val intent = Intent()
        intent.setClass(context, MainActivity::class.java)
        startActivity(context, intent, null)
    }
}

主工程中启动该Activity
test.san.mymodule.MainActivity.launch(this)
  • 数据存储

Android数据存储的方式:
1、SharedPreference
2、手机内部存储
3、手机外部存储
4、Sqlite数据库存储
5、远程服务器存储

SharedPreference
存储位置
/data/data/packageName/shared_prefs/name.xml
特点:利用key-value的方式存储小数据

手机内部存储
存储位置
/data/data/packageName/files/文件
特点:1、存储较大的数据、图片 2、应用卸载时会自动删除此数据

// 读取文件
val inputStream = openFileInput("test.png")
// 保存文件
val outputStream = openFileOutput("put.png", Context.MODE_PRIVATE)
// 得到files文件夹对象
val file = filesDir
// 操作asserts下的文件
assets.open("test1.png")
// 加载图片文件
BitmapFactory.decodeFile("")

手机外部存储
存储位置
路径1:/storage/sdcard/Android/data/packageName/files/
路径2:/storage/sdcard/xxx/
特点:
路径1:其他应用可以访问,应用卸载时删除
路径2:其他应用可以访问,应用卸载时不会删除
相关API

// Environment
// 获取SD卡的状态
Environment.getExternalStorageState()
// 获取SD卡的路径
Environment.getExternalStorageDirectory()
// SD课读写的状态
Environment.MEDIA_MOUNTED

Sqlite数据库存储
存储路径:/data/datapackageName/databases/name.db
特点:应用卸载时自动删除

  • Android屏幕触控MotionEvent机制

事件类型:dwon、move、up
事件发生的顺序:down->move->move->up
MotionEvent:触屏事件
ViewGroup

// 拦截事件
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
    return super.onInterceptTouchEvent(ev)
}

Activity相关API

// 处理事件的回调方法
override fun onTouchEvent(event: MotionEvent?): Boolean {
    return super.onTouchEvent(event)
}
// 分发事件
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    return super.dispatchTouchEvent(ev)
}

事件分发和处理流程:
1、事件对象被系统创建后,首先会调用对应Activity对象的dispatchTouchEvent()进行分发
2、down在分发给视图对象的过程中要确定消费者(onTouchEvent返回true),如果都返回false,那最终消费者就是activity
3、后面的move和up事件,将事件分发给消费者,可能是视图,可能是activity
4、每个事件都需要一个消费者

按键KeyEvent机制
事件类型:down、up
API:
Activity:

// 分发事件
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
    return super.dispatchKeyEvent(event)
}
// 按下按键的回调
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    return super.onKeyDown(keyCode, event)
}
// 松开按键的回调
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    return super.onKeyUp(keyCode, event)
}
// 长安按键的回调
override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean {
    return super.onKeyLongPress(keyCode, event)
}
  • shape属性


    
    

    
    

    
    

    
    

    
    

    
    

  • selector选择器
//设置是否按压状态,一般在true时设置该属性,表示已按压状态,默认为false
android:state_pressed
//设置是否选中状态,true表示已选中,false表示未选中
android:state_selected
//设置是否勾选状态,主要用于CheckBox和RadioButton,true表示已被勾选,false表示未被勾选
android:state_checked
//设置勾选是否可用状态,类似state_enabled,只是state_enabled会影响触摸或点击事件,state_checkable影响勾选事件
android:state_checkable
//设置是否获得焦点状态,true表示获得焦点,默认为false,表示未获得焦点
android:state_focused
//设置触摸或点击事件是否可用状态,一般只在false时设置该属性,表示不可用状态
android:state_enabled


设置选中时候的背景颜色


    
    


设置颜色的时候要使用android:drawable,需要在color.xml中定义,不能直接写16进制值

定义多形状图片
selector + shape
selector + drawable
  • Context

Context是提供了关于应用环境全局信息的抽象类,通过它可以操作系统或应用的相关资源
作用:
启动或停止Activity/Service
发送广播/注册广播接收器
加载布局/创建视图对象
获取应用环境全局信息:

applicationContext
contentResolver
applicationInfo
packageManager
packageName
resources
assets
getSharedPreferences()
getString()
getSystemService()

Application
1、每个应用只有一个对象,单例
2、context类型的对象都可以得到此对象
3、是应用全局数据内存级共享容器
4、在应用启动且该对象不存在的时候创建
5、应用退出不会销毁Application对象
6、应用的进程被主动或被动杀死时销毁

Activity和applicationContext如何选择?
显示Alertdialog时必须用Activity
使用Adapter时最好使用Activity
显示地图时必须用applicationContext
其他情况使用两者都可以

  • 横竖屏切换

1、默认情况下,横竖屏切换时Activity会被销毁重新创建
2、如何不让Activity不被销毁


当屏幕旋转的时候会自动调用onConfigurationChanged方法
3、如何只设置横屏或者竖屏呢
方法一:在AndroidMainifest.xml中设置Activity属性screenOrientation的值


方法二:代码中设置requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

4、获取当前手机的方向
resources.configuration.orientation

  • 自定义控件和属性

1、定义一个类继承自View或者ViewGroup(ViewGroup子类)
2、定义初始化方法
3、在attr.xml中编写自定义属性名
4、在类中获取自定义属性做其他操作

class SwitchButton : View {
    private lateinit var title: String

    constructor(context: Context) : super(context) {
        initView(context)
    }
    
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        Log.e("SwitchButton", "获取xml中设置的属性值")
//        // 方法1
//        for(index in 0 until attrs.attributeCount) {
//            val attrName = attrs.getAttributeName(index)
//            val attrValue = attrs.getAttributeValue(index)
//            Log.e("SwitchButton", "获取xml中设置的属性值 attrName = ${attrName} attrValue = ${attrValue}")
//        }

        // 方法二
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwitchButton)
        val count = typedArray.indexCount
        for (index in 0 until count) {
            val i = typedArray.getIndex(index)
            when(i) {
                R.styleable.SwitchButton_test_bg -> {

                }
                R.styleable.SwitchButton_test_title -> {
                    title = typedArray.getString(i).toString()
                    Log.e("SwitchButton", "获取xml中设置的属性值 title = ${title}")
                }
            }
        }
        initView(context)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        initView(context)
    }

    private fun initView(context: Context) {

    }
}

在attr.xml中配置需要定义的属性

    
        
        
        
    


在布局文件中使用该控件
xmlns:app="http://schemas.android.com/apk/res-auto"


你可能感兴趣的:(Android的自学之路,Android基础,Android常用知识点,Module,事件分发)