2024年Android最全Android 音乐APP(一)扫描本地音乐(1),42岁程序员面试有希望吗

总结

可以看出,笔者的工作学习模式便是由以下 「六个要点」 组成:

❝ 多层次的工作/学习计划 + 番茄工作法 + 定额工作法 + 批处理 + 多任务并行 + 图层工作法❞

希望大家能将这些要点融入自己的工作学习当中,我相信一定会工作与学习地更富有成效。

下面是我学习用到的一些书籍学习导图,以及系统的学习资料。每一个知识点,都有对应的导图,学习的资料,视频,面试题目。

**如:我需要学习 **Flutter的知识。(大家可以参考我的学习方法)

  • Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)

  • Flutter进阶学习全套手册

  • Flutter进阶学习全套视频

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

⑥ 获取音乐数据

首先需要些几个工具类,方便APP后面的开发。第一个是日志,这里不用系统自带的日志。在utils包下新建一个BLog类。里面的代码如下:

package com.llw.goodmusic.utils;

import android.text.TextUtils;

import android.util.Log;

import org.json.JSONArray;

import org.json.JSONException;

import org.json.JSONObject;

/**

  • 日志

  • @author llw

*/

public class BLog {

private static boolean IS_SHOW_LOG = true;

private static final String DEFAULT_MESSAGE = “execute”;

private static final String LINE_SEPARATOR = System.getProperty(“line.separator”);

private static final int JSON_INDENT = 4;

private static final int V = 0x1;

private static final int D = 0x2;

private static final int I = 0x3;

private static final int W = 0x4;

private static final int E = 0x5;

private static final int A = 0x6;

private static final int JSON = 0x7;

public static void init(boolean isShowLog) {

IS_SHOW_LOG = isShowLog;

}

public static void v() {

printLog(V, null, DEFAULT_MESSAGE);

}

public static void v(String msg) {

printLog(V, null, msg);

}

public static void v(String tag, String msg) {

printLog(V, tag, msg);

}

public static void d() {

printLog(D, null, DEFAULT_MESSAGE);

}

public static void d(String msg) {

printLog(D, null, msg);

}

public static void d(String tag, String msg) {

printLog(D, tag, msg);

}

public static void i() {

printLog(I, null, DEFAULT_MESSAGE);

}

public static void i(String msg) {

printLog(I, null, msg);

}

public static void i(String tag, String msg) {

printLog(I, tag, msg);

}

public static void w() {

printLog(W, null, DEFAULT_MESSAGE);

}

public static void w(String msg) {

printLog(W, null, msg);

}

public static void w(String tag, String msg) {

printLog(W, tag, msg);

}

public static void e() {

printLog(E, null, DEFAULT_MESSAGE);

}

public static void e(String msg) {

printLog(E, null, msg);

}

public static void e(String tag, String msg) {

printLog(E, tag, msg);

}

public static void a() {

printLog(A, null, DEFAULT_MESSAGE);

}

public static void a(String msg) {

printLog(A, null, msg);

}

public static void a(String tag, String msg) {

printLog(A, tag, msg);

}

public static void json(String jsonFormat) {

printLog(JSON, null, jsonFormat);

}

public static void json(String tag, String jsonFormat) {

printLog(JSON, tag, jsonFormat);

}

private static void printLog(int type, String tagStr, String msg) {

if (!IS_SHOW_LOG) {

return;

}

StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

int index = 4;

String className = stackTrace[index].getFileName();

String methodName = stackTrace[index].getMethodName();

int lineNumber = stackTrace[index].getLineNumber();

String tag = (tagStr == null ? className : tagStr);

methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);

StringBuilder stringBuilder = new StringBuilder();

stringBuilder.append(“[ (”).append(className).append(“:”).append(lineNumber).append(“)#”).append(methodName).append(" ] ");

if (msg != null && type != JSON) {

stringBuilder.append(msg);

}

String logStr = stringBuilder.toString();

switch (type) {

case V:

Log.v(tag, logStr);

break;

case D:

Log.d(tag, logStr);

break;

case I:

Log.i(tag, logStr);

break;

case W:

Log.w(tag, logStr);

break;

case E:

Log.e(tag, logStr);

break;

case A:

Log.wtf(tag, logStr);

break;

case JSON: {

if (TextUtils.isEmpty(msg)) {

Log.d(tag, “Empty or Null json content”);

return;

}

String message = null;

try {

if (msg.startsWith(“{”)) {

JSONObject jsonObject = new JSONObject(msg);

message = jsonObject.toString(JSON_INDENT);

} else if (msg.startsWith(“[”)) {

JSONArray jsonArray = new JSONArray(msg);

message = jsonArray.toString(JSON_INDENT);

}

} catch (JSONException e) {

e(tag, e.getCause().getMessage() + “\n” + msg);

return;

}

printLine(tag, true);

message = logStr + LINE_SEPARATOR + message;

String[] lines = message.split(LINE_SEPARATOR);

StringBuilder jsonContent = new StringBuilder();

for (String line : lines) {

jsonContent.append("║ ").append(line).append(LINE_SEPARATOR);

}

Log.d(tag, jsonContent.toString());

printLine(tag, false);

}

break;

default:

break;

}

}

private static void printLine(String tag, boolean isTop) {

if (isTop) {

Log.d(tag, “╔═══════════════════════════════════════════════════════════════════════════════════════”);

} else {

Log.d(tag, “╚═══════════════════════════════════════════════════════════════════════════════════════”);

}

}

}

为了方便使用,我再加上一个ToastUtils,代码如下:

package com.llw.goodmusic.utils;

import android.content.Context;

import android.widget.Toast;

public class ToastUtils {

/**

  • 长消息

  • @param context 上下文参数

  • @param llw 内容

*/

public static void longToast(Context context, CharSequence llw) {

Toast.makeText(context.getApplicationContext(), llw, Toast.LENGTH_LONG).show();

}

/**

  • 短消息

  • @param context 上下文参数

  • @param llw 内容

*/

public static void shortToast(Context context, CharSequence llw) {

Toast.makeText(context.getApplicationContext(), llw, Toast.LENGTH_SHORT).show();

}

}

既然是歌曲信息肯定是需要一个实体bean的。在com.llw.goodmusic下新建一个bean包。在包下新建一个Song类,代码如下:

package com.llw.goodmusic.bean;

/**

  • 歌曲Bean

  • @author llw

*/

public class Song {

/**

  • 歌手

*/

public String singer;

/**

  • 歌曲名

*/

public String song;

/**

  • 专辑名

*/

public String album;

/**

  • 专辑图片

*/

public String album_art;

/**

  • 歌曲的地址

*/

public String path;

/**

  • 歌曲长度

*/

public int duration;

/**

  • 歌曲的大小

*/

public long size;

/**

  • 当前歌曲选中

*/

public boolean isCheck;

public String getSinger() {

return singer;

}

public void setSinger(String singer) {

this.singer = singer;

}

public String getSong() {

return song;

}

public void setSong(String song) {

this.song = song;

}

public String getPath() {

return path;

}

public void setPath(String path) {

this.path = path;

}

public int getDuration() {

return duration;

}

public void setDuration(int duration) {

this.duration = duration;

}

public long getSize() {

return size;

}

public void setSize(long size) {

this.size = size;

}

public String getAlbum() {

return album;

}

public void setAlbum(String album) {

this.album = album;

}

public String getAlbum_art() {

return album_art;

}

public void setAlbum_art(String album_art) {

this.album_art = album_art;

}

public boolean isCheck() {

return isCheck;

}

public void setCheck(boolean check) {

isCheck = check;

}

}

然后还有一个最主要的工具类MusicUtils,代码如下:

package com.llw.goodmusic.utils;

import android.content.Context;

import android.database.Cursor;

import android.provider.MediaStore;

import com.llw.goodmusic.bean.Song;

import java.util.ArrayList;

import java.util.List;

/**

  • 音乐扫描工具

  • @author llw

*/

public class MusicUtils {

/**

  • 扫描系统里面的音频文件,返回一个list集合

*/

public static List getMusicData(Context context) {

List list = new ArrayList();

// 媒体库查询语句(写一个工具类MusicUtils)

Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null,

null, MediaStore.Audio.Media.IS_MUSIC);

if (cursor != null) {

while (cursor.moveToNext()) {

Song song = new Song();

//歌曲名称

song.song = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));

//歌手

song.singer = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));

//专辑名

song.album = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));

