Android应用--简、美音乐播放器原型放送(作者:小巫)

private boolean isFirstTime = true;

private boolean isPlaying; // 正在播放

private boolean isPause; // 暂停

private boolean isNoneShuffle = true; // 顺序播放

private boolean isShuffle = false; // 随机播放

private int listPosition = 0; //标识列表位置

private HomeReceiver homeReceiver; //自定义的广播接收器

//一系列动作

public static final String UPDATE_ACTION = “com.wwj.action.UPDATE_ACTION”; //更新动作

public static final String CTL_ACTION = “com.wwj.action.CTL_ACTION”; //控制动作

public static final String MUSIC_CURRENT = “com.wwj.action.MUSIC_CURRENT”; //当前音乐改变动作

public static final String MUSIC_DURATION = “com.wwj.action.MUSIC_DURATION”; //音乐时长改变动作

public static final String REPEAT_ACTION = “com.wwj.action.REPEAT_ACTION”; //音乐重复改变动作

public static final String SHUFFLE_ACTION = “com.wwj.action.SHUFFLE_ACTION”; //音乐随机播放动作

private int currentTime; //当前时间

private int duration; //时长

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.home_activity_layout);

mMusiclist = (ListView) findViewById(R.id.music_list);

mMusiclist.setOnItemClickListener(new MusicListItemClickListener());

mMusiclist.setOnCreateContextMenuListener(new MusicListItemContextMenuListener());

mp3Infos = MediaUtil.getMp3Infos(HomeActivity.this); //获取歌曲对象集合

// setListAdpter(MediaUtil.getMusicMaps(mp3Infos)); //显示歌曲列表

listAdapter = new MusicListAdapter(this,mp3Infos);

mMusiclist.setAdapter(listAdapter);

findViewById(); //找到界面上的每一个控件

setViewOnclickListener(); //为一些控件设置监听器

repeatState = isNoneRepeat; // 初始状态为无重复播放状态

homeReceiver = new HomeReceiver();

// 创建IntentFilter

IntentFilter filter = new IntentFilter();

// 指定BroadcastReceiver监听的Action

filter.addAction(UPDATE_ACTION);

filter.addAction(MUSIC_CURRENT);

filter.addAction(MUSIC_DURATION);

filter.addAction(REPEAT_ACTION);

filter.addAction(SHUFFLE_ACTION);

// 注册BroadcastReceiver

registerReceiver(homeReceiver, filter);

}

/**

  • 从界面上根据id获取按钮

*/

private void findViewById() {

previousBtn = (Button) findViewById(R.id.previous_music);

repeatBtn = (Button) findViewById(R.id.repeat_music);

playBtn = (Button) findViewById(R.id.play_music);

shuffleBtn = (Button) findViewById(R.id.shuffle_music);

nextBtn = (Button) findViewById(R.id.next_music);

musicTitle = (TextView) findViewById(R.id.music_title);

musicDuration = (TextView) findViewById(R.id.music_duration);

musicPlaying = (Button) findViewById(R.id.playing);

musicAlbum = (ImageView) findViewById(R.id.music_album);

}

/**

  • 给每一个按钮设置监听器

*/

private void setViewOnclickListener() {

ViewOnClickListener viewOnClickListener = new ViewOnClickListener();

previousBtn.setOnClickListener(viewOnClickListener);

repeatBtn.setOnClickListener(viewOnClickListener);

playBtn.setOnClickListener(viewOnClickListener);

shuffleBtn.setOnClickListener(viewOnClickListener);

nextBtn.setOnClickListener(viewOnClickListener);

musicPlaying.setOnClickListener(viewOnClickListener);

}

/**

  • 控件的监听器

  • @author Administrator

*/

