Android 实例:多线程下载,进度条,音乐播放器(2)

实例源码下载

=========

下载地址:https://github.com/zhuanghongji/MultiThreadDownPlayerZhj

实例图片:

=====

实例源码:

=====

Manifest.xml 中添加权限:


<!-- 在SD卡中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 向SD卡写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 授权访问网络 -->
<uses-permission android:name="android.permission.INTERNET"/>

MainActivity.java :


public class MainActivity extends AppCompatActivity {

private ImageView mImageView;
private DownUtil mPictureDownUtil, mSongDownUtil;
private MediaPlayer mMediaPlayer;
private ProgressBar mPitureProBar, mSongProBar;
private int mPitureDownStatus, mSongDownStatus;
private Button mPictureDownBtn, mSongDownBtn;
private SeekBar mSongSeekBar;
private int mPlayStatus;
private ImageButton mPlayBtn;
private double mDuration;
Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 1:     // 改变图片的下载进度条
                mPitureProBar.setProgress(mPitureDownStatus);
                break;
            case 2:     // 图片下载完成后,设置歌手图片
                Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/李健.jpg");
                mImageView.setImageBitmap(bitmap);
                break;
            case 3:     // 改变歌曲文件的下载进度条
                mSongProBar.setProgress(mSongDownStatus);
                break;
            case 4:     // 改变播放的进度
                mSongSeekBar.setProgress(mPlayStatus);
                break;
            case 5:     // 播放完成后更改播放按钮图
                mPlayBtn.setImageResource(R.drawable.start);
                break;
        }
    }
};
public static final String URL_DOWNLOAD_JPG = "http://upload.timedg.com/2015/0228/1425097230412.jpg";
public static final String URL_DOWNLOAD_MP3 = "http://music.baidu.com/data/music/file?link=" +
        "http://yinyueshiting.baidu.com/data2/music/" +
        "245302327/2452981731439064061128.mp3?xcode=10c72737bdd9a2f07ed60eb536e08c87&song_id=245298173";
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initViews();
    intiEvents();
    initMediaPlay();
}
/**
 * 初始化播放器
 */
private void initMediaPlay() {
    try {
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setDataSource("/mnt/sdcard/假如爱有天意.mp3");
        mMediaPlayer.prepare();
        Log.i("Duration", String.valueOf(mMediaPlayer.getDuration()));
        Log.i("CurrentPosition", String.valueOf(mMediaPlayer.getCurrentPosition()));
    } catch (IOException e) {
        e.printStackTrace();
    }
    new Thread() {
        @Override
        public void run() {
            final Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    double completeRate = mMediaPlayer.getCurrentPosition();
                    double duration = mMediaPlayer.getDuration();
                    mPlayStatus = (int) (completeRate * 100 / duration);
                    mHandler.sendEmptyMessage(4);
                    Log.i("CurrentPosition", String.valueOf(mMediaPlayer.getCurrentPosition()));
                    if (mMediaPlayer.getDuration() - completeRate <= 1000) {
                        timer.cancel();
                        mHandler.sendEmptyMessage(5);
                    }
                }
            }, 0, 100);
        }
    }.start();
}
/**
 * 初始化事件
 */
private void intiEvents() {
    mPictureDownBtn.setOnClickListener(new MyOnClickListener());
    mSongDownBtn.setOnClickListener(new MyOnClickListener());
    mPlayBtn.setOnClickListener(new MyOnClickListener());
    mSongSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
        }
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            mMediaPlayer.pause();
        }
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            int progress = mSongSeekBar.getProgress();
            mDuration = mMediaPlayer.getDuration();
            mMediaPlayer.seekTo((int) (progress * mDuration / 100));
            mMediaPlayer.start();
        }
    });
}
/**
 * 初始化控件
 */
private void initViews() {
    mImageView = (ImageView) findViewById(R.id.iv_singer_picture);
    mPitureProBar = (ProgressBar) findViewById(R.id.bar_dowmload_picture);
    mSongProBar = (ProgressBar) findViewById(R.id.bar_dowmload_song);
    mPictureDownBtn = (Button) findViewById(R.id.btn_download_picture);
    mSongDownBtn = (Button) findViewById(R.id.btn_download_song);
    mSongSeekBar = (SeekBar) findViewById(R.id.seekbar_song_play);
    mPlayBtn = (ImageButton) findViewById(R.id.btn_song_play);
}
public void makeToast(String s) {
    Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
}
private class MyOnClickListener implements OnClickListener {
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_download_picture:
                downloadPicture();
                break;
            case R.id.btn_download_song:
                makeToast("歌曲下载");
                downloadSong();
                break;
            case R.id.btn_song_play:
                playSong();
                break;
        }
    }
}
/**
 * 下载歌手图片
 */