//歌曲路径

song.path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));

//歌曲时长

song.duration = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));

//歌曲大小

song.size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));

if (song.size > 1000 * 800) {

// 注释部分是切割标题,分离出歌曲名和歌手 (本地媒体库读取的歌曲信息不规范)

if (song.song.contains(“-”)) {

String[] str = song.song.split(“-”);

song.singer = str[0];

song.song = str[1];

}

list.add(song);

}

}

// 释放资源

cursor.close();

}

return list;

}

}

这个扫描请求的工具类是无法扫描到加密的音乐文件的,能扫描到mp3、flac格式的音乐文件,其他的格式我没有试过,因为现在网易云和QQ音乐下载本地歌曲有很多是需要VIP才能下载的,这种音乐下载之后是加密的音乐文件,QQ音乐的下载的加密文件是 .qmc后缀开头的,网易的我就不知道了,因为我没有开网易云音乐的VIP,不过这些加密文件有一个共同点,不允许其他播放器播放,这个就很恶心了,也就是说哪怕你通过文件夹路径扫描到添加到你自己的音乐播放列表里面之后也播放不了。因为加密规则你不知道,你就不能去解密,解密不了自然播放不了。

最终你的项目目录会如下图所示

在这里插入图片描述

如果有出入的话可以照这个来改一下,或者可以自己分包也可以。

