Android开发高级进阶—多线程(实现简单下载器)
2016-09-07 18:05
483 查看
Android开发高级进阶——多线程(实现简单下载器)
每个Android应用在被启动时都会创建一个线程,这个线程称为主线程或UI线程,Android应用的所有操作都会运行在这个线程中。但是为了保证UI的流畅性,通常会将耗时操作放到子线程中,例如IO操作、网络请求等。而几乎每个Android应用都会涉及到网络请求等耗时操作,所以多线程对于Android来说变得至关重要。什么是多线程?
线程:是进程中单一的连续控制流程/执行路径。多线程:多个线程并行执行。
二.为什么要使用多线程?
使用多线程可以提高效率,并且不会使程序出现卡顿现象(比如ANR)。三.什么时候使用多线程?
Android3.0以及以后的版本中,禁止在主线程执行网络请求,否则会抛出异常,可见在UI线程中执行耗时操作是不推荐的行为。所以,在进行与耗时操作同步进行的操作时(即并行)使用多线程。四.如何使用多线程?
我们经常说Android中的主线程是线程不安全的,所以只能在主线程中更新UI。那么如何更新主线程且保证线程是安全的呢?Android中提供了保证线程安全的几种解决方案:
使用Handler实现线程之间的通信。
Activity.runOnUiThread(Runnable):一般在Activity的Thread中运用。
View.post(Runnable)
View.postDelayed(Runnable, long)
Android中的线程分为主线程(UI线程)和工作线程。
主线程(UI线程):程序运行时被创建的线程。
工作线程:自己创建的线程。
以上两个线程之间的通信最基本的有两种:
Thread和Runnable
这里通过实现一个简单的下载器来学习Thread和Runnable。这个下载器就一个界面,包含一个输入框,一个进度条,用来显示下载进度,用来输入下载地址,一个按钮,用来开始下载。
界面代码如下:activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="16dp" android:layout_marginTop="16dp" tools:context="com.trampcr.downloaddemo.MainActivity"> <EditText android:id="@+id/et_url" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:hint="请输入下载地址" /> <ProgressBar android:id="@+id/pb_down_load" style="@style/Widget.AppCompat.ProgressBar.Horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/et_url" android:layout_marginTop="30dp" android:max="100" /> <TextView android:id="@+id/tv_progress" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/pb_down_load" android:layout_marginTop="20dp" android:text="下载进度" android:textColor="#000000" /> <Button android:id="@+id/btn_start_download" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_progress" android:layout_centerHorizontal="true" android:layout_marginTop="50dp" android:background="@drawable/btn_style" android:text="开始下载" android:textColor="#000000" /> </RelativeLayout>
细心的人可能会注意到这里的按钮用了一个背景@drawable/btn_style,这里是自定义按钮的形状。代码如下:btn_style.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:topLeftRadius="10dp" android:radius="8dp" android:topRightRadius="10dp" android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp" /> <stroke android:color="#000000" android:width="0.7dp"/> </shape>
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener { //public static final String DOWNLOAD_URL = "http://psoft.33lc.com:801/small/rootexplorer_33lc.apk"; private Button mBtnStartDownload; private EditText mEtUrl; private String mUrl; private ProgressBar mPbDownload; private TextView mTvProgress; private Handler mHandler = new DownloadHandler(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEtUrl = (EditText) findViewById(R.id.et_url); mBtnStartDownload = (Button) findViewById(R.id.btn_start_download); mPbDownload = (ProgressBar) findViewById(R.id.pb_down_load); mTvProgress = (TextView) findViewById(R.id.tv_progress); mBtnStartDownload.setOnClickListener(this); } @Override public void onClick(View v) { mUrl = mEtUrl.getText().toString().trim(); new Thread(new Runnable() { @Override public void run() { download(mUrl); } }).start(); } private void download(String mUrl) { try { URL url = new URL(mUrl); URLConnection urlConnection = url.openConnection(); int contentLength = urlConnection.getContentLength(); //下载文件大小 InputStream inputStream= urlConnection.getInputStream(); String downloadFolderName = Environment.getExternalStorageDirectory() + File.separator + "trampcr" + File.separator; File file = new File(downloadFolderName); if (!file.exists()){ file.mkdir(); } String fileName = downloadFolderName + "zxm.apk"; File apkFile = new File(fileName); if (apkFile.exists()) { apkFile.delete(); } int downloadSize = 0; byte[] buff = new byte[1024]; int length = 0; OutputStream outputStream = new FileOutputStream(fileName); while ((length = inputStream.read(buff)) != -1) { outputStream.write(buff, 0, length); downloadSize += length; int progress = downloadSize * 100 / contentLength; Message msg = mHandler.obtainMessage(); msg.what = 0; msg.obj = progress; mHandler.sendMessage(msg); } outputStream.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } public static class DownloadHandler extends Handler{ public final WeakReference<MainActivity> weakRefActivity; public DownloadHandler(MainActivity mainActivity) { weakRefActivity = new WeakReference<MainActivity>(mainActivity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MainActivity activity = weakRefActivity.get();//判断是否被回收 switch (msg.what){ case 0: int progress = (int) msg.obj; activity.mPbDownload.setProgress(progress); activity.mTvProgress.setText("下载进度:" + progress + "%"); if (progress == 100){ Toast.makeText(activity, "下载完成", Toast.LENGTH_LONG).show(); } break; } } } }
所需要的权限:
<uses-permission android:name="android.permission.INTERNET"/>
效果如如下:
注:这里面用到了一个我不太熟悉的知识:We
4000
akReference的理解与使用
文/trampcr(简书作者)
原文链接:http://www.jianshu.com/p/6a558a23084a
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
相关文章推荐
- Android开发高级进阶(二)—多线程(实现简单下载器)
- 在Java中使用多线程结合断点续传实现一个简单的文件下载器
- C#中简单实现多线程
- 简单多线程实现代码(参考卖票代码)
- 使用python多线程实现一个简单spider
- [PHP]进阶教程:服务器端嵌入(SSI)实现多个页面之间的引用与简单案例
- 一种简单高效的生产者消费者多线程实现
- 编写多线程网络检测程序的简单实现
- 简单多线程网络爬虫的实现
- 记事本运行java文件实现简单的多线程
- Java多线程实现简单的售票程序
- c++ 多线程阻塞队列的简单实现
- Java多线程-一个简单的线程,实现挂起和恢复的功能
- 简单多线程服务器实现
- JAVA进阶:一个简单Thread缓冲池的实现
- objective-c 简单实现多线程(线程池)
- 简单多线程实现代码(参考卖票代码)
- 进阶:Java Web中的入侵检测及简单实现
- Android中用AsyncTask简单实现多线程
- java简单多线程方式+实现文件上传(spring mvc + jquery.form.js 框架)