安卓开发——笔记(1)

记录安卓开发时,所遇到的问题及方法

调试输出

1
2
3
4
5
6
7
import android.util.Log;

Log.v("a", "Haha , this is a Verbose of MyAndroid. ");
Log.d("a", "Haha , this is a Debug of MyAndroid. ");
Log.i("a", "Haha , this is a Info of MyAndroid. ");
Log.w("a", "Haha , this is a Warning of MyAndroid. ");
Log.e("a", "Haha , this is a Error of MyAndroid. ");

点击事件获取文本内容

1
2
3
4
5
6
7
8
9
10
11
final TextView value = (TextView) findViewById(R.id.textView);

Button btn = new Button(this);
//绑定点击事件
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = ((Button) v).getText().toString();
value.setText(value.getText()+text);
}
});

xml里绑定事件并传参数

xml部分代码

1
2
3
<Button 
android:onClick="click"
android:tag="params"/>

java部分代码

1
2
3
public void click(View view){
String param = view.getTag().toString();
}

引用res里的资源,类型变为 View

通过加载器 LayoutInflater

1
2
LayoutInflater tableItem = LayoutInflater.from(this);
View viewItem = tableItem.inflate(R.layout.fbutton_item, null);

handler发送消息(线程间通讯)

子线程里无法调用ui,通过handler发送消息至ui线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private static final int SHOW_TOAST = 1;
private Handler mHandler = null;

@Override
public void onCreate(){
Message msg = new Message();
msg.what = SHOW_TOAST;
msg.obj = "信息";
mHandler.sendMessage(msg);
}

// 发送消息
private class MsgHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case SHOW_TOAST:
String text = msg.obj.toString();
Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
break;
default:
throw new IllegalStateException("Unexpected value: " + msg.what);
}
}
}

广播事件

Tip:

  • 可一个接收器 对应多个 action ( 用 intent-filter 包裹) 或 多个接收器
1
2
3
4
5
6
7
8
9
10
11
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>

将数据写入本地缓存

SharedPreferences

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private SharedPreferences sf;
private SharedPreferences.Editor edit;

public void onCreate() {
// 链接库
sf = getSharedPreferences(getResources().getString(R.string.app_name), Context.MODE_PRIVATE);
// 编辑器
edit = sf.edit();
// set 值
edit.putString("key","value");
edit.commit();
// get 值
sf.getString("key","");
}

播放mp3音频

  • main目录下 新建个 assets目录 存放mp3音频
  • MediaPlayer 播放音频
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
private MediaPlayer musicPlay = null;
private AssetManager assetManager = null;
private List<AssetFileDescriptor> musicQueue = new ArrayList<AssetFileDescriptor>();
// 初始化播放器
private void initPlayer(Context context) {
// 获取asset文件管理器
assetManager = context.getAssets();
// new 播放器
musicPlay = new MediaPlayer();
// 播放结束监听
musicPlay.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
// 存在播放队列
if (musicQueue.size() != 0) {
play(musicQueue.get(0));
musicQueue.remove(0);
}
return;
}
});
}

// 开始播放
private void play(AssetFileDescriptor music) {
try {
// 存在播放任务,追加队列中
if (musicPlay.isPlaying()) {
musicQueue.add(music);
return;
}
// 重置播放器
musicPlay.reset();
// 设置播放资源
musicPlay.setDataSource(music.getFileDescriptor(), music.getStartOffset(), music.getLength());
// 预加载
musicPlay.prepare();
// 开始
musicPlay.start();
} catch (IOException e) {
e.printStackTrace();
}
}

// 选择播放音频
private void selectMusic() {
try {
// 播放 test.mp3
this.play(assetManager.openFd("test.mp3"));
} catch (IOException e) {
e.printStackTrace();
}
}

解析JSON

  • 用 阿里的 fastjson

app 配置文件

1
2
3
dependencies {
implementation 'com.alibaba:fastjson:1.2.62'
}

简单dome

1
2
3
4
5
6
// 引
import com.alibaba.fastjson.JSONObject;

// 反序列化
JSONObject data = JSONObject.parseObject(res);
String type = data.getString("type");

socket

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 连接 socket
socket = new Socket(SOCKET_IP, SOCKET_PORT);

//构建IO
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
bw = new BufferedWriter(new OutputStreamWriter(os));

//读取服务器返回的消息
br = new BufferedReader(new InputStreamReader(is));

//向服务器端发送一条消息
try {
bw.write("msg" + "\n");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}