private class ViewOnClickListener implements OnClickListener {

Intent intent = new Intent();

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.previous_music: // 上一首

playBtn.setBackgroundResource(R.drawable.play_selector);

isFirstTime = false;

isPlaying = true;

isPause = false;

previous();

break;

case R.id.repeat_music: // 重复播放

if (repeatState == isNoneRepeat) {

repeat_one();

shuffleBtn.setClickable(false);

repeatState = isCurrentRepeat;

} else if (repeatState == isCurrentRepeat) {

repeat_all();

shuffleBtn.setClickable(false);

repeatState = isAllRepeat;

} else if (repeatState == isAllRepeat) {

repeat_none();

shuffleBtn.setClickable(true);

repeatState = isNoneRepeat;

}

switch (repeatState) {

case isCurrentRepeat: // 单曲循环

repeatBtn

.setBackgroundResource(R.drawable.repeat_current_selector);

Toast.makeText(HomeActivity.this, R.string.repeat_current,

Toast.LENGTH_SHORT).show();

break;

case isAllRepeat: // 全部循环

repeatBtn

.setBackgroundResource(R.drawable.repeat_all_selector);

Toast.makeText(HomeActivity.this, R.string.repeat_all,

Toast.LENGTH_SHORT).show();

break;

case isNoneRepeat: // 无重复

repeatBtn

.setBackgroundResource(R.drawable.repeat_none_selector);

Toast.makeText(HomeActivity.this, R.string.repeat_none,

Toast.LENGTH_SHORT).show();

break;

}

break;

case R.id.play_music: // 播放音乐

if(isFirstTime) {

play();

isFirstTime = false;

isPlaying = true;

isPause = false;

} else {

if (isPlaying) {

playBtn.setBackgroundResource(R.drawable.pause_selector);

intent.setAction(“com.wwj.media.MUSIC_SERVICE”);

intent.putExtra(“MSG”, AppConstant.PlayerMsg.PAUSE_MSG);

startService(intent);

isPlaying = false;

isPause = true;

} else if (isPause) {

playBtn.setBackgroundResource(R.drawable.play_selector);

intent.setAction(“com.wwj.media.MUSIC_SERVICE”);

intent.putExtra(“MSG”, AppConstant.PlayerMsg.CONTINUE_MSG);

startService(intent);

isPause = false;

isPlaying = true;

}

}

break;

case R.id.shuffle_music: // 随机播放

if (isNoneShuffle) {

shuffleBtn

.setBackgroundResource(R.drawable.shuffle_selector);

Toast.makeText(HomeActivity.this, R.string.shuffle,

Toast.LENGTH_SHORT).show();

isNoneShuffle = false;

isShuffle = true;

shuffleMusic();

repeatBtn.setClickable(false);

} else if (isShuffle) {

shuffleBtn

.setBackgroundResource(R.drawable.shuffle_none_selector);

Toast.makeText(HomeActivity.this, R.string.shuffle_none,

Toast.LENGTH_SHORT).show();

isShuffle = false;

isNoneShuffle = true;

repeatBtn.setClickable(true);

}

break;

case R.id.next_music: // 下一首

playBtn.setBackgroundResource(R.drawable.play_selector);

isFirstTime = false;

isPlaying = true;

isPause = false;

next();

break;

case R.id.playing: //正在播放

Mp3Info mp3Info = mp3Infos.get(listPosition);

Intent intent = new Intent(HomeActivity.this, PlayerActivity.class);

intent.putExtra(“title”, mp3Info.getTitle());

intent.putExtra(“url”, mp3Info.getUrl());

intent.putExtra(“artist”, mp3Info.getArtist());

intent.putExtra(“listPosition”, listPosition);

intent.putExtra(“currentTime”, currentTime);

intent.putExtra(“duration”, duration);

intent.putExtra(“MSG”, AppConstant.PlayerMsg.PLAYING_MSG);

startActivity(intent);

break;

}

}

}

/**

  • 列表点击监听器

  • @author wwj

*/

private class MusicListItemClickListener implements OnItemClickListener {

/**

  • 点击列表播放音乐

*/

@Override

public void onItemClick(AdapterView<?> parent, View view, int position,

long id) {

listPosition = position; //获取列表点击的位置

playMusic(listPosition); //播放音乐

}

}

/**

  • 上下文菜单显示监听器

  • @author Administrator

*/

public class MusicListItemContextMenuListener implements OnCreateContextMenuListener {

@Override

public void onCreateContextMenu(ContextMenu menu, View v,

ContextMenuInfo menuInfo) {

Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);

vibrator.vibrate(50); //长按振动

musicListItemDialog(); //长按后弹出的对话框

final AdapterView.AdapterContextMenuInfo menuInfo2 = (AdapterView.AdapterContextMenuInfo) menuInfo;

listPosition = menuInfo2.position; //点击列表的位置

}

}

