Thread和AsyncTask使用:

1.Thread使用:
继承Thread类:

public class MyThread extends Thread {
    @Override
    public void run() {
        //线程中处理的逻辑
    }
}

调用:

new MyThread().start();

实现Runnable:

public class MyThread implements Runnable {
    @Override
    public void run() {
        //线程中处理的逻辑
    }
}

调用:

        MyThread myThread=new MyThread()
        new Thread(myThread).start();

异步消息处理

public class ThreadTestActivity extends Activity {
    private TextView text;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 0:
                    //子线程不允许操作UI.,在这里操作UI 防止线程堵塞
                    text.setText("这里操作UI,防止线程堵塞");
                    break;
                case 1:
                    break;
                default:
                    break;
            }

        }
    };
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button=findViewById(R.id.start_download);
        text=(TextView)findViewById(R.id.text_view);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message=new Message();
                        message.what=0;
                        handler.sendMessage(message);
                    }
                }).start();
            }
        });
    }

}

1.Message存储少量数据,用于进程间交换数据。除了what字段,还有arg1 arg2 以及obj.

2.Handler处理Message发送过来的信息,发送消息一般是Handler的sedMessage()方法。最终会传递到Handler的Handler的handleMessage()方法中。

3.MessageQueue是存放Handler的sendMessage()发送过来的消息,这些消息存在一个队列中,等待被处理。每个线程中只有一个MessageQueue对象。

4.Loop:MessageQueue的管家,调用Loop的loop()方法后,就会无线循环。没发现MessageQueue中存在消息队列,就会从中取出,传递到Handler的handleMessage()中。每个线程中只有已给Loop对象

runOnUiThread()方法就是这个原理实现的

2.AsyncTask使用:

继承AsyncTask,实现一个抽象方法 doInBackground()

public class MyAsyncTask extends AsyncTask<String,Integer,Integer> {
    @Override
    protected Integer doInBackground(String... strings) {
        return null;
    }
}

Params:执行AsyncTask时需要传入的参数,可用于在后台任务
Progress:界面上显示当前进度,只用这里指定泛型作为进度单位
Result:当任务执行完,需要对结果进行返回,可以指定泛型作为返回值类型

一些常用方法:
onPreExecute()
这个会在执行后台任务之前被调用,常用语一些初始化操作

doInBackground(Params…)
这个方法的代码都会在子线程中执行,常用的耗时操作都在这里执行,可以通过reture返回执行结果。AsyncTask的第三个参数指定为Void,则可以不返回任务执行结果。如果需要操作UI,比如反馈当前任务进度。可以调用publishProgress(Progress…)

onProgressUpdata(Progress..)
调用 publishProgress()方法后,onProgressUpdata()方法会很快被调用,这个方法携带过来的参数就是在后台任务传递过来的,可以利用参数中的数值进行UI操作

onPostExecute(Result…)
后台执行完毕通过return返回结果时,就会调用此方法,doInBackground()返回的结果会作为参数传递到此方法中,比如提醒任务执行结果

例子:DownloadTask.java代码

public class DownloadTask extends AsyncTask<String, Integer, Integer> {

    public static final int TYPE_SUCCESS = 0;
    public static final int TYPE_FAILED = 1;
    public static final int TYPE_PAUSED = 2;
    public static final int TYPE_CANCELED = 3;


    private DownloadListener listener;

    private boolean isCanceled = false;

    private boolean isPaused = false;

    private int lastProgress;

    public DownloadTask(DownloadListener listener) {
        this.listener = listener;
    }