⑦ 数据显示

做一个列表来显示本地的歌曲列表,列表由item决定,item需要新建一个xml文件,如下图这种。

在这里插入图片描述

在layout下面新建一个item_music_rv_list.xml,布局如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:id=“@+id/item_music”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginBottom=“@dimen/dp_1”

android:background=“@color/app_color”

android:foreground=“?android:attr/selectableItemBackground”

android:gravity=“center_vertical”

android:orientation=“horizontal”

android:padding=“@dimen/dp_10”>

<TextView

android:id=“@+id/tv_position”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_margin=“2dp”

android:text=“1”

android:textColor=“@color/white”

android:textSize=“@dimen/sp_16” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginLeft=“@dimen/dp_10”

android:orientation=“vertical”>

<TextView

android:id=“@+id/tv_song_name”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:maxLines=“1”

android:text=“歌曲名”

android:textColor=“@color/white”

android:textSize=“@dimen/sp_18” />

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“@dimen/dp_4”>

<TextView

android:id=“@+id/tv_singer”

android:layout_width=“0dp”

android:layout_height=“wrap_content”

android:layout_weight=“1”

android:ellipsize=“end”

android:maxLines=“1”

android:text=“歌手”

android:textColor=“@color/white”

android:textSize=“@dimen/sp_14” />

<TextView

android:id=“@+id/tv_duration_time”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_marginLeft=“12dp”

android:text=“时间”

android:textColor=“@color/white”

android:textSize=“@dimen/sp_14” />

里面的尺寸都是放在dimen.xml文件里面的,放在values.xml下,和colors.xml同级,这个我也贴一下代码

<?xml version="1.0" encoding="utf-8"?>

0dp

0.1dp

0.5dp

1dp

1.5dp

2dp

2.5dp

3dp

3.5dp

4dp

4.5dp

5dp

6dp

7dp

8dp

9dp

10dp

11dp

12dp

13dp

14dp

15dp

16dp

17dp

18dp

19dp

20dp

21dp

22dp

23dp

24dp

25dp

26dp

27dp

28dp

29dp

30dp

31dp

32dp

33dp

34dp

35dp

36dp

37dp

38dp

39dp

40dp

41dp

42dp

43dp

44dp

45dp

46dp

47dp

48dp

49dp

