十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
注:这里只是个成功的示例,compileSdkVersion和27.1.1有关,也可以换成你需要的
在璧山等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供成都网站设计、网站制作 网站设计制作按需定制网站,公司网站建设,企业网站建设,成都品牌网站建设,全网整合营销推广,成都外贸网站建设,璧山网站建设费用合理。
提供下颜色
清单AndroidManifest
内存泄漏:
举例:
请注意以下的例子是虚构的
内存抖动
源自Android文档中的 Memory churn 一词,中文翻译为内存抖动。
指快速频繁的创建对象从而产生的性能问题。
引用Android文档原文:
Java内存泄漏的根本原因是 长生命周期 的对象持有 短生命周期 对象的引用就很可能发生内存泄漏。
尽管短生命周期对象已经不再需要,但因为长生命周期依旧持有它的引用,故不能被回收而导致内存泄漏。
静态集合类引起的内存泄漏
如果仅仅释放引用本身(tO = null), ArrayList 依然在引用该对象,GC无法回收。
监听器
在Java应用中,通常会用到很多监听器,一般通过 addXXXXListener() 实现。但释放对象时通常会忘记删除监听器,从而增加内存泄漏的风险。
各种连接
如数据库连接、网络连接(Socket)和I/O连接。忘记显式调用 close() 方法引起的内存泄漏。
内部类和外部模块的引用
内部类的引用是很容易被遗忘的一种,一旦没有释放可能会导致一系列后续对象无法释放。此外还要小心外部模块不经意的引用,内部类是否提供相应的操作去除外部引用。
单例模式
由于单例的静态特性,使其生命周期与应用的生命周期一样长,一旦使用不恰当极易造成内存泄漏。如果单利持有外部引用,需要注意提供释放方式,否则当外部对象无法被正常回收时,会进而导致内存泄漏。
集合类泄漏
如集合的使用范围超过逻辑代码的范围,需要格外注意删除机制是否完善可靠。比如由静态属性 static 指向的集合。
单利泄漏
以下为简单逻辑代码,只为举例说明内存泄漏问题,不保证单利模式的可靠性。
AppManager 创建时需要传入一个 Context ,这个 Context 的生命周期长短至关重要。
1. 如果传入的是 Application 的 Context ,因为 Application 的生命周期等同于应用的生命周期,所以没有任何问题。
2. 如果传入的是 Activity 的 Context ,则需要考虑这个 Activity 是否在整个生命周期都不会被回收了,如果不是,则会造成内存泄漏。
非静态内部类创建静态实例造成的内存泄漏
应该将该内部类单独封装为一个单例来使用。
匿名内部类/异步线程
Runnable都使用了匿名内部类,将持有MyActivity的引用。如果任务在Activity销毁前未完成,将导致Activity的内存无法被回收,从而造成内存泄漏。
解决方法:将Runnable独立出来或使用静态内部类,可以避免因持有外部对象导致的内存泄漏。
Handler造成的内存泄漏
Handler属于TLS(Thread Local Storage)变量,生命周期与Activity是不一致的,容易导致持有的对象无法正确被释放
当Android应用程序启动时,该应用程序的主线程会自动创建一个Looper对象和与之关联的MessageQueue。
当主线程中实例化一个Handler对象后,它就会自动与主线程Looper的MessageQueue关联起来。所有发送到MessageQueue的Messag都会持有Handler的引用,所以Looper会据此回调Handle的handleMessage()方法来处理消息。只要MessageQueue中有未处理的Message,Looper就会不断的从中取出并交给Handler处理。
另外,主线程的Looper对象会伴随该应用程序的整个生命周期。
在Java中,非静态内部类和匿名类内部类都会潜在持有它们所属的外部类的引用,但是静态内部类却不会。
当该 Activity 被 finish() 掉时,延迟执行任务的 Message 还会继续存在于主线程中,它持有该 Activity 的 Handler 引用,所以此时 finish() 掉的 Activity 就不会被回收了从而造成内存泄漏(因 Handler 为非静态内部类,它会持有外部类的引用,在这里就是指 SampleActivity)。
避免不必要的静态成员变量
对于BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等资源的使用,应在Activity销毁前及时关闭或注销。
不使用WebView对象时,应调用`destroy()`方法销毁。
给你个示例吧:
package com.water.activity;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.telephony.CellLocation;
import android.telephony.NeighboringCellInfo;
import android.telephony.TelephonyManager;
import android.util.Log;
public class MyList extends Activity {
/**
* android API中的TelephonyManager对象,可以取得SIM卡中的信息
*/
private TelephonyManager telMgr;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
telMgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (telMgr.getSimState() == telMgr.SIM_STATE_READY) {
Log.i("MyList", "良好");
} else if (telMgr.getSimState() == telMgr.SIM_STATE_ABSENT) {
Log.i("MyList", "无SIM卡");
} else {
Log.i("MyList", "SIM卡被锁定或未知的状态");
}
Log.i("MyList", "电话状态[0 无活动/1 响铃/2 摘机]:" + getCallState());
Log.i("MyList", "电话方位:" + getCellLocation());
Log.i("MyList", "唯一的设备ID:" + getDeviceId());
Log.i("MyList", "设备的软件版本号:" + getDeviceSoftwareVersion());
Log.i("MyList", "手机号:" + getLine1Number());
Log.i("MyList", "附近的电话的信息:" + getNeighboringCellInfo());
Log.i("MyList", "获取ISO标准的国家码,即国际长途区号:" + getNetworkCountryIso());
Log.i("MyList", "MCC+MNC:" + getNetworkOperator());
Log.i("MyList", "(当前已注册的用户)的名字:" + getNetworkOperatorName());
Log.i("MyList", "当前使用的网络类型:" + getNetworkType());
Log.i("MyList", "手机类型:" + getPhoneType());
Log.i("MyList", "SIM卡的国家码:" + getSimCountryIso());
Log.i("MyList", "获取SIM卡提供的移动国家码和移动网络码.5或6位的十进制数字:" + getSimOperator());
Log.i("MyList", "服务商名称:" + getSimOperatorName());
Log.i("MyList", "SIM卡的序列号:" + getSimSerialNumber());
Log.i("MyList", "SIM的状态信息:" + getSimState());
Log.i("MyList", "唯一的用户ID:" + getSubscriberId());
Log.i("MyList", "取得和语音邮件相关的标签,即为识别符:" + getVoiceMailAlphaTag());
Log.i("MyList", "获取语音邮件号码:" + getVoiceMailNumber());
Log.i("MyList", "ICC卡是否存在:" + hasIccCard());
Log.i("MyList", "是否漫游:" + isNetworkRoaming());
Log.i("MyList", "获取数据活动状态:" + getDataActivity());
Log.i("MyList", "获取数据连接状态:" + getDataState());
}
/**
* 电话状态:br/
* CALL_STATE_IDLE 无任何状态时br/
* CALL_STATE_OFFHOOK 接起电话时br/
* CALL_STATE_RINGING 电话进来时
*
* @return
*/
private int getCallState() {
return telMgr.getCallState();
}
/**
* 返回当前移动终端的位置 br/
*
* @return
*/
private CellLocation getCellLocation() {
CellLocation location = telMgr.getCellLocation();
// 请求位置更新,如果更新将产生广播,接收对象为注册LISTEN_CELL_LOCATION的对象,需要的permission名称为ACCESS_COARSE_LOCATION。
// location.requestLocationUpdate();
return location;
}
/**
* 唯一的设备ID:br/
* 如果是GSM网络,返回IMEI;如果是CDMA网络,返回MEIDbr/
* 需要权限:android.permission.READ_PHONE_STATE
*
* @return null if device ID is not available.
*/
private String getDeviceId() {
return telMgr.getDeviceId();
}
/**
* 返回移动终端的软件版本:br/
* 例如:GSM手机的IMEI/SV码。br/
*
* @return null if the software version is not available.
*/
private String getDeviceSoftwareVersion() {
return telMgr.getDeviceSoftwareVersion();
}
/**
* 手机号:br/
* 对于GSM网络来说即MSISDN
*
* @return null if it is unavailable.
*/
private String getLine1Number() {
return telMgr.getLine1Number();
}
/**
* 返回当前移动终端附近移动终端的信息:br/
* 类型:ListNeighboringCellInfobr/
* 需要权限:android.Manifest.permission#ACCESS_COARSE_UPDATES
*
* @return
*/
private ListNeighboringCellInfo getNeighboringCellInfo() {
// ListNeighboringCellInfo infos = telMgr.getNeighboringCellInfo();
// for (NeighboringCellInfo info : infos) {
// // 获取邻居小区号
// int cid = info.getCid();
//
// // 获取邻居小区LAC,LAC:
// // 位置区域码。为了确定移动台的位置,每个GSM/PLMN的覆盖区都被划分成许多位置区,LAC则用于标识不同的位置区。
// info.getLac();
// info.getNetworkType();
// info.getPsc();
//
// // 获取邻居小区信号强度
// info.getRssi();
// }
return telMgr.getNeighboringCellInfo();
}
/**
* 获取ISO标准的国家码,即国际长途区号。br/
* 注意:仅当用户已在网络注册后有效。br/
* 在CDMA网络中结果也许不可靠。br/
*
* @return
*/
private String getNetworkCountryIso() {
return telMgr.getNetworkCountryIso();
}
/**
* MCC+MNC(mobile country code + mobile network code)br/
* 注意:仅当用户已在网络注册时有效。br/
* 在CDMA网络中结果也许不可靠。br/
*
* @return
*/
private String getNetworkOperator() {
return telMgr.getNetworkOperator();
}
/**
* 按照字母次序的current registered operator(当前已注册的用户)的名字br/
* 注意:仅当用户已在网络注册时有效。br/
* 在CDMA网络中结果也许不可靠。
*
* @return
*/
private String getNetworkOperatorName() {
return telMgr.getNetworkOperatorName();
}
/**
* 当前使用的网络类型:br/
* NETWORK_TYPE_UNKNOWN 网络类型未知 0br/
* NETWORK_TYPE_GPRS GPRS网络 1br/
* NETWORK_TYPE_EDGE EDGE网络 2br/
* NETWORK_TYPE_UMTS UMTS网络 3br/
* NETWORK_TYPE_HSDPA HSDPA网络 8br/
* NETWORK_TYPE_HSUPA HSUPA网络 9br/
* NETWORK_TYPE_HSPA HSPA网络 10br/
* NETWORK_TYPE_CDMA CDMA网络,IS95A 或 IS95B. 4br/
* NETWORK_TYPE_EVDO_0 EVDO网络, revision 0. 5br/
* NETWORK_TYPE_EVDO_A EVDO网络, revision A. 6br/
* NETWORK_TYPE_1xRTT 1xRTT网络 7br/
* 在中国,联通的3G为UMTS或HSDPA,移动和联通的2G为GPRS或EGDE,电信的2G为CDMA,电信的3G为EVDObr/
*
* @return
*/
private int getNetworkType() {
return telMgr.getNetworkType();
}
/**
* 返回移动终端的类型:br/
* PHONE_TYPE_CDMA 手机制式为CDMA,电信br/
* PHONE_TYPE_GSM 手机制式为GSM,移动和联通br/
* PHONE_TYPE_NONE 手机制式未知br/
*
* @return
*/
private int getPhoneType() {
return telMgr.getPhoneType();
}
/**
* 获取ISO国家码,相当于提供SIM卡的国家码。
*
* @return Returns the ISO country code equivalent for the SIM provider's
* country code.
*/
private String getSimCountryIso() {
return telMgr.getSimCountryIso();
}
/**
* 获取SIM卡提供的移动国家码和移动网络码.5或6位的十进制数字.br/
* SIM卡的状态必须是 SIM_STATE_READY(使用getSimState()判断).
*
* @return Returns the MCC+MNC (mobile country code + mobile network code)
* of the provider of the SIM. 5 or 6 decimal digits.
*/
private String getSimOperator() {
return telMgr.getSimOperator();
}
/**
* 服务商名称:br/
* 例如:中国移动、联通br/
* SIM卡的状态必须是 SIM_STATE_READY(使用getSimState()判断).
*
* @return
*/
private String getSimOperatorName() {
return telMgr.getSimOperatorName();
}
/**
* SIM卡的序列号:br/
* 需要权限:READ_PHONE_STATE
*
* @return
*/
private String getSimSerialNumber() {
return telMgr.getSimSerialNumber();
}
/**
* SIM的状态信息:br/
* SIM_STATE_UNKNOWN 未知状态 0br/
* SIM_STATE_ABSENT 没插卡 1br/
* SIM_STATE_PIN_REQUIRED 锁定状态,需要用户的PIN码解锁 2br/
* SIM_STATE_PUK_REQUIRED 锁定状态,需要用户的PUK码解锁 3br/
* SIM_STATE_NETWORK_LOCKED 锁定状态,需要网络的PIN码解锁 4br/
* SIM_STATE_READY 就绪状态 5
*
* @return
*/
private int getSimState() {
return telMgr.getSimState();
}
/**
* 唯一的用户ID:br/
* 例如:IMSI(国际移动用户识别码) for a GSM phone.br/
* 需要权限:READ_PHONE_STATE
*
* @return
*/
private String getSubscriberId() {
return telMgr.getSubscriberId();
}
/**
* 取得和语音邮件相关的标签,即为识别符br/
* 需要权限:READ_PHONE_STATE
*
* @return
*/
private String getVoiceMailAlphaTag() {
return telMgr.getVoiceMailAlphaTag();
}
/**
* 获取语音邮件号码:br/
* 需要权限:READ_PHONE_STATE
*
* @return
*/
private String getVoiceMailNumber() {
return telMgr.getVoiceMailNumber();
}
/**
* ICC卡是否存在
*
* @return
*/
private boolean hasIccCard() {
return telMgr.hasIccCard();
}
/**
* 是否漫游:(在GSM用途下)
*
* @return
*/
private boolean isNetworkRoaming() {
return telMgr.isNetworkRoaming();
}
/**
* 获取数据活动状态br/
* DATA_ACTIVITY_IN 数据连接状态:活动,正在接受数据br/
* DATA_ACTIVITY_OUT 数据连接状态:活动,正在发送数据br/
* DATA_ACTIVITY_INOUT 数据连接状态:活动,正在接受和发送数据br/
* DATA_ACTIVITY_NONE 数据连接状态:活动,但无数据发送和接受br/
*
* @return
*/
private int getDataActivity() {
return telMgr.getDataActivity();
}
/**
* 获取数据连接状态br/
* DATA_CONNECTED 数据连接状态:已连接br/
* DATA_CONNECTING 数据连接状态:正在连接br/
* DATA_DISCONNECTED 数据连接状态:断开br/
* DATA_SUSPENDED 数据连接状态:暂停br/
*
* @return
*/
private int getDataState() {
return telMgr.getDataState();
}
}
万物互联的物联网时代的已经来临,ble蓝牙开发在其中扮演着举重若轻的角色。最近刚好闲一点,抽时间梳理下这块的知识点。
涉及ble蓝牙通讯的客户端(开启、扫描、连接、发送和接收数据、分包解包)和服务端(初始化广播数据、开始广播、配置Services、Server回调操作)整个环节以及一些常见的问题即踩过的一些坑。
比如
1、在Android不同版本或不同手机的适配问题,扫描不到蓝牙设备
2、如何避免ble蓝牙连接出现133错误?
3、单次写的数据大小有20字节限制,如何发送长数据
蓝牙有传统(经典)蓝牙和低功耗蓝牙BLE(Bluetooth Low Energy)之分,两者的开发的API不一样,本文主讲Ble蓝牙开发,传统蓝牙不展开,有需要的可以自行了解。
相对传统蓝牙,BLE低功耗蓝牙,主要特点是快速搜索,快速连接,超低功耗保持连接和数据传输。
客户端
服务端
Android4.3(API Level 18)开始引入BLE的核心功能并提供了相应的 API。应用程序通过这些 API 扫描蓝牙设备、查询 services、读写设备的 characteristics(属性特征)等操作。
BLE蓝牙协议是GATT协议, BLE相关类不多, 全都位于android.bluetooth包和android.bluetooth.le包的几个类:
android.bluetooth.
.BluetoothGattService 包含多个Characteristic(属性特征值), 含有唯一的UUID作为标识
.BluetoothGattCharacteristic 包含单个值和多个Descriptor, 含有唯一的UUID作为标识
.BluetoothGattDescriptor 对Characteristic进行描述, 含有唯一的UUID作为标识
.BluetoothGatt 客户端相关
.BluetoothGattCallback 客户端连接回调
.BluetoothGattServer 服务端相关
.BluetoothGattServerCallback 服务端连接回调
android.bluetooth.le.
.AdvertiseCallback 服务端的广播回调
.AdvertiseData 服务端的广播数据
.AdvertiseSettings 服务端的广播设置
.BluetoothLeAdvertiser 服务端的广播
.BluetoothLeScanner 客户端扫描相关(Android5.0新增)
.ScanCallback 客户端扫描回调
.ScanFilter 客户端扫描过滤
.ScanRecord 客户端扫描结果的广播数据
.ScanResult 客户端扫描结果
.ScanSettings 客户端扫描设置
BLE设备分为两种设备: 客户端(也叫主机/中心设备/Central), 服务端(也叫从机/外围设备/peripheral)
客户端的核心类是 BluetoothGatt
服务端的核心类是 BluetoothGattServer 和 BluetoothLeAdvertiser
BLE数据的核心类是 BluetoothGattCharacteristic 和 BluetoothGattDescriptor
下面详细讲解下客户端和服务端的开发步骤流程
安卓手机涉及蓝牙权限问题,蓝牙开发需要在AndroidManifest.xml文件中添加权限声明:
在搜索设备之前需要询问打开手机蓝牙:
注意: BLE设备地址是动态变化(每隔一段时间都会变化),而经典蓝牙设备是出厂就固定不变了!
通过扫描BLE设备,根据设备名称区分出目标设备targetDevice,下一步实现与目标设备的连接,在连接设备之前要停止搜索蓝牙;停止搜索一般需要一定的时间来完成,最好调用停止搜索函数之后加以100ms的延时,保证系统能够完全停止搜索蓝牙设备。停止搜索之后启动连接过程;
BLE蓝牙的连接方法相对简单只需调用connectGatt方法;
参数说明
与设备建立连接之后与设备通信,整个通信过程都是在BluetoothGattCallback的异步回调函数中完成;
BluetoothGattCallback中主要回调函数如下:
上述几个回调函数是BLE开发中不可缺少的;
当调用targetdDevice.connectGatt(context, false, gattCallback)后系统会主动发起与BLE蓝牙设备的连接,若成功连接到设备将回调onConnectionStateChange方法,其处理过程如下:
判断newState == BluetoothGatt.STATE_CONNECTED表明此时已经成功连接到设备;
mBluetoothGatt.discoverServices();
扫描BLE设备服务是安卓系统中关于BLE蓝牙开发的重要一步,一般在设备连接成功后调用,扫描到设备服务后回调onServicesDiscovered()函数,函数原型如下:
BLE蓝牙开发主要有负责通信的BluetoothGattService完成的。当且称为通信服务。通信服务通过硬件工程师提供的UUID获取。获取方式如下:
具体操作方式如下:
开启监听,即建立与设备的通信的首发数据通道,BLE开发中只有当客户端成功开启监听后才能与服务端收发数据。开启监听的方式如下:
BLE单次写的数据量大小是有限制的, 通常是20字节 ,可以尝试通过requestMTU增大,但不保证能成功。分包写是一种解决方案,需要定义分包协议,假设每个包大小20字节,分两种包,数据包和非数据包。对于数据包,头两个字节表示包的序号,剩下的都填充数据。对于非数据包,主要是发送一些控制信息。
监听成功后通过向 writeCharacteristic写入数据实现与服务端的通信。写入方式如下:
其中:value一般为Hex格式指令,其内容由设备通信的蓝牙通信协议规定;
若写入指令成功则回调BluetoothGattCallback中的onCharacteristicWrite()方法,说明将数据已经发送给下位机;
若发送的数据符合通信协议,则服务端会向客户端回复相应的数据。发送的数据通过回调onCharacteristicChanged()方法获取,其处理方式如下:
通过向服务端发送指令获取服务端的回复数据,即可完成与设备的通信过程;
当与设备完成通信之后之后一定要断开与设备的连接。调用以下方法断开与设备的连接:
源码上传在CSDN上了,有需要的可以借鉴。
===== Android蓝牙Ble通讯Demo示例源码–扫描,连接,发送和接收数据,分包解包
BLE单次写的数据量大小是有限制的,通常是20字节,可以尝试通过requestMTU增大,但不保证能成功。分包写是一种解决方案,需要定义分包协议,假设每个包大小20字节,分两种包,数据包和非数据包。对于数据包,头两个字节表示包的序号,剩下的都填充数据。对于非数据包,主要是发送一些控制信息。
总体流程如下:
1、定义通讯协议,如下(这里只是个举例,可以根据项目需求扩展)
2、封装通用发送数据接口(拆包)
该接口根据会发送数据内容按最大字节数拆分(一般20字节)放入队列,拆分完后,依次从队列里取出发送
3、封装通用接收数据接口(组包)
该接口根据从接收的数据按协议里的定义解析数据长度判读是否完整包,不是的话把每条消息累加起来
4、解析完整的数据包,进行业务逻辑处理
5、协议还可以引入加密解密,需要注意的选算法参数的时候,加密后的长度最好跟原数据长度一致,这样不会影响拆包组包
一般都是Android版本适配以及不同ROM机型(小米/红米、华为/荣耀等)(EMUI、MIUI、ColorOS等)的权限问题
蓝牙开发中有很多问题,要静下心分析问题,肯定可以解决的,一起加油;
第一种点击事件
在xml中设置onclick属性
android:onClick="myOnclick"
第二种;获取Button然后一个一个单独绑定点击事件
"
xmlns:tools=" "
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/btn_imgBtn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="myOnclick"
android:text="imageButton"
/
android:id="@+id/btn_imgView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="myOnclick"
android:text="imageView"
/
public class MainActivity extends ActionBarActivity {
private Button btnImageBtn;
private Button btnImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnImageBtn = (Button) findViewById(R.id.btn_imgBtn);
btnImageView = (Button) findViewById(R.id.btn_imgView);
btnImageBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击ImageButton", Toast.LENGTH_SHORT).show();
}
});
btnImageView.setOnClickListener(new MyListener());
}
第三种:写一个类(MyListener)实现OnClickListener接口,然后Button在设置onclickListener的时候new一个MyListener
btnImageView.setOnClickListener(new MyListener());
class MyListener implements OnClickListener{
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_imgBtn:
Toast.makeText(MainActivity.this, "点击ImageButton", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_imgView:
Toast.makeText(MainActivity.this, "点击imageView", Toast.LENGTH_SHORT).show();
break;
}
第四种:整个类(MianActivity)实现onclickListener的接口
跳转界面
Intent:意图,用于访问android中的组件
用Intent跳转界面(activity)
第一步:new一个Intent()
Intent intent1 = new Intent(MainActivity.this,ImageButtonActivity.class);
startActivity(intent1);
public void myOnclick(View view){
switch (view.getId()) {
case R.id.btn_imgBtn:
Intent intent1 = new Intent(MainActivity.this,ImageButtonActivity.class);
startActivity(intent1);
break;
case R.id.btn_imgView:
Intent intent2 = new Intent(MainActivity.this,ImageViewActivity.class);
startActivity(intent2);
break;
Intent intent = new Intent(当前的activity,跳转到的acticvity.class);
startActivity(intent);
3.ImageView
展示方式:scaleType:
4.ImageButton:
触摸事件:当控件或者屏幕呗触摸的时候,产生的反应
public boolean onTouchEvent(MotionEvent event) {
}
imageButton:现在已经呗button代替,用于展示图片的按钮。不能显示文字。
imageView
scaleType:图片展示的方式
fitStart:展示在控件的上方
fitCenter:展示在控件的中间
fitEnd;展示在控件的下方
fitXY:不按照比例拉伸
matrix:矩阵模式
matrix可以设置图片旋转,缩放。移动
获取图片的高度和宽度
int h = imgView.getDrawable().getIntrinsicHeight();
int w = imgView.getDrawable().getIntrinsicWidth();
Matrix m = new Matrix();
m.postRotate(45);
m.postRotate(45, w/2, h/2);
imgView.setImageMatrix(m);
移动事件:
按下:MotionEvent.ACTION_DOWN
抬起:MotionEvent.ACTION_UP
移动:MotionEvent.ACTION_MOVE
获取当前的移动事件,
event.getAction()
"
xmlns:tools=" "
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/img_01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/ss"
android:scaleType="fitXY"/
android:id="@+id/img_02"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="@drawable/gl"
android:visibility="gone"
android:scaleType="fitXY"/
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/bird"
android:layout_gravity="center"
/
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ff0000"
android:gravity="center"
android:text="小鸟飞"/
public class MainActivity extends Activity {
private ImageView img01;
private ImageView img02;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img01 = (ImageView) findViewById(R.id.img_01);
img02 = (ImageView) findViewById(R.id.img_02);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//System.out.println("被摸了");
if(event.getAction()==MotionEvent.ACTION_UP){
Log.v("TAG", "被抬起来");
if(img01.getVisibility()==View.VISIBLE){
img01.setVisibility(View.GONE);
img02.setVisibility(View.VISIBLE);
}else{
img01.setVisibility(View.VISIBLE);
img02.setVisibility(View.GONE);
}
}else if(event.getAction()==MotionEvent.ACTION_DOWN){
Log.v("TAG", "被按下了");
}else if(event.getAction()==MotionEvent.ACTION_MOVE){
Log.v("TAG", "移动了");
}
return super.onTouchEvent(event);
}