home archives github knives links
tags android studio android adb java
categories
only title title and content
Android开发笔记

Music开发笔记

CSDN:实例
cnblogs:其他几种方式

音乐进度

MediaPlayer

MediaPlayer参数–简书

时长

CSDN:数字格式化

total_time = MainPlayer.player.getDuration();
SimpleDateFormat format = new SimpleDateFormat("mm:ss");

// TODO 更新总时长
tmp = new Date(total_time);
formatTime = format.format(tmp);
MainPlayer.totalTime.setText(formatTime);

进度条

媒体信号

CSDN:配对全过程
CSDN:简易

CSDN

  1. 创建一个继承BroadcastReceiver的类
public class MediaReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {// 重载方法
String action = intent.getAction();
if (action != null) {
MainPlayer.infoLog("action: " + action);// TODO debug
switch (action) {
// 有线耳机状态改变
case Intent.ACTION_HEADSET_PLUG:
int mediaState = intent.getIntExtra("state", 0);// 判断插拔

// 蓝牙连接状态改变
case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:// 安卓端主动改变蓝牙状态
int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);// 获取蓝牙状态

// 接收蓝牙/媒体按键信号
case Intent.ACTION_MEDIA_BUTTON:
KeyEvent keyEvent = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);// 获取键码
}
}
}

// receiver注册函数
public void registerReceiver(Context context) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName name = new ComponentName(context.getPackageName(), MediaReceiver.class.getName());
audioManager.registerMediaButtonEventReceiver(name);
}

public void unregisterReceiver(Context context){
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName name = new ComponentName(context.getPackageName(), MediaReceiver.class.getName());
audioManager.unregisterMediaButtonEventReceiver(name);
}
}

注意点:

  1. 修改AndroidManifest.xml

父节点为application,android:name要和BroadcastReceiver的子类名相同,priority可以不要

<receiver android:name=".MediaReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.MEDIA_BUTTON"></action>
</intent-filter>
</receiver>
  1. 初始化MediaReceiver
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 获取蓝牙适配器
receiver = new MediaReceiver(this);// 接收蓝牙信号

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);// 监视蓝牙设备与APP连接的状态
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);// 监听有线耳机的插拔
intentFilter.addAction(Intent.ACTION_MEDIA_BUTTON);// TODO

registerReceiver(this.receiver, intentFilter);// 注册广播
receiver.registerReceiver(this);// 初始化广播

adb

华为手机配置adb:*#*#2846579#*#*->后台设置->usb端口设置->生产模式

adb devices
adb tcpip 5555
# 拔掉数据线
adb connect 手机ip

若安卓设备显示offline,可能是由于adb版本过低

蓝牙连接管理

无需在AndroidManifest里注册

蓝牙连接

Method createBond = device.getClass().getMethod("createBond");
createBond.setAccessible(true);
result = (Boolean) createBond.invoke(device);
  1. 注意区分已经配对的设备
  2. 特殊的蓝牙设备仍未解决

状态栏部件

创建

简书:notification channel

可使用NotificationCompatNotification,注意常量取值

NotificationManager notificationManager = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager = getSystemService(NotificationManager.class);
CharSequence name = "fuck";// 通知渠道名称
String description = "shit";
String id = "111";
NotificationChannel channel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(description);
notificationManager.createNotificationChannel(channel);
}

NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this, id)
.setSmallIcon(R.drawable.ic_launcher_background)
// .setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);

显示

  1. 首先保证系统更新并能够支持notification category

  2. 保证给应用程序提供锁屏通知权限

startForeground

常驻通知栏

for (int i = 0; i < 10; i ++) {
stopForeground(true);
Thread.sleep(500);
startForeground(10, builder.build());
}
  1. mainifest节点下增加权限

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  2. 清除通知不要使用deleteNotificationChannel,否则无法控制音效/震动,使用stopForeground

notify

可以被作为通知清除

for (int i = 0; i < 10; i ++) {
notificationManager.cancel(0);
Thread.sleep(500);
notificationManager.notify(0, builder.build());
}

注意channelidBuilderid要一致

通信

  1. 注意不同intent要使用不同的requestCode
  2. 切换到MainActivity,MainActivity要使用singleTask
    Intent intent = new Intent(this, MusicList.class);
    remoteViews.setOnClickPendingIntent(R.id.button_open, PendingIntent.getActivity(this, 6, intent, 0));
  3. 使用空pendingIntent来防止点击通知会消失