50dp

51dp

52dp

53dp

54dp

55dp

56dp

57dp

58dp

59dp

60dp

61dp

62dp

63dp

64dp

65dp

66dp

67dp

68dp

69dp

70dp

71dp

72dp

73dp

74dp

75dp

76dp

77dp

78dp

79dp

80dp

81dp

82dp

83dp

84dp

85dp

86dp

87dp

88dp

89dp

90dp

91dp

92dp

93dp

94dp

95dp

96dp

97dp

98dp

99dp

100dp

101dp

102dp

103dp

104dp

105dp

106dp

107dp

108dp

109dp

110dp

111dp

112dp

113dp

114dp

115dp

116dp

117dp

118dp

119dp

120dp

121dp

122dp

123dp

124dp

125dp

126dp

127dp

128dp

129dp

130dp

131dp

132dp

133dp

134dp

135dp

136dp

137dp

138dp

139dp

140dp

141dp

142dp

143dp

144dp

145dp

146dp

147dp

148dp

149dp

150dp

151dp

152dp

153dp

154dp

155dp

156dp

157dp

158dp

159dp

160dp

161dp

162dp

163dp

164dp

165dp

166dp

167dp

168dp

169dp

170dp

171dp

172dp

173dp

174dp

175dp

176dp

177dp

178dp

179dp

180dp

181dp

182dp

183dp

184dp

185dp

186dp

187dp

188dp

189dp

190dp

191dp

192dp

193dp

194dp

195dp

196dp

197dp

198dp

199dp

200dp

201dp

202dp

203dp

204dp

205dp

206dp

207dp

208dp

209dp

210dp

211dp

212dp

213dp

214dp

215dp

216dp

217dp

218dp

219dp

220dp

221dp

222dp

223dp

224dp

225dp

226dp

227dp

228dp

229dp

230dp

231dp

232dp

233dp

234dp

235dp

236dp

237dp

238dp

239dp

240dp

241dp

242dp

243dp

244dp

245dp

246dp

247dp

248dp

249dp

250dp

251dp

252dp

253dp

254dp

255dp

256dp

257dp

258dp

259dp

260dp

261dp

262dp

263dp

264dp

265dp

266dp

267dp

268dp

269dp

270dp

271dp

272dp

273dp

274dp

275dp

276dp

277dp

278dp

279dp

280dp

281dp

282dp

283dp

284dp

285dp

286dp

287dp

288dp

289dp

290dp

291dp

292dp

293dp

294dp

295dp

296dp

297dp

298dp

299dp

300dp

301dp

302dp

303dp

304dp

305dp

306dp

307dp

308dp

309dp

310dp

311dp

312dp

313dp

314dp

315dp

316dp

317dp

318dp

319dp

320dp

321dp

322dp

323dp

324dp

325dp

326dp

327dp

328dp

329dp

330dp

331dp

332dp

333dp

334dp

335dp

336dp

337dp

338dp

339dp

340dp

341dp

342dp

343dp

344dp

345dp

346dp

347dp

348dp

349dp

350dp

351dp

352dp

353dp

354dp

355dp

356dp

357dp

358dp

359dp

360dp

365dp

370dp

400dp

410dp

422dp

472dp

500dp

600dp

640dp

720dp

6sp

7sp

8sp

9sp

10sp

11sp

12sp

13sp

14sp

15sp

16sp

17sp

18sp

19sp

20sp

21sp

22sp

23sp

24sp

25sp

26sp

27sp

28sp

29sp

30sp

31sp

32sp

33sp

34sp

35sp

36sp

37sp

38sp

40sp

42sp

48sp

item布局有了,还要一个适配器,在com.llw.goodmusic包下新建一个adapter包,然后新建一个MusicListAdapter类。里面的代码如下:

package com.llw.goodmusic.adapter;

import androidx.annotation.Nullable;

import com.chad.library.adapter.base.BaseQuickAdapter;

import com.chad.library.adapter.base.BaseViewHolder;

import com.llw.goodmusic.R;

import com.llw.goodmusic.bean.Song;

