赞
踩
== : 关系操作符, 比较的是两个变量本身的值
equal:Object类中的方法,比较的是字符串中包含的内容是否相同
适用于存储少量数据,以key+value形式存储数据,存储的数据以xml文件的形式存储于设备
进程之间进行数据的共享,即跨进程通信
ContentProvider的简单使用
3、数据库存储
安卓五大存储方式之SQlite
4、网络存储
5、文件存储
1、startService()
2、bindService()
startService启动的服务:
Service会经历onCreate()------->onStartCommand()
多次开始时候onStartCommand会被多次调用
bindService启动的服务:
Service会经历onCreate()----->onBind()
多次开始时候onBind只会调用一次
startService在activity被终止后,服务依旧存在,用这个方法创建的服务是个单独的进程,占用一定资源
可通过stopService结束进程
bindService:主进程被终止后,服务也会被终止掉
1、Activity
2、Service
3、contentProvider:主要用于对外共享数据
ContentProvider的简单使用
4、BroadcastReceiver:是一个全局的监听器
使用示例
var mLocalBroadcastManager = LocalBroadcastManager.getInstance(this) var mBroadcastReceiver = MyBroadcastReceiver() val intentFilter = IntentFilter() intentFilter.addAction("action.type.thread") mLocalBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter) /** * 非静态内部类,关键字inner *可以访问外部类的成员变量 */ inner class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent) { when (intent.action) { "action.type.thread" -> { //更改UI val progress = intent.getIntExtra("progress", 0) tv_statue.text = progress.toString() if (progress == 0) { tv_statue.text = "下载结束" } } } } }
onCreate()-onResume()-onStart()-onPause()-onStop()-onDeatory()
1、应用层
2、应用框架层
3、系统运行层
4、Linux内核层
需求分析、原型设计、功能开发、产品测试、应用上架
每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权,但这依赖于线程调度的实现,这个实现是和操作系统相关的(OS dependent)。我们可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10),1代表最低优先级,10代表最高优先级。
启动一个线程是调用start()方法 , run()方法是线程启动后要进行回调(callback)的方法。
安卓BLE蓝牙开发详解
安卓蓝牙开发填坑之路
蓝牙ble数据传输最大字节数20
蓝牙连接数据传输
权限
<!-- 声明蓝牙权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- 允许程序发现和配对蓝牙设备 -->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!--为适配安卓6.0以及以上版本需要添加一个模糊定位的权限 否则会出现无法搜索到设备的情况。-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
判断是否支持蓝牙
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE).getAdapter()==null
判断蓝牙是否开启
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE).getAdapter().isEnabled()
搜索设备
startLeScan(BluetoothAdapter.LeScanCallback)
连接设备
connectGatt+BluetoothGattCallback
开启扫描服务 扫描BLE设备服务是安卓系统中关于BLE蓝牙开发的重要一步,一般在设备连接成功后调用,扫描到设备服务后回调onServicesDiscovered()函数
mBluetoothGatt.discoverServices();
开启通信服务 通信服务通过硬件工程师提供的UUID获取
BluetoothGattService service = mBluetoothGatt.getService(UUID.fromString(“蓝牙模块提供的负责通信UUID字符串”));
开启监听
BluetoothGattCallback
写入数据
mBluetoothGatt.writeCharacteristic(writeCharacteristic)
接收数据
BluetoothGattCallback
断开连接
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
蓝牙BLE低功耗蓝牙介绍:
蓝牙BLE相对于传统蓝牙的优点:最大化的待机时间、快速连接和低峰值的发送/接收功耗。
有关BLE低功耗蓝牙和传统蓝牙的五大区别:
1、低功耗蓝牙的发送和接受任务会以最快的速度完成,完成之后蓝牙BLE会暂停发射无线(但是还是会接受),等待下一次连接再激活;
传统蓝牙是持续保持连接。
2、低功耗蓝牙的广播信道(为保证网络不互相干扰而划分)仅有3个;传统蓝牙是32个。
3、低功耗蓝牙“完成”一次连接(即扫描其它设备、建立链路、发送数据、认证和适当地结束)只需3ms;传统蓝牙完成相同的连接周期需要数百毫秒。
4、低功耗蓝牙使用非常短的数据包,多应用于实时性要求比较高,但是数据速率比较低的产品,遥控类的如键盘,遥控鼠标,传感设备的数据发送,
如心跳带,血压计,温度传感器等;传统蓝牙使用的数据包长度较长,可用于数据量比较大的传输,如语音,音乐,较高数据量传输等。
5、低功耗蓝牙无功率级别,一般发送功率在+4dBm,一般在空旷距离,达到70m的传输距离;传统蓝牙有3个功率级别,Class1,Class2,Class3,
分别支持100m,10m,1m的传输距离。
Android 中的异步消息处理机制主要由四个部分组成:Message、Handler、MessageQueue和Looper。下面对这4个部分进行简单的介绍。
Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同的线程之间交换数据。比如使用Message的what字段携带消息具体是
哪一条,用arg1和arg2字段来携带一些整形数据,使用obj字段携带一个Object对象。
Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用到Handler的sendMessage()方法,而发出的消息经过一
系列的辗转处理后,最终会传递到Handler的handleMessage()方法中。
.MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。
每个线程中只会有一个MessageQueue对象
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue中存在
着一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中也只会有一个Looper对象。
1、ContentProvider
2、AIDL
1、动态权限
一些权限6.0以后使用需要在代码中动态申请,例如:拍照、读写、定位等
若想规避则将targetSdkVersion 降为23以下
比较类型 | List | Set | Map |
---|---|---|---|
继承 | Collection | Collection | |
常见实现类 | ArrayList,LinkedList,Vector | HashSet,LinkedSet | HashMap,HashTable |
元素 | 可重复 | 不可重复 | 不可重复 |
顺序 | 有序 | 无序 | |
线性安全 | Vector线性安全 | HashTable线性安全 |
List转换为数组:ArrayList的toArray()
数组转List:.asList()
class JavaKnowledgeActivity : AppCompatActivity() ,View.OnClickListener{ var list_data=ArrayList<String>() var str= arrayOf("1","2","3") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_java_knowledge) init_Listener() init() } fun init(){ str.forEach { list_data.add(it) } } fun init_Listener(){ tv_iterator.setOnClickListener(this) } override fun onClick(v: View?) { when(v?.id){ R.id.tv_iterator->{//迭代器 useIterator() } } } /** * iterator迭代器的使用 */ fun useIterator(){ var iteratortext=list_data.iterator() while (iteratortext.hasNext()){ Log.i("useIterator==",iteratortext.next()) } } }
输出:
com.light.mytext I/useIterator==: 1
com.light.mytext I/useIterator==: 2
com.light.mytext I/useIterator==: 3
你吃饭吃一半儿了电话来了,你吃完饭才去接电话,说明你既不支持并发也不支持并行
你吃饭吃一半儿了电话来了,你停下吃饭去接电话,说明你支持并发
你吃饭吃一半儿了电话来了,你一边吃饭一边接电话说明支持并行
进程=火车 线程=车厢
Thread{
tv_statue.post(Runnable {
tv_statue.text = "下载中"
ToastUtils.show(baseContext, "下载中")
})
Thread.sleep(2000)
tv_statue.post(Runnable {
tv_statue.text = "下载完成"
ToastUtils.show(baseContext, "下载完成")
})
}.start()
class SynchronizedDemo : Runnable { //共享资源 var i = 0 /** * synchronized 修饰实例方法 */ @Synchronized fun increase() { i++ } override fun run() { for (j in 0..9999) { increase() } } fun main() { val test = SynchronizedDemo() val t1 = Thread(test) val t2 = Thread(test) t1.start() t2.start() t1.join() t2.join() Log.i("Lock==",i.toString()) } }
返回示例:
Lock==: increase: 1
…
Lock==: increase:20000
class CallableFutureActivity : AppCompatActivity(), View.OnClickListener { private var task: FutureTask<Int>?=null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_callable_future) init_Listener() init() } fun init() { task = FutureTask<Int>( Callable<Int> { var i = 0 while (i < 100) { Log.i("CallableFuture==",Thread.currentThread().name + "的循环变量主的值:" + i) i++ } i } as Callable<Int>? ) } fun init_Listener() { tv_start.setOnClickListener(this) } override fun onClick(v: View?) { when (v?.id) { R.id.tv_start -> { Thread(task,"有返回值的线程").start() try { //获取线程返回值 Log.i("CallableFuture==","子线程返回的值:" + task!!.get()) } catch (ex: Exception) { ex.printStackTrace() } } } } }
返回示例:
有返回值的线程的循环变量主的值:0
…
有返回值的线程的循环变量主的值:99
子线程返回的值:100
object类、对象唤醒线程
//创建一个可重用固定线程数的线程池 val pool: ExecutorService = Executors.newSingleThreadExecutor() //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口; val t1: Thread = MyThread() val t2: Thread = MyThread() val t3: Thread = MyThread() val t4: Thread = MyThread() val t5: Thread = MyThread() //将线程放到池中执行; pool.execute(t1) pool.execute(t2) pool.execute(t3) pool.execute(t4) pool.execute(t5) //关闭线程池 pool.shutdown() ----------------------------------------------- inner class MyThread : Thread() { override fun run() { super.run() var name=currentThread().name tv_reult.post { var str=StringBuffer("") str.append(tv_reult.text.toString()).append("\n").append(name + "正在执行....") tv_reult.text=str.toString() } println(name + "正在执行...."); } }
输出结果
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
//创建一个可重用固定线程数的线程池 var pool: ExecutorService? = Executors.newFixedThreadPool(3) //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口; val t1: Thread = MyThread() val t2: Thread = MyThread() val t3: Thread = MyThread() val t4: Thread = MyThread() val t5: Thread = MyThread() //将线程放到池中执行; pool!!.execute(t1) pool.execute(t2) pool.execute(t3) pool.execute(t4) pool.execute(t5) //关闭线程池 pool.shutdown()
输出结果
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-1正在执行…
pool-1-thread-2正在执行…
//创建一个可重用固定线程数的线程池 val pool = Executors.newCachedThreadPool() //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口; val t1: Thread = MyThread() val t2: Thread = MyThread() val t3: Thread = MyThread() val t4: Thread = MyThread() val t5: Thread = MyThread() //将线程放到池中执行; pool.execute(t1) pool.execute(t2) pool.execute(t3) pool.execute(t4) pool.execute(t5) //关闭线程池 pool.shutdown()
输出结果
pool-1-thread-2正在执行…
pool-1-thread-1正在执行…
pool-1-thread-3正在执行…
pool-1-thread-4正在执行…
pool-1-thread-5正在执行…
* newScheduledThreadPool(数量)
创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。
var exec: ScheduledThreadPoolExecutor = ScheduledThreadPoolExecutor(1) exec.scheduleAtFixedRate( Runnable //每隔一段时间就触发异常 { // TODO Auto-generated method stub println("AAAAAAAA") }, 1000, 5000, TimeUnit.MILLISECONDS ) exec.scheduleAtFixedRate( Runnable //每隔一段时间打印系统时间,证明两者是互不影响的 { // TODO Auto-generated method stub println(System.nanoTime()) }, 1000, 2000, TimeUnit.MILLISECONDS )
输出结果
AAAAAAAA
23119318857491
23121319071841
23129318176148
23123319007891
AAAAAAAA
23125318176937
23127318190359
AAAAAAAA
23131318344312
23133318465896
AAAAAAAA
23135319645812
线程安全体现在:
1、原子性:一个或多个操作在CPU执行的过程中不被中断的特性
2、可见性:一个线程对共享变量的修改,另外一个线程能立即看到
3、有序性:程序执行的顺序按照代码的先后顺序来执行
导致原因:
1、缓存导致的可见性的问题
2、线程切换导致的原子性问题
3、编译优化带来的有序性问题
解决办法:
1、synchronized、Lock可以解决原子性问题
2、synchronized、Lock、volatile能解决可见性问题
class ThreadLocalActivity : AppCompatActivity(), View.OnClickListener { lateinit var THREAD_LOCAL_NUM: ThreadLocal<Int?> var stringBuffer = StringBuffer("") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_thread_local) init() init_Listener() } fun init() { //线程本地存储变量 THREAD_LOCAL_NUM = object : ThreadLocal<Int?>() { override fun initialValue(): Int { return 0 } } } fun init_Listener() { bt_0.setOnClickListener(this) } fun main() { for (i in 0..1) { var thread = Thread { changeLocalValue() }.start() } } /** * 修改本地存储数据 */ fun changeLocalValue() { for (i in 0..2) { var n = THREAD_LOCAL_NUM.get()!!.toInt() n++ THREAD_LOCAL_NUM.set(n) Log.i("ThreadLocal==", Thread.currentThread().name + " : ThreadLocal num=" + n) stringBuffer.append(Thread.currentThread().name + " : ThreadLocal num=" + n) stringBuffer.append("\r\n") runOnUiThread() { tv_text.text = stringBuffer.toString() } } } override fun onClick(v: View?) { main() } }
返回示例
Thread-4 : ThreadLocal num=1
Thread-4 : ThreadLocal num=2
Thread-5 : ThreadLocal num=1
Thread-5 : ThreadLocal num=2
Thread-4 : ThreadLocal num=3
Thread-5 : ThreadLocal num=3
/** * 日期转换 */ var sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") fun getChangeData(dataStr: String): Date? { var date: Date? = null date = sdf.parse(dataStr) return date } fun main() { var service = Executors.newFixedThreadPool(20) for (i in 0..19) { service.execute { Log.i("ThreadLocal==", getChangeData("2019-06-01 16:34:30").toString()) } } service.shutdown() }
结果main中打印:
Sat Jun 01 16:34:30 GMT+08:00 2019
Sat Jun 01 16:34:30 GMT+08:00 2019
Sun Jun 01 16:34:30 GMT+08:00 2200
Sun Jun 01 16:34:30 GMT+08:00 2200
Mon Apr 01 16:34:30 GMT+08:00 1202
Sat Jun 01 16:34:30 GMT+08:00 2019
Sat Jun 01 16:34:30 GMT+08:00 2019
…
发现数据获取不对
private static ThreadLocal<DateFormat> threadLocal = ThreadLocal.withInitial(
()-> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static Date getChangeData(String dateStr) {
Date date = null;
try {
date = threadLocal.get().parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
注意:ThreadLocal支持安卓8.0系统,即Build.VERSION_CODES.O=26的时候可以使用
更为详细的介绍请参考
ThreadLocal的应用场景和注意事项有哪些?
fun getInstance(): RequestUtils {
if (mRequestUtils == null) {
synchronized(RequestUtils::class) {//双重检验锁
if (mRequestUtils == null) {
mRequestUtils = RequestUtils()
Log.i(Tag, "new RequestUtils()")
}
}
}
return mRequestUtils
}
2、修饰静态方法
public synchronized static void methodTwo() {
System.out.println("method two executed!");
}
3、修饰代码块儿
public void methodTwo() {
synchronized (obj) {
System.out.println("method two executed!");
}
}
class MyThread implements Runnable { static AtomicInteger ai=new AtomicInteger(0); public void run() { for (int m = 0; m < 1000000; m++) { ai.getAndIncrement(); } } }; public class TestAtomicInteger { public static void main(String[] args) throws InterruptedException { MyThread mt = new MyThread(); Thread t1 = new Thread(mt); Thread t2 = new Thread(mt); t1.start(); t2.start(); Thread.sleep(500); System.out.println(MyThread.ai.get()); } }
class DPerson implements Cloneable { public DPerson() { } private int pid; private String name; private DFood food; public DPerson(int pid, String name, DFood food) { this.pid = pid; this.name = name; this.food = food; System.out.println("Person constructor call"); } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } @NonNull @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]"; } public DFood getFood() { return food; } public void setFood(DFood food) { this.food = food; } class DFood implements Cloneable{ private String name; public DFood(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } } ----------------------------我是分割线------------------------ fun init(){ var bean1=DPerson(1,"文阿花", DPerson().DFood("大米饭")) var bean2= bean1.clone() as DPerson bean2.food.name="面包" bean2.name="wenahua" Log.i("Clone==","bean1="+bean1+"bean2="+bean2) }
输出结果
bean1=Person [pid:1, name:文阿花, food:面包]
bean2=Person [pid:1, name:wenahua, food:面包]
我们发现bean2变了,但是bean1也变了,这样并不能满足我们的需求,因此我们需要深克隆!!
(1)方法1、在克隆对象时候手动属性
class DPerson implements Cloneable { public DPerson() { } private int pid; private String name; private DFood food; public DPerson(int pid, String name, DFood food) { this.pid = pid; this.name = name; this.food = food; System.out.println("Person constructor call"); } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Object clone() throws CloneNotSupportedException { DPerson p = (DPerson)super.clone(); p.setFood((DFood)p.getFood().clone()); return p; } @Override public String toString() { return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]"; } public DFood getFood() { return food; } public void setFood(DFood food) { this.food = food; } class DFood implements Cloneable{ private String name; public DFood(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } } -------------------------------我是分割线------------- fun init(){ var bean1=DPerson(1,"文阿花", DPerson().DFood("大米饭")) var bean2= bean1.clone() as DPerson bean2.food.name="面包" bean2.name="wenahua" Log.i("Clone==","bean1="+bean1+"bean2="+bean2) }
输出结果
bean1=Person [pid:1, name:文阿花, food:大米饭]
bean2=Person [pid:1, name:wenahua, food:面包]
可以看出 bean2变了,而bean1没变
(2)方法2、结合序列化Serializable 实现深拷贝
package constxiong.interview; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class TestSeriazableClone { public static void main(String[] args) { SPerson p1 = new SPerson(1, "ConstXiong", new SFood("米饭"));//创建 SPerson 对象 p1 SPerson p2 = (SPerson)p1.cloneBySerializable();//克隆 p1 p2.setName("其不答");//修改 p2 的 name 属性 p2.getFood().setName("面条");//修改 p2 的自定义引用类型 food 属性 System.out.println(p1);//修改 p2 的自定义引用类型 food 属性被改变,p1的自定义引用类型 food 属性未随之改变,说明p2的food属性,只拷贝了引用和 food 对象 System.out.println(p2); } } class SPerson implements Cloneable, Serializable { private static final long serialVersionUID = -7710144514831611031L; private int pid; private String name; private SFood food; public SPerson(int pid, String name, SFood food) { this.pid = pid; this.name = name; this.food = food; System.out.println("Person constructor call"); } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public String getName() { return name; } public void setName(String name) { this.name = name; } /** * 通过序列化完成克隆 * @return */ public Object cloneBySerializable() { Object obj = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); obj = ois.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return obj; } @Override public String toString() { return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]"; } public SFood getFood() { return food; } public void setFood(SFood food) { this.food = food; } } class SFood implements Serializable { private static final long serialVersionUID = -3443815804346831432L; private String name; public SFood(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
输出结果
Person constructor call
Person [pid:1, name:ConstXiong, food:米饭]
Person [pid:1, name:其不答, food:面条]
也可以看出 bean2变了,而bean1没变
public static void send(WebSocketClient client, byte[] bytes) {
if (client.isClosed()) {
throw new RuntimeException("client connect closed!");//处理异常
}
client.send(bytes);//正常情况下需要执行的方法
}
TCP是双全工的,即客户端再给服务端发信息的同时,服务端也在给客户端发信息
半全工的意思是,A能给B发信息,B也能给A发信息,但是不能同时
单工是指A和B之间的通信是单向的,即A能给B发,但B不能给A发,或者B能给A发,A不能对B发
举个例子
第一次握手:A跟B打电话问,你能听到我说话吗
第二次握手:B收到A的信息,并回信息说我可以听到你说话
第三次握手:A跟B说,可以,那我要开始向你发信息了
经过三次握手,确认A能听到B说话,B能听到A说话,这样就能开始正常通信了
由于TCP协议中,建立见连接后,AB双方谁都能先发送信息,所以只握手两次的话,无法确定A是否能听到B说话,会出现问题,但是四次的话,又会造成浪费
正式情况下 三次握手都做了什么
TCP为什么是三次握手,为什么不是两次或者四次 && TCP四次挥手
四次挥手
A:我不说了
B:好的,等我把最后一句说完
B:我说完了
A:好的
(1)地图:百度map,高德。
(2)推送:小米推送
(3)聊天:环信、腾讯。
(4)第三方登陆:新浪,qq,微信等
(5)json解析:fastjson,速度最快,简单易用
(6)网络请求:okhttp
(7)图片加载:ImageLoader
特别注意:
JNI是 Java 调用 Native 语言的一种特性
JNI 是属于 Java 的,与 Android 无直接关系
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。