一、文件创建目录结构
-
工程项目创建完成后,默认打开activity.main.xml与MainActivity.java文件
-
目录结构
1.1 app模块

1.2 Gradle Scripts工程编译配置文件
1.2.1 build.gradle 编译文件
android {
compileSdkVersion 33 //sdk版本号
defaultConfig {
minSdkVersion 24 //最小支持sdk版本号
targetSdkVersion 33 //最佳sdk版本号
versionCode 1 //指定App应用版本号,必须是整数
versionName "1.0" //版本名称
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" //单元测试
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
//依赖项
}
//单个项目配置阿里云镜像
buildscript {
repositories {
maven {url 'http://maven.aliyun.com/nexus/content/groups/public/'}//这里
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
}
}
allprojects {
repositories {
google()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }//这里
jcenter()
}
}
1.2.2 AndroidManifest.xml清单文件
android: allowBackup备份
icon图标
label手机屏上显示的名称,app名称
roundIcon圆角图标
theme主题
activity 活动页面注册声明
1.3编写一个页面流程
XML+JAVA
-
layout目录下创建xml文件,里面需要的文本写在strings.xml里
-
创建与xml对应的Java代码,需要extends AppCompatActivity,因为它里面处理了很多兼容性问题,重写oncreate方法,执行布局。
-
在清单中注册页面配置,这里注册的是Java代码
-
可以一键生成,自动注册
二、基础知识
2.1 Activity
-
Activity是安卓开发四大组件之一
2.1.1 activity启动与结束
startActivity(new Intent(原页面.this,跳转目标页面.class));//跳转
finish();//当前activity结束
2.1.2 生命周期