import com.llw.goodmusic.utils.DateTimeUtils;

import java.util.List;

/**

  • 音乐列表适配器

  • @author llw

*/

public class MusicListAdapter extends BaseQuickAdapter<Song, BaseViewHolder> {

public MusicListAdapter(int layoutResId, @Nullable List data) {

super(layoutResId, data);

}

@Override

protected void convert(BaseViewHolder helper, Song item) {

//给控件赋值

int duration = item.duration;

String time = DateTimeUtils.formatTime(duration);

//歌曲名称

helper.setText(R.id.tv_song_name, item.getSong().trim())

//歌手 - 专辑

.setText(R.id.tv_singer, item.getSinger() + " - " + item.getAlbum())

//歌曲时间

.setText(R.id.tv_duration_time, time)

//歌曲序号,因为getAdapterPosition得到的位置是从0开始,故而加1,

//是因为位置和1都是整数类型,直接赋值给TextView会报错,故而拼接了""

.setText(R.id.tv_position, helper.getAdapterPosition() + 1 + “”);

//给item添加点击事件,点击之后传递数据到播放页面或者在本页面进行音乐播放

helper.addOnClickListener(R.id.item_music);

//点击后改变文字颜色

if (item.isCheck()) {

helper.setTextColor(R.id.tv_position, mContext.getColor(R.color.gold_color))

.setTextColor(R.id.tv_song_name, mContext.getColor(R.color.gold_color))

.setTextColor(R.id.tv_singer, mContext.getColor(R.color.gold_color))

.setTextColor(R.id.tv_duration_time, mContext.getColor(R.color.gold_color));

} else {

helper.setTextColor(R.id.tv_position, mContext.getColor(R.color.white))

.setTextColor(R.id.tv_song_name, mContext.getColor(R.color.white))

.setTextColor(R.id.tv_singer, mContext.getColor(R.color.white))

.setTextColor(R.id.tv_duration_time, mContext.getColor(R.color.white));

}

}

/**

  • 刷新数据

*/

public void changeState() {

notifyDataSetChanged();

}

}

上面的代码,除了基本的数据填充之外也没有什么好说,只有一个点击歌曲时更改文字颜色,类似与一般的音乐APP歌曲的效果。当在Activity点击item时,调用changeState方法刷新数据。

好了,一切的准备工作都做完了。看起来这个功能好像没啥东西,但是要想的细节是很多的。下面回到LocalMusicActivity。

定义一些需要的变量

private Toolbar toolbar;

/**

  • 歌曲列表

*/

private RecyclerView rvMusic;

/**

  • 扫描歌曲布局

*/

private LinearLayout layScanMusic;

/**

  • 歌曲适配器

*/

private MusicListAdapter mAdapter;

/**

  • 歌曲列表

*/

private List mList = new ArrayList<>();

/**

  • 上一次点击的位置

*/

private int oldPosition = -1;

/**

  • 初始化控件级页面的业务逻辑

*/

private void initView() {

ActivityLocalMusicBinding binding = DataBindingUtil.setContentView(context, R.layout.activity_local_music);

toolbar = binding.toolbar;

rvMusic = binding.rvMusic;

layScanMusic = binding.layScanMusic;

Back(toolbar);

//当进入页面时发现有缓存数据时,则隐藏扫描布局,直接获取本地数据。

if (SPUtils.getBoolean(Constant.LOCAL_MUSIC_DATA, false, context)) {

//省去一个点击扫描的步骤

layScanMusic.setVisibility(View.GONE);

permissionsRequest();

}

}

新建一个方法,在权限通过时调用

在这里插入图片描述

方法如下:

/**

  • 获取音乐列表

*/

private void getMusicList() {

//清除列表数据

mList.clear();

//将扫描到的音乐赋值给音乐列表

mList = MusicUtils.getMusicData(this);

if (mList != null && mList.size() > 0) {

//是否有缓存歌曲

SPUtils.putBoolean(Constant.LOCAL_MUSIC_DATA, true, context);

layScanMusic.setVisibility(View.GONE);

//显示本地音乐

showLocalMusicData();

} else {

show(“兄嘚,你是一无所有啊~”);

}

}