/**

  • 填充列表

  • @param mp3Infos

*/

// public void setListAdpter(List<HashMap<String, String>> mp3list) {

// mAdapter = new SimpleAdapter(this, mp3list,

// R.layout.music_list_item_layout, new String[] {“title”,

// “Artist”, “duration” }, new int[] {R.id.music_title,

// R.id.music_Artist, R.id.music_duration });

mMusiclist.setAdapter(mAdapter);

//

// }

/**

  • 下一首歌曲

*/

public void next() {

listPosition = listPosition + 1;

if(listPosition <= mp3Infos.size() - 1) {

Mp3Info mp3Info = mp3Infos.get(listPosition);

musicTitle.setText(mp3Info.getTitle());

Intent intent = new Intent();

intent.setAction(“com.wwj.media.MUSIC_SERVICE”);

intent.putExtra(“listPosition”, listPosition);

intent.putExtra(“url”, mp3Info.getUrl());

intent.putExtra(“MSG”, AppConstant.PlayerMsg.NEXT_MSG);

startService(intent);

} else {

listPosition = mp3Infos.size() - 1;

Toast.makeText(HomeActivity.this, “没有下一首了”, Toast.LENGTH_SHORT).show();

}

}

/**

  • 上一首歌曲

*/

public void previous() {

listPosition = listPosition - 1;

if(listPosition >= 0) {

Mp3Info mp3Info = mp3Infos.get(listPosition);

musicTitle.setText(mp3Info.getTitle());

Intent intent = new Intent();

intent.setAction(“com.wwj.media.MUSIC_SERVICE”);

intent.putExtra(“listPosition”, listPosition);

intent.putExtra(“url”, mp3Info.getUrl());

intent.putExtra(“MSG”, AppConstant.PlayerMsg.PRIVIOUS_MSG);

startService(intent);

}else {

listPosition = 0;

Toast.makeText(HomeActivity.this, “没有上一首了”, Toast.LENGTH_SHORT).show();

}

}

/**

  • 播放音乐

*/

public void play() {

playBtn.setBackgroundResource(R.drawable.play_selector);

Mp3Info mp3Info = mp3Infos.get(listPosition);

musicTitle.setText(mp3Info.getTitle());

Intent intent = new Intent();

intent.setAction(“com.wwj.media.MUSIC_SERVICE”);

intent.putExtra(“listPosition”, 0);

intent.putExtra(“url”, mp3Info.getUrl());

intent.putExtra(“MSG”, AppConstant.PlayerMsg.PLAY_MSG);

startService(intent);

}

/**

  • 单曲循环

*/

public void repeat_one() {

Intent intent = new Intent(CTL_ACTION);

intent.putExtra(“control”, 1);

sendBroadcast(intent);

}

/**

  • 全部循环

*/

public void repeat_all() {

Intent intent = new Intent(CTL_ACTION);

intent.putExtra(“control”, 2);

sendBroadcast(intent);

}

/**

  • 顺序播放

*/

public void repeat_none() {

Intent intent = new Intent(CTL_ACTION);

intent.putExtra(“control”, 3);

sendBroadcast(intent);

}

/**

  • 随机播放

*/

public void shuffleMusic() {

Intent intent = new Intent(CTL_ACTION);

intent.putExtra(“control”, 4);

sendBroadcast(intent);

}

/**

  • 自定义对话框

*/

public void musicListItemDialog() {

String[] menuItems = new String[]{“播放音乐”,“设为铃声”,“查看详情”};

ListView menuList = new ListView(HomeActivity.this);

menuList.setCacheColorHint(Color.TRANSPARENT);

menuList.setDividerHeight(1);

menuList.setAdapter(new ArrayAdapter(HomeActivity.this, R.layout.context_dialog_layout, R.id.dialogText, menuItems));

menuList.setLayoutParams(new LayoutParams(ConstantUtil.getScreen(HomeActivity.this)[0] / 2, LayoutParams.WRAP_CONTENT));

final CustomDialog customDialog = new CustomDialog.Builder(HomeActivity.this).setTitle(R.string.operation).setView(menuList).create();

customDialog.show();

menuList.setOnItemClickListener( new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View view,

int position, long id) {

customDialog.cancel();

customDialog.dismiss();

if(position == 0){

playMusic(listPosition);

} else if(position == 1) {

setRing();

} else if(position == 2) {

showMusicInfo(listPosition);

}

}

});

}