private void downloadPicture() {
    // 初始化DownUtil对象(最后一个参数指定线程数)
    mPictureDownUtil = new DownUtil(URL_DOWNLOAD_JPG,
            "/mnt/sdcard/李健.jpg", 8);
    new Thread() {
        @Override
        public void run() {
            try {
                // 开始下载
                mPictureDownUtil.download();
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 定义每0.1秒调度获取一次系统的完成进度
            final Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    // 获取下载任务的完成比率
                    double completeRate = mPictureDownUtil.getCompleteRate();
                    mPitureDownStatus = (int) (completeRate * 100);
                    // 发送消息通知界面更新进度条
                    mHandler.sendEmptyMessage(1);
                    // 下载完全后取消任务调度
                    if (mPitureDownStatus >= 100) {
                        timer.cancel();
                        mHandler.sendEmptyMessage(2);
                    }
                }
            }, 0, 100);
        }
    }.start();
}
/**
 * 下载歌曲文件
 */
private void downloadSong() {
    // 初始化DownUtil对象(最后一个参数指定线程数)
    mSongDownUtil = new DownUtil(URL_DOWNLOAD_MP3,
            "/mnt/sdcard/假如爱有天意.mp3", 1);
    new Thread() {
        @Override
        public void run() {
            try {
                // 开始下载
                mSongDownUtil.download();
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 定义每0.1秒调度获取一次系统的完成进度
            final Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    // 获取下载任务的完成比率
                    double completeRate = mSongDownUtil.getCompleteRate();
                    mSongDownStatus = (int) (completeRate * 100);
                    // 发送消息通知界面更新进度条
                    mHandler.sendEmptyMessage(3);
                    // 下载完全后取消任务调度
                    if (mSongDownStatus >= 100) {
                        timer.cancel();
                    }
                }
            }, 0, 100);
        }
    }.start();
}
/**
 * 播放歌曲
 */
private void playSong() {
    boolean isPlaying = mMediaPlayer.isPlaying();
    if (isPlaying == false) {
        mMediaPlayer.start();
        mPlayBtn.setImageResource(R.drawable.pause);
    } else if ((isPlaying == true)) {
        mMediaPlayer.pause();
        mPlayBtn.setImageResource(R.drawable.start);
    }
}

}

DownUtil.java :


public class DownUtil {

// 定义下载资源的路径
private String path;
// 指定所下载的文件的保存位置
private String targetFile;
// 定义需要使用多少线程下载资源
private int threadNum;
// 定义下载的线程对象
private DownThread[] threads;
// 定义下载的文件的总大小
private long fileSize;
public DownUtil(String path, String targetFile, int threadNum)
{
    this.path = path;
    this.threadNum = threadNum;
    // 初始化threads数组
    threads = new DownThread[threadNum];
    this.targetFile = targetFile;
}
public void download() throws Exception
{
    URL url = new URL(path);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setConnectTimeout(5 * 1000);
    conn.setRequestMethod("GET");
    conn.setRequestProperty(
            "Accept",
            "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
                    + "application/x-shockwave-flash, application/xaml+xml, "
                    + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
                    + "application/x-ms-application, application/vnd.ms-excel, "
                    + "application/vnd.ms-powerpoint, application/msword, */*");
    conn.setRequestProperty("Accept-Language", "zh-CN");
    conn.setRequestProperty("Charset", "UTF-8");
    conn.setRequestProperty("Connection", "Keep-Alive");
    // 得到文件大小
    fileSize = conn.getContentLength();
    Log.e("fileSize", fileSize + "");
    conn.disconnect();
    long currentPartSize = fileSize / threadNum;
    Log.e("currentPartSize",currentPartSize+"");
    RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
    // 设置本地文件的大小
    file.setLength(fileSize);
    file.close();
    for (int i = 0; i < threadNum; i++)
    {
        // 计算每条线程的下载的开始位置
        long startPos = i * currentPartSize;
        Log.e("startPos",startPos+"");
        // 每个线程使用一个RandomAccessFile进行下载
        RandomAccessFile currentPart = new RandomAccessFile(targetFile,
                "rw");
        // 定位该线程的下载位置
        currentPart.seek(startPos);
        // 创建下载线程
        threads[i] = new DownThread(startPos, currentPartSize,
                currentPart);
        // 启动下载线程
        threads[i].start();
    }
}
public class DownThread extends Thread {
    // 当前线程的下载位置
    private long startPos;
    // 定义当前线程负责下载的文件大小
    private long currentPartSize;
    // 当前线程需要下载的文件块

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

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

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

img

img

img

img

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

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

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

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

【Android高级架构视频学习资源】

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

g-GdSKZwIS-1713116761666)]

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

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

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

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

上面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

【Android思维脑图(技能树)】

知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。

[外链图片转存中…(img-Ywqdw2x7-1713116761666)]

【Android高级架构视频学习资源】

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值