锁屏通知

只能够从系统中手动打开权限

事件 intent
亮屏 Intent.ACTION_SCREEN_ON
关屏 Intent.ACTION_SCREEN_OFF
解锁 Intent.ACTION_USER_PRESENT

桌面部件

在进程完全被杀死后通过widget启动app

  1. PendingIntent.getActivity()/startActivity()
  2. PendingIntent.getForegroundService()/startForegroundService(),不要使用Service

Editor开发笔记

获取读写权限

AndroidManifest

<!-- manifest节点下  -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Activity

String permission = "android.permission.WRITE_EXTERNAL_STORAGE";
int check_result = ActivityCompat.checkSelfPermission(this, permission);// `允许`返回0,`拒绝`返回-1
if (check_result != PackageManager.PERMISSION_GRANTED) {// 没有`写`权限
ActivityCompat.requestPermissions(this, new String[]{permission}, 1);// 获取`写`权限
}

关联文件类型

文本文件

<intent-filter android:scheme="http"
tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/*"/>
</intent-filter>

修改默认Toast

static public void info(Context context, String log) {
Toast toast = Toast.makeText(context, log, Toast.LENGTH_SHORT);
View view = toast.getView();
view.setBackgroundResource(R.drawable.toast);
TextView textView = view.findViewById(android.R.id.message);
textView.setTextColor(Color.rgb(0xff, 0xff, 0xff));
toast.show();
}

由外部打开文件

Intent intent = getIntent();
String action = intent.getAction();// 判断本activity启动的方式
if (action.equals("android.intent.action.VIEW")) {// 由其他软件打开本软件
}

控制activity数目

<activity android:name=".Editor"
android:launchMode="singleTask">

获取根view

View view = getWindow().getDecorView().findViewById(android.R.id.content);

数据保存

SharedPreferences

SharedPreferences:基于xml的键值对,存储于/data/data/应用程序包/shared_prefs

提示框/窗口

Dialog

参考

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.save_layout);

// 初始化`保存`按钮
yes.setOnClickListener(new View.OnClickListener() {//
});

// 初始化`取消`按钮
cancel.setOnClickListener(new View.OnClickListener() {
});

// 初始化`删除`按钮
no.setOnClickListener(new View.OnClickListener() {
});
}

private void initButton() {
// 初始化按钮
yes = findViewById(R.id.yes_button);
cancel = findViewById(R.id.cancel_button);
no = findViewById(R.id.no_button);
}
myWindow = new MyWindow(MainActivity.this, R.style.save_style);
myWindow.setCanceledOnTouchOutside(false);
myWindow.setOnDismissListener(new DialogInterface.OnDismissListener() {
});
myWindow.show();// TODO 获取点击结果
public class MyWindow extends PopupWindow {
public Button yes;
public Button cancel;
public Button no;
public int result;

public MyWindow(Context context, View view) {
super(context);
this.setContentView(LayoutInflater.from(context).inflate(R.layout.manager_layout, null));
// this.setOutsideTouchable(false);
this.setFocusable(true);// 否则无法进行edittext输入

this.showAsDropDown(view);
this.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
this.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
}
}

DialogFragment

参考

public class MyWindow extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.manager_layout, container);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0x00000000));
return view;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, android.R.style.Theme);
}
}
myWindow = new MyWindow();
myWindow.show(getSupportFragmentManager(), "edit");

全景相机开发笔记

自定义相机界面


过期内容

调用系统文件浏览器

1.绑定点击事件

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");// 所有类型文件
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, 1);

2.根据requestCode接收数据

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (requestCode == 1) {// `打开`按钮
...
}
}
}
}
  1. Intent.ACTION_GET_CONTENT:用于调用系统程序,比如一个打开一个文件的时候会提示你用哪个软件打开

  2. Intent.setType():设置默认打开格式,如"video/*","audio/amr"

调用相册

Intent intent = new Intent(Intent.ACTION_PICK);//intent  action属性
intent.setType("image/*");
startActivityForResult(intent, 2);

通用框架修改

drawable

添加buttondialog

values

删掉styles,修改colors,添加styles_button(按钮)和styles_tab(工具栏)

manifests

增加权限,删除label,增加android:launchMode="singleTask"

相机相关