/**

  • 显示音乐详细信息

  • @param position

*/

private void showMusicInfo(int position) {

Mp3Info mp3Info = mp3Infos.get(position);

LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

View view = inflater.inflate(R.layout.music_info_layout, null);

((TextView) view.findViewById(R.id.tv_song_title)).setText(mp3Info.getTitle());

((TextView) view.findViewById(R.id.tv_song_artist)).setText(mp3Info.getArtist());

((TextView) view.findViewById(R.id.tv_song_album)).setText(mp3Info.getAlbum());

((TextView) view.findViewById(R.id.tv_song_filepath)).setText(mp3Info.getUrl());

((TextView) view.findViewById(R.id.tv_song_duration)).setText(MediaUtil.formatTime(mp3Info.getDuration()));

((TextView) view.findViewById(R.id.tv_song_format)).setText(Contsant.getSuffix(mp3Info.getDisplayName()));

((TextView) view.findViewById(R.id.tv_song_size)).setText(Contsant.formatByteToMB(mp3Info.getSize()) + “MB”);

new CustomDialog.Builder(HomeActivity.this).setTitle(“歌曲详细信息:”).setNeutralButton(“确定”, null).setView(view).create().show();

}

/**

  • 设置铃声

*/

protected void setRing() {

RadioGroup rg_ring = new RadioGroup(HomeActivity.this);

LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);

rg_ring.setLayoutParams(params);

//第一个单选按钮,来电铃声

final RadioButton rbtn_ringtones = new RadioButton(HomeActivity.this);

rbtn_ringtones.setText(“来电铃声”);

rg_ring.addView(rbtn_ringtones, params);

//第二个单选按钮,闹铃铃声

final RadioButton rbtn_alarms = new RadioButton(HomeActivity.this);

rbtn_alarms.setText(“闹铃铃声”);

rg_ring.addView(rbtn_alarms, params);

//第三个单选按钮,通知铃声

final RadioButton rbtn_notifications = new RadioButton(HomeActivity.this);

rbtn_notifications.setText(“通知铃声”);

rg_ring.addView(rbtn_notifications, params);

new CustomDialog.Builder(HomeActivity.this).setTitle(“设置铃声”).setView(rg_ring).setPositiveButton(“确定”, new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

dialog.cancel();

dialog.dismiss();

if(rbtn_ringtones.isChecked()) {

try {

//设置来电铃声

setRingtone(listPosition);

} catch (Exception e) {

e.printStackTrace();

}

} else if(rbtn_alarms.isChecked()) {

try {

//设置闹铃

setAlarm(listPosition);

} catch (Exception e) {

e.printStackTrace();

}

} else if(rbtn_notifications.isChecked()) {

try {

//设置通知铃声

setNotifaction(listPosition);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}).setNegativeButton(“取消”, null).show();

}

/**

  • 设置提示音

  • @param position

*/

protected void setNotifaction(int position) {

Mp3Info mp3Info = mp3Infos.get(position);

File sdfile = new File(mp3Info.getUrl().substring(4));

ContentValues values = new ContentValues();

values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath());

values.put(MediaStore.MediaColumns.TITLE, sdfile.getName());