// 持续读消息
String res;
while ((res = br.readLine()) != null) {
// 当读到消息 do something
}

弹窗AlertDialog

基本用法

  • setTitle :为对话框设置标题
  • setIcon :为对话框设置图标
  • setMessage:为对话框设置内容
  • setView : 给对话框设置自定义样式
  • setItems :设置对话框要显示的一个list,一般用于显示几个命令时
  • setMultiChoiceItems :用来设置对话框显示一系列的复选框
  • setSingleChoiceItems :用来设置对话框显示一系列的单选框
  • setNeutralButton :普通按钮
  • setPositiveButton :给对话框添加”Yes”按钮
  • setNegativeButton :对话框添加”No”按钮
  • create : 创建对话框
  • show :显示对话框

dome

1
2
3
4
5
6
7
8
9
10
11
12
13
AlertDialog.Builder builder = new AlertDialog.Builder(this);

builder.setTitle("这是标题")
.setMessage("这是内容")
.setNegativeButton("取消", null)
.create();

builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do something
}
});
builder.show();

打开跳转至无障碍设置页面

1
2
3
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.getApplicationContext().startActivity(intent);

通过shell静默开启无障碍模式

  • root权限

开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 包名/程序名
String myAs = this.getPackageName() + "/" + MainAccessibilityService.class.getName();
// 获取目前设置无障碍模式的app
String nowAs = shellExec("settings get secure enabled_accessibility_services");
nowAs.replace("\n", "");
// 目前存在其它时,追加 : 隔开
if (nowAs.length() > 1 && !nowAs.contains(myAs)) {
nowAs = ":" + nowAs;
}
// 不存在时,即设置.存在直接启动
if(!nowAs.contains(myAs)){
String cmd = "settings put secure enabled_accessibility_services " + myAs + nowAs;
shellExec(cmd);
}
// 启动
shellExec("settings put secure accessibility_enabled 1");

关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 包名/程序名
String myAs = this.getPackageName() + "/" + MainAccessibilityService.class.getName();
// 获取目前的配置
String nowAs = shellExec("settings get secure enabled_accessibility_services");
nowAs.replace("\n", "");
// 找到需关闭的程序对应下标
int index = nowAs.indexOf(myAs);
// 找到后
if (index >= 0) {
// 前面的 : 下标
int beforeIndex = nowAs.lastIndexOf(":", index);
// 后面的 : 下标
int afterIndex = nowAs.indexOf(":", index);
// 判断下,得到 需关闭程序+: 的头尾 下标
if (beforeIndex < 0) beforeIndex = 0;
if (afterIndex < 0) afterIndex = nowAs.length();
else afterIndex++;
// 截取
String As = nowAs.substring(0, beforeIndex) + nowAs.substring(afterIndex, nowAs.length());
// 判断是否为空
if (As.length() > 0) {
shellExec("settings put secure enabled_accessibility_services " + As);
shellExec("settings put secure accessibility_enabled 1");
} else {
shellExec("settings put secure enabled_accessibility_services ''");
shellExec("settings put secure accessibility_enabled 0");
}
}

执行shell 命令

简易版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private String shellExec(String cmd) {
StringBuilder result = new StringBuilder();
try {
// Log.i(Tag, "start shell command");

Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("su");

DataOutputStream os = new DataOutputStream(process.getOutputStream());

os.write(cmd.getBytes());
os.writeBytes("\n");
os.flush();
os.writeBytes("exit\n");
os.flush();

BufferedReader successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));

String str;
while ((str = errorResult.readLine()) != null) {
result.append(str + "\n");
}
while ((str = successResult.readLine()) != null) {
result.append(str + "\n");
}


// Log.i(Tag, result.toString());

// Log.i(Tag, "end shell");
os.close();
successResult.close();
errorResult.close();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}

静默安装apk

  • root 权限
  • su 下执行
1
2
3
4
// shell 运行命令
shellExec("pm install xxx/xxx.apk");
// 覆盖安装
shellExec("pm install -r xxx/xxx.apk");

调用系统安装apk (需手动点击安装)

1
2
3
4
5
6
7
8
9
10
11
12
// 安装路径
String path = "xxx/xxx.apk";
File file = new File(path);
// 是否存在
if(file.exists()){
Uri fileUri = Uri.fromFile(file);
// 执行安装
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(fileUri, "application/vnd.android.package-archive");
installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(installIntent);
}

Tip

  • 字体单位 用 sp

  • 常用单位dp