Java部分
基础知识篇
八大基本类型
名称 | 大小(byte) |
boolean | 1 |
char | 2 |
byte | 1 |
short | 2 |
int | 4 |
long | 8 |
float | 4 |
double | 4 |
String、StringBuffer和StringBuilder
String声明的是不可变的对象,而StringBuffer和StringBuilder是可变的。但前者是线程安全的,而后者不是,同时后者的效率要高于前者,因此在多线程环境下会使用前者,否则后者。
多线程篇
线程和进程的区别
单位 | 特点 | |
进程 | 系统运行的基本单位 | 运行过程中相互独立,但每个进程包含的线程之间可互相影响 |
线程 | 独立运行的最小单位 | 一个进程包含多个线程,所有线程共享该进程的所有资源 |
进程通信方式
- 管道
- 共享内存
- 信号量机制(wait、notify)
- 消息队列通信(Handler)
Android部分
UI篇
scaleType属性
属性名 | 说明 |
center | 居中,不做任何缩放; 图片过大时,显示不全; 图片过小时,完整显示,有空白 |
centerCrop | 居中,以填满控件为目的; 保持宽高比缩放,直到图像宽高都 ≥ 控件宽高; 图片和控件宽高比例不等时,图片会被裁剪 |
centerInside | 居中,以图片正常显示为目的; 图片过大时,按原图比例缩小,直到宽高之一等于控件宽高之一; 图片过小时,完整显示,有空白 |
fitCenter | 居中; 保持宽高比缩放,直到宽高都 ≤ 控件宽高; 是ImageView的默认缩放方式 |
fitEnd | 居右侧或底部; 保持宽高比缩放,直到宽高都 ≤ 控件宽高 |
fitStart | 居左侧或上侧; 保持宽高比缩放,直到宽高都 ≤ 控件宽高 |
fitXY | 按照控件大小拉伸,不保持原比例,填满控件 |
matrix | 不改变原图大小,从控件左上角开始绘制,超出裁剪 |
不同分辨率对应的dpi
首先需要明确,想要一套布局适用多个分辨率,可以将组件大小和字体大小的单位分别改为dp和sp。其中dp无关像素,sp是可伸缩像素。
名称 | 与px的换算关系 | 对应分辨率 | 对应dpi |
ldpi | 0.75 | 240x320 | 120 |
mdpi | 1 | 320x480 | 160 |
hdpi | 1.5 | 480x800 | 240 |
xhdpi | 2 | 720x1280 | 320 |
xxhdpi | 3 | 1080x1920 | 480 |
性能调优的布局优化
有以下方式:
- 使用RelativeLayout代替LinearLayout,可以减少因为后者引起的嵌套层级
- 使用抽象布局标签include、merge和ViewStub
- 使用最新的ConstraintLayout,它不需要使用任何嵌套
include、merge和ViewStub的具体区别:
include可以用来引入另一个布局文件:
<include layout="@layout/list_item"/>
merge通常和include配套使用:
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<include layout="@layout/list_item"/>
</merge>
使用 <include>
时,默认情况下会在父布局中生成一个多余的视图层级。
这就是 <merge>
标签发挥作用的地方。当您使用 <merge>
标签包围 <include>
标签时,它告诉系统只合并引用布局中的视图层级,而不会生成多余的视图层级。这有助于减少视图层级,提高性能,并且可以使布局更具可读性。
ViewStub用于延迟加载,它允许您在程序运行时动态地向布局中添加视图,而不需要将这些视图包含在初始布局中:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ViewStub
android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/my_sub_tree"
android:layout_width="120dip"
android:layout_height="40dip" />
<!-- 可见或隐藏的其他视图 -->
</FrameLayout>
自定义View
开发方式包括:
- 组合控件
- 继承控件
- 自绘控件
Android版本篇
不同android版本之间的差异(此处仅列出11、12与他们前一版本之间的差异):
版本号(API) | 与前作的差异 |
11,API 30 |
|
12,API 31-32 |
|
第三方库篇
使用诸如okhttp、retrofit、EventBus等需要在gradle中implements的都是引用了第三方库。
序列化篇
先将一个对象序列化成可存储或传输的状态,传递给另一个activity或者其他地方后,再将其反序列化为一个新的对象。
多媒体
桌面的音视频小组件是如何实现“播放”、“上一曲”、“下一曲”这种操作的?
使用MediaSession和MediaController可以实现。
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.session.MediaControllerCompat;
import android.media.session.MediaSessionCompat;
import android.media.session.PlaybackStateCompat;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
public class MyMusicService extends Service {
private static final String TAG = "MyMusicService";
private MediaPlayer mediaPlayer;
private MediaSessionCompat mediaSession;
private final IBinder musicBinder = new MusicServiceBinder();
public class MusicServiceBinder extends Binder {
MyMusicService getService() {
return MyMusicService.this;
}
}
@Override
public void onCreate() {
super.onCreate();
// 初始化 MediaSession。
mediaSession = new MediaSessionCompat(this, TAG);
// 启用来自 MediaButtons 和 TransportControls 的回调。
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
// 不让 MediaButtons 在应用不可见时重新启动播放器。
mediaSession.setMediaButtonReceiver(null);
// 设置初始的 PlaybackState 包含 ACTION_PLAY,以便媒体按钮可以启动播放器。
PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
PlaybackStateCompat.ACTION_STOP);
mediaSession.setPlaybackState(stateBuilder.build());
// MySessionCallback 包含来自媒体控制器的回调方法。
mediaSession.setCallback(new MySessionCallback());
// 由于服务正在运行,启动 MediaSession。
mediaSession.setActive(true);
// 创建内部的 MediaPlayer 并将其附加到此会话。
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(mp -> {
// 当这首歌播放完毕时,跳转到下一首。
mediaSession.setPlaybackState(
stateBuilder.setState(PlaybackStateCompat.STATE_STOPPED, 0, 1).build());
});
// 为了本示例的目的,自动开始播放。
// 对于真实的应用程序,您应该让播放器处于停止状态,
// 直到用户请求播放。
startPlaying();
}
// ...
private void startPlaying() {
// 播放一首歌。
// 为了简单起见,我们只为持续时间设置一个随机的位置。
mediaPlayer.reset();
try {
mediaPlayer.setDataSource("http://sample-song-url.com");
mediaPlayer.prepare();
mediaPlayer.start();
} catch (Exception e) {
e.printStackTrace();
}
// 更新状态为 PLAYING。
PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PLAYING, mediaPlayer.getCurrentPosition(), 1f)
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
PlaybackStateCompat.ACTION_STOP);
mediaSession.setPlaybackState(stateBuilder.build());
}
// ...
@Override
public IBinder onBind(Intent intent) {
return musicBinder;
}
// ...
private class MySessionCallback extends MediaSessionCompat.Callback {
@Override
public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
// 将媒体按钮事件转发给 MediaController。
return MediaControllerCompat.getMediaController(MyMusicService.this)
.dispatchMediaButtonEvent(mediaButtonIntent);
}
@Override
public void onPlay() {
startPlaying();
}
@Override
public void onPause() {
mediaPlayer.pause();
PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_PAUSED, mediaPlayer.getCurrentPosition(), 1f)
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
PlaybackStateCompat.ACTION_STOP);
mediaSession.setPlaybackState(stateBuilder.build());
}
@Override
public void onSkipToNext() {
// 跳转到下一首。
startPlaying(); // 为了简单起见,只是重新开始当前的歌曲。
}
@Override
public void onSkipToPrevious() {
// 跳转到上一首。
startPlaying(); // 为了简单起见,只是重新开始当前的歌曲。
}
@Override
public void onStop() {
// 停止播放。
stopPlaying();
}
}
private void stopPlaying() {
// 停止播放。
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
// 更新状态为 STOPPED。
PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_STOPPED, 0, 1f)
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
PlaybackStateCompat.ACTION_SKIP_TO_NEXT |
PlaybackStateCompat.ACTION_STOP);
mediaSession.setPlaybackState(stateBuilder.build());
}
// ...
}