    @Override
    protected Integer doInBackground(String... params) {
        InputStream is = null;
        RandomAccessFile savedFile = null;
        File file = null;
        try {
            long downloadedLength = 0; // 记录已下载的文件长度
            String downloadUrl = params[0];
            String fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"));
            String directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
            file = new File(directory + fileName);
            if (file.exists()) {
                downloadedLength = file.length();
            }
            long contentLength = getContentLength(downloadUrl);
            Log.d("TAG", "contentLength: "+contentLength);
            if (contentLength == 0) {
                return TYPE_FAILED;
            } else if (contentLength == downloadedLength) {
                // 已下载字节和文件总字节相等,说明已经下载完成了
                return TYPE_SUCCESS;
            }
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    // 断点下载,指定从哪个字节开始下载
                    .addHeader("RANGE", "bytes=" + downloadedLength + "-")
                    .url(downloadUrl)
                    .build();
            Response response = client.newCall(request).execute();
            if (response != null) {
                is = response.body().byteStream();
                savedFile = new RandomAccessFile(file, "rw");
                savedFile.seek(downloadedLength); // 跳过已下载的字节
                byte[] b = new byte[1024];
                int total = 0;
                int len;
                while ((len = is.read(b)) != -1) {
                    if (isCanceled) {
                        return TYPE_CANCELED;
                    } else if(isPaused) {
                        return TYPE_PAUSED;
                    } else {
                        total += len;
                        savedFile.write(b, 0, len);
                        // 计算已下载的百分比
                        int progress = (int) ((total + downloadedLength) * 100 / contentLength);
                        publishProgress(progress);
                    }
                }
                response.body().close();
                return TYPE_SUCCESS;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (savedFile != null) {
                    savedFile.close();
                }
                if (isCanceled && file != null) {
                    file.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return TYPE_FAILED;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int progress = values[0];
        //更新下载进度
        if (progress > lastProgress) {
            listener.onProgress(progress);
            lastProgress = progress;
        }
    }

    @Override
    protected void onPostExecute(Integer status) {
        switch (status) {
            case TYPE_SUCCESS:
                listener.onSuccess();
                break;
            case TYPE_FAILED:
                listener.onFailed();
                break;
            case TYPE_PAUSED:
                listener.onPaused();
                break;
            case TYPE_CANCELED:
                listener.onCanceled();
            default:
                break;
        }
    }

    public void pauseDownload() {
        isPaused = true;
    }


    public void cancelDownload() {
        isCanceled = true;
    }
     /**
     * 获取文件总字节数
     * @param downloadUrl
     * @return contentLength
     * @throws IOException
     */
    private long getContentLength(String downloadUrl) throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(downloadUrl)
                .build();
        Response response = client.newCall(request).execute();
        if (response != null && response.isSuccessful()) {
            long contentLength = response.body().contentLength();
            response.close();
            return contentLength;
        }
        return 0;
    }
}

DownloadListener.java代码

public interface DownloadListener {
    void onProgress(int progress);
    void onPaused();
    void onCanceled();
    void onSuccess();
    void onFailed();
}

DownloadService.java代码

public class DownloadService extends Service {
    private String downloadUrl;
    private DownloadTask downloadTask;

    private DownloadListener downloadListener=new DownloadListener() {
        @Override
        public void onProgress(int progress) {
            getNotificationManage().notify(1,getNotification("download...",progress));
        }

        @Override
        public void onPaused() {
            downloadTask=null;
            Toast.makeText(DownloadService.this,"Paused Download",Toast.LENGTH_LONG).show();
        }

        @Override
        public void onCanceled() {
            downloadTask=null;
            stopForeground(true);
            Toast.makeText(DownloadService.this,"Canceled Download",Toast.LENGTH_LONG).show();
        }

        @Override
        public void onSuccess() {
            downloadTask=null;
            //前台服务关闭,并创建一个下载成功通知
            stopForeground(true);
            getNotificationManage().notify(1,getNotification("下载完成",-1));
            Toast.makeText(DownloadService.this,"Download success",Toast.LENGTH_LONG).show();
        }

        @Override
        public void onFailed() {
            downloadTask=null;
            //下载失败关闭前台服务通知,并创建一个下载失败通知
            stopForeground(true);
            getNotificationManage().notify(1,getNotification("Download Failed",-1));
            Toast.makeText(DownloadService.this,"Download failed",Toast.LENGTH_LONG).show();
        }
    };
    private DownloadBind mBind=new DownloadBind();
    class DownloadBind extends Binder{
        public void startDownload(String url){
            if (downloadTask==null){
                DownloadTask downloadTask=new DownloadTask(downloadListener);
                downloadUrl=url;
                downloadTask.execute(downloadUrl);
                startForeground(1,getNotification("download...",0));
                Toast.makeText(DownloadService.this,"download...",Toast.LENGTH_LONG).show();
            }
        }

        public void pauseDownload(){
            if (downloadTask!=null){
                downloadTask.pauseDownload();
            }

        }

        public void cancelDownload(){
            if (downloadTask!=null){
                downloadTask.cancelDownload();
            }else {
                if (downloadUrl!=null){
                    //取消下载,删除文件,关闭通知
                    String fileName=downloadUrl.substring(downloadUrl.lastIndexOf("/"));
                    String fileDir= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
                    File file=new File(fileDir+fileName);
                    if (file.exists()){
                        file.delete();
                    }
                    getNotificationManage().cancel(1);
                    stopForeground(true);
                    Toast.makeText(DownloadService.this,"Cancel download",Toast.LENGTH_LONG).show();
                }
            }

        }
    }


    @Override
    public IBinder onBind(Intent intent) {
        return mBind;
    }

    public NotificationManager getNotificationManage(){
       return (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    }

    private Notification getNotification(String title,int progress){
        Intent intent=new Intent(this,MainActivity.class);
        PendingIntent pi=PendingIntent.getActivity(this,0,intent,0);
        NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
        builder.setContentTitle(title).setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher));
        builder.setContentIntent(pi);
        if (progress>0){
            builder.setContentTitle(progress+"%");
            builder.setProgress(100,progress,false);
        }
        return builder.build();
    }
}

DownloadService服务中实现DownloadListener中的5个方法,onProgress()方法中创建通知栏,在下拉状态栏中实时更新下载进度。onSuccess()方法中关闭前台任务,创建一个新通知告诉用户下载完成了。
DownloadBind中提供三个方法 分别分别用于启动,暂停,和取消下载任务。startDownload()方法中实例了DownloadTask,并调用了execute()方法开启下载。这个下载服务就作为已给前台服务运行了startForeground()方法在系统状态栏创建持续运行通知

MainActivity.java代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button startBtn, pauseBtn, cancelBtn;
    private DownloadService.DownloadBind downloadBind;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            downloadBind = (DownloadService.DownloadBind) iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startBtn = (Button) findViewById(R.id.start_download);
        pauseBtn = (Button) findViewById(R.id.pause_download);
        cancelBtn = (Button) findViewById(R.id.cancel_download);
        startBtn.setOnClickListener(this);
        pauseBtn.setOnClickListener(this);
        cancelBtn.setOnClickListener(this);
        Intent intent = new Intent(MainActivity.this, DownloadService.class);
        startService(intent);//启动服务
        bindService(intent, connection, BIND_AUTO_CREATE);//绑定bind
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        }

    }

    @Override
    public void onClick(View view) {
        if (downloadBind == null) {
            return;
        }
        switch (view.getId()) {
            case R.id.start_download:
                String url = "https://raw.githubusercontent.com/guolindev/eclipse/master/eclipse-inst-win64.exe";
                String url2="http://sw.bos.baidu.com/sw-search-sp/software/71bdb07e88935/Firefox-55.0.2.6435-setup.exe";
                downloadBind.startDownload(url2);
                break;
            case R.id.pause_download:
                downloadBind.pauseDownload();
                break;
            case R.id.cancel_download:
                downloadBind.cancelDownload();
                break;
            default:
                break;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(connection);
    }
}

layout布局文件就不贴出来了,感觉已经写了很长了。
在onCreatView()中启动服务,和bindService()绑定service.
ServiceConnection 中实例了DownloadBind。有了DownloadBind的实例就可以调用其中的StartDownload(),pauseDownload(),cancelDownload()三个方法了。分别对应到不同按钮的点击事件中。
另外则是一个权限的动态申请了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值