然后再看showLocalMusicData方法:

/**

  • 显示本地音乐数据

*/

private void showLocalMusicData() {

//指定适配器的布局和数据源

mAdapter = new MusicListAdapter(R.layout.item_music_rv_list, mList);

//线性布局管理器,可以设置横向还是纵向,RecyclerView默认是纵向的,所以不用处理,如果不需要设置方向,代码还可以更加的精简如下

总结

首先是感觉自己的基础还是不够吧,大厂好像都喜欢问这些底层原理。

另外一部分原因在于资料也还没有看完,一面时凭借那份资料考前突击恶补个几天居然也能轻松应对(在这里还是要感谢那份资料,真的牛),于是自我感觉良好,资料就没有怎么深究下去了。

之前的准备只涉及了Java、Android、计网、数据结构与算法这些方面,面对面试官对其他基础课程的考察显得捉襟见肘。

下一步还是要查漏补缺,进行针对性复习。

最后的最后,那套资料这次一定要全部看完,是真的太全面了,各个知识点都涵盖了,几乎我面试遇到的所有问题的知识点这里面都有!希望大家不要犯和我一样的错误呀!!!一定要看完!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

new ArrayList<>();

/**

  • 上一次点击的位置

*/

private int oldPosition = -1;

/**

  • 初始化控件级页面的业务逻辑

*/

private void initView() {

ActivityLocalMusicBinding binding = DataBindingUtil.setContentView(context, R.layout.activity_local_music);

toolbar = binding.toolbar;

rvMusic = binding.rvMusic;

layScanMusic = binding.layScanMusic;

Back(toolbar);

//当进入页面时发现有缓存数据时,则隐藏扫描布局,直接获取本地数据。

if (SPUtils.getBoolean(Constant.LOCAL_MUSIC_DATA, false, context)) {

//省去一个点击扫描的步骤

layScanMusic.setVisibility(View.GONE);

permissionsRequest();

}

}

新建一个方法,在权限通过时调用

在这里插入图片描述

方法如下:

/**

  • 获取音乐列表

*/

private void getMusicList() {

//清除列表数据

mList.clear();

//将扫描到的音乐赋值给音乐列表

mList = MusicUtils.getMusicData(this);

if (mList != null && mList.size() > 0) {

//是否有缓存歌曲

SPUtils.putBoolean(Constant.LOCAL_MUSIC_DATA, true, context);

layScanMusic.setVisibility(View.GONE);

//显示本地音乐

showLocalMusicData();

} else {

show(“兄嘚,你是一无所有啊~”);

}

}

然后再看showLocalMusicData方法:

/**

  • 显示本地音乐数据

*/

private void showLocalMusicData() {

//指定适配器的布局和数据源

mAdapter = new MusicListAdapter(R.layout.item_music_rv_list, mList);

//线性布局管理器,可以设置横向还是纵向,RecyclerView默认是纵向的,所以不用处理,如果不需要设置方向,代码还可以更加的精简如下

总结

首先是感觉自己的基础还是不够吧,大厂好像都喜欢问这些底层原理。

另外一部分原因在于资料也还没有看完,一面时凭借那份资料考前突击恶补个几天居然也能轻松应对(在这里还是要感谢那份资料,真的牛),于是自我感觉良好,资料就没有怎么深究下去了。

之前的准备只涉及了Java、Android、计网、数据结构与算法这些方面,面对面试官对其他基础课程的考察显得捉襟见肘。

下一步还是要查漏补缺,进行针对性复习。

最后的最后,那套资料这次一定要全部看完,是真的太全面了,各个知识点都涵盖了,几乎我面试遇到的所有问题的知识点这里面都有!希望大家不要犯和我一样的错误呀!!!一定要看完!
[外链图片转存中…(img-s2jX8jtk-1715705660510)]

[外链图片转存中…(img-k1eMgA9B-1715705660511)]

[外链图片转存中…(img-5BaEMKAQ-1715705660511)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值