values.put(MediaStore.MediaColumns.MIME_TYPE, “audio/*”);

values.put(MediaStore.Audio.Media.IS_RINGTONE, true);

values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);

values.put(MediaStore.Audio.Media.IS_ALARM, false);

values.put(MediaStore.Audio.Media.IS_MUSIC, false);

Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdfile.getAbsolutePath());

Uri newUri = this.getContentResolver().insert(uri, values);

RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION, newUri);

Toast.makeText( getApplicationContext(),“设置通知铃声成功!”, Toast.LENGTH_SHORT ).show();

}

/**

  • 设置闹铃

  • @param position

*/

protected void setAlarm(int position) {

Mp3Info mp3Info = mp3Infos.get(position);

File sdfile = new File(mp3Info.getUrl().substring(4));

ContentValues values = new ContentValues();

values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath());

values.put(MediaStore.MediaColumns.TITLE, sdfile.getName());

values.put(MediaStore.MediaColumns.MIME_TYPE, “audio/*”);

values.put(MediaStore.Audio.Media.IS_RINGTONE, true);

values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);

values.put(MediaStore.Audio.Media.IS_ALARM, false);

values.put(MediaStore.Audio.Media.IS_MUSIC, false);

Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdfile.getAbsolutePath());

Uri newUri = this.getContentResolver().insert(uri, values);

RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM, newUri);

Toast.makeText( getApplicationContext(),“设置闹钟铃声成功!”, Toast.LENGTH_SHORT ).show();

}

/**

  • 设置来电铃声

  • @param position

*/

protected void setRingtone(int position) {

Mp3Info mp3Info = mp3Infos.get(position);

File sdfile = new File(mp3Info.getUrl().substring(4));

ContentValues values = new ContentValues();

values.put(MediaStore.MediaColumns.DATA, sdfile.getAbsolutePath());

values.put(MediaStore.MediaColumns.TITLE, sdfile.getName());

values.put(MediaStore.MediaColumns.MIME_TYPE, “audio/*”);

values.put(MediaStore.Audio.Media.IS_RINGTONE, false);

values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);

values.put(MediaStore.Audio.Media.IS_ALARM, true);

values.put(MediaStore.Audio.Media.IS_MUSIC, false);

Uri uri = MediaStore.Audio.Media.getContentUriForPath(sdfile.getAbsolutePath());

Uri newUri = this.getContentResolver().insert(uri, values);

RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE, newUri);

Toast.makeText( getApplicationContext(),“设置来电铃声成功!”, Toast.LENGTH_SHORT ).show();

}

/**

  • 此方法通过传递列表点击位置来获取mp3Info对象

  • @param listPosition

*/

public void playMusic(int listPosition) {

if (mp3Infos != null) {

Mp3Info mp3Info = mp3Infos.get(listPosition);

musicTitle.setText(mp3Info.getTitle()); //这里显示标题

Bitmap bitmap = MediaUtil.getArtwork(this, mp3Info.getId(), mp3Info.getAlbumId(), true, true);//获取专辑位图对象,为小图

musicAlbum.setImageBitmap(bitmap); //这里显示专辑图片

Intent intent = new Intent(HomeActivity.this, PlayerActivity.class); //定义Intent对象,跳转到PlayerActivity

//添加一系列要传递的数据

intent.putExtra(“title”, mp3Info.getTitle());

intent.putExtra(“url”, mp3Info.getUrl());

intent.putExtra(“artist”, mp3Info.getArtist());

intent.putExtra(“listPosition”, listPosition);

intent.putExtra(“currentTime”, currentTime);

intent.putExtra(“repeatState”, repeatState);

intent.putExtra(“shuffleState”, isShuffle);

intent.putExtra(“MSG”, AppConstant.PlayerMsg.PLAY_MSG);

startActivity(intent);

}

}

@Override

protected void onStop() {

// TODO Auto-generated method stub

super.onStop();

}

@Override

protected void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BATJ 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。

节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960全网最全Android开发笔记》

《379页Android开发面试宝典》

历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

如何使用它?

1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

[外链图片转存中…(img-MIDWu5X5-1713806546565)]

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BATJ 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。

节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960全网最全Android开发笔记》

[外链图片转存中…(img-5IDdGtJs-1713806546566)]

《379页Android开发面试宝典》

历时半年,我们整理了这份市面上最全面的安卓面试题解析大全
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

如何使用它?

1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数

[外链图片转存中…(img-i1nFpKUn-1713806546567)]

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。

[外链图片转存中…(img-ER0lueAc-1713806546568)]

腾讯、字节跳动、阿里、百度等BAT大厂 2019-2021面试真题解析

[外链图片转存中…(img-cL5YEM9M-1713806546568)]

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值