2.2 数据库框架GreenDAO
-
配置
-
实体类贴标签
-
Util中 private DaoSession daoSession;
-
创建数据库
DaoMaster.DevOpenHelper devOpenHelper=new DaoMaster.DevOpenHelper(this,"xxx.dp");
SQLiteDatabase sqLiteDatabase = devOpenHelper.getWritableDatabase();
DaoMaster daoMaster = new DaoMaster(sqLiteDatabase);
daoSession = daoMaster.newSession();
2.3 蓝牙钥匙2000cKey
2.3.1 onActivityResult回调方法、onRequestPermissionsResult回调方法
在Activity页面finish时,会将resultCode和resultIntent的数据打包放在原来的Activity的ActivityRecord里面,原来的Activity页面进行onResume时,会将ActivityResult的数据提取出来进行处理,动态权限就回调onRequestPermissionsResult,其他情况回调onActivityResult。
2.3.2 权限获取与回调
-
检查权限时,在机器上弹出选择框,当你选择完是否获取权限后,执行onRequestPermissionResult回调函数,获取选择的结果。
-
机器弹出获取权限选择框,这时如果继续执行检查权限后的语句,不会等待权限是否获取,容易出现问题,所以一般是在执行onRequestPermissionResult之后确认获取权限的位置之后,再进行相关函数的执行。
-
权限获取示例,这里oncreate只要checkCameraPermission()就可以了,联动检查全部权限。
private static final int ST_PERMISSION_REQUEST_CAMERA = 1;
private static final int ST_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 2;
private static final int ST_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 3;
private void checkCameraPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {//只有当!=PackageManager.PERMISSION_GRANTED时候才执行,保证只在第一次打开软件时候申请权限(4)
requestPermissions(new String[]{Manifest.permission.CAMERA},
ST_PERMISSION_REQUEST_CAMERA);
}
}
}
private void checkReadPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
ST_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE);
}
}
}
private void checkWritePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
ST_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {//第一次打开软件可以进来
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == ST_PERMISSION_REQUEST_CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("----","cameraPermisssion");
checkReadPermission();//联动申请读
}
} else if (requestCode == ST_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("----","readPermisssion");
checkWritePermission();//联动申请写
}
} else if (requestCode == ST_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.e("----","writePermission");
} else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
Log.e("----","write申请失败");
}
}
-
蓝牙钥匙主页面oncreate方法中调用checkPermissions()检查权限。
private void checkPermissions() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//判断蓝牙是否开启
if (!bluetoothAdapter.isEnabled()) {
Toast.makeText(this, "Open ble", Toast.LENGTH_LONG).show();
return;
}
//清单中注册的权限集合
String[] permissions = {Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
List<String> permissionDeniedList = new ArrayList<>();
for (String permission : permissions) {
int permissionCheck = ContextCompat.checkSelfPermission(this, permission);
//判断权限是否开启,有权限
if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
onPermissionGranted(permission);
} else {
permissionDeniedList.add(permission);//无权限
}
}
//无权限列表不为空
if (!permissionDeniedList.isEmpty()) {
String[] deniedPermissions = permissionDeniedList.toArray(new String[permissionDeniedList.size()]);
ActivityCompat.requestPermissions(this, deniedPermissions, REQUEST_CODE_PERMISSION_LOCATION);
}
}
有权限调用onPermissionGranted(String permission)
private void onPermissionGranted(String permission) {
switch (permission) {
//GPS定位权限
case Manifest.permission.ACCESS_FINE_LOCATION:
//当前安卓sdk版本大于等于6.0并且没开GPS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkGPSIsOpen()) {
new AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("当前手机扫描蓝牙需要打开定位功能")
.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setPositiveButton("前往设置",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(intent, REQUEST_CODE_OPEN_GPS);
}
})
.setCancelable(false)
.show();
} else {
BleKeySdk.getInstance().startScan(10*1000,bleScanCallback);
}
break;
}
}
//检查GPS是否开启
private boolean checkGPSIsOpen() {
LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null)
return false;
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
两个回调方法,嵌套的GPS走onActivityResult方法。
@Override
public final void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_PERMISSION_LOCATION:
if (grantResults.length > 0) {
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
onPermissionGranted(permissions[i]);
}
}
}
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_OPEN_GPS) {
if (checkGPSIsOpen()) {
//setScanRule();
//startScan();
BleKeySdk.getInstance().startScan(60*10*1000,bleScanCallback);
}
}
}
扫描蓝牙钥匙
BleScanCallback bleScanCallback = new BleScanCallback(){
@Override
public void onScanStarted(boolean success) {
fab.setShowProgressBackground(true);
fab.setIndeterminate(true);
}
@Override
public void onScanning(BleDevice bleDevice) {
if (!map.containsKey(bleDevice.getMac())) {
map.put(bleDevice.getMac(), bleDevice);
bleDeviceAdapter.addData(bleDevice);
}
}
@Override
public void onScanFinished(List<BleDevice> scanResultList) {
fab.hideProgress();
}
};
onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_key_link);
// 全屏
getWindow()
.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
initView();
BleKeySdk.getInstance().initSdk(this, null);
checkPermissions();
}
private FloatingActionButton fab;//这里是一个浮动动画按钮,需要在buliding里提娜佳依赖
private void initView() {
mRecyclerView = findViewById(R.id.list);
LinearLayoutManager lm = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(lm);
bleDeviceAdapter = new BleDeviceAdapter(list);
mRecyclerView.setAdapter(bleDeviceAdapter);
bleDeviceAdapter.setOnItemClickListener(
new OnItemClickListener() {
//BaseQuickAdapter旧版本与新版本实现方法不一致
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
BleDevice bleDevice = (BleDevice) adapter.getData().get(position);
startActivity(
new Intent(SourceLockActivity.this, KeyActivity.class)
.putExtra("mac", bleDevice.getMac()));
}
});
fab = findViewById(R.id.floatingActionButton);
fab.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
map.clear();
bleDeviceAdapter.getData().clear();
BleKeySdk.getInstance().stopScan();
BleKeySdk.getInstance().startScan(10 * 1000, bleScanCallback);
}
});
}
2.4控件视图布局方式
2.4.1 文本显示
<TextView
android:id="@+id/bleName" //ID
android:layout_width&