安卓开发 之小白养成-Android异步任务

progressBar:进度条

在开发中做一件很长时间的任务时,这时需要有一个进度条来提醒,已经进行到哪个阶段了,好处是时时可以和用户交互,比如说下载时,我们经常会看到一个进度条来提示用户下载的进度。

 

1.对话框进度条

2.标题进度条

3.自定义进度条

progressBar:他也是继承View,在某些操作的进度中的可视指示器,为用户呈现操作的进度,还它有一个次要的进度条,用来显示中间进度,如在流媒体播放的缓冲区的进度,一个进度条也可不确定其进度。在不确定模式下,进度条显示循环动画,这种模式常用于应用程序使用任务的长度是未知的,进度条也就是一个表示运转的过程,例如发送短信,连接网络等等。表示一个过程正在执行中。

进度条有两种样式,一种是条的(条形填充形式),用来显示进度,一种是转圈的(表盘形式,分为普通,小,大),就是不确定其进度,在layout定义时,需要通过设置style属性设置展示方式。

style="?android:attr/progressBarStyleLarge"(大)

style="?android:attr/progressBarStyleSmall"(小)

style="?android:attr/progressBarStyleHorizontal"(条形)

重要属性:

max:这是进度条长度最大值

progress:设定进度条当前进度值

secondaryProgress:第二进度条进度值

progressBarStyle:默认进度条样式

progressBarStyleHorizontal:水平样式

 

重要方法:

getMax():返回这个进度条的范围的上限

getProgress():返回当前进度值

getSecondaryProgress():返回次要当前进度值,用来做缓冲用的,比如说在网上看视频时,有一个播放的进度,有一个缓冲的进度。

incrementProgressBy(int diff):指定增加的进度--即步长

isIndeterminate():指示进度条是否在不确定模式下

setIndeterminate(boolean im):设置进度条是不是不确定模式,如果设置为true,那么设置当前进度和第二进度是无效的

setVisivility(int v):设置该进度条是否可视

对话框进度条:ProgressDialog,是组件式的,需要代码完成

 

 

 

这个取消表示点其它空白地方就取消了,没有真空的按钮

标题进度条:必须在标题栏这有一个进度

 

设置进度标题(该方法必须在setContentView方法之前)

自定义进度条:进度条的图标不是默认的,而是自己设置的图片

是通过一个图片来定义进度条

1. 在res/drawable/下创建一个layer-list

2.设置ProgressBar的android:indeterminateDrawable属性

 

 

  • AsyncTask异步任务的基本使用

 

  1. Android中的单线程模型

 

当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

 

在开发Android 应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

如 果在非UI线程中直接操作UI线程,会抛出异常 android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views,这与普通的java程序不同。

由于UI线程负责事件的监听和绘图,因此,必须保证UI线程能够随时响应用户的需求,UI线程里的操作应该向中断事件那样短小,费时的操作(如网络连接)需要另开线程,否则,如果UI线程超过5s没有响应用户请求,会弹出对话框提醒用户终止应用程序。

在UI主线程里做耗时操作,程序会

 

备注:从3.0开始,网络连接的操作必须放在子线程中,如果放在主线程中会直接抛出异常。

 

主线程成不能执行耗时操作,子线程不能修改UI,如何解决这个问题?很荣幸,android共提供了5种解决方案供我们选择:

  1. 使用Handler消息机制。子线程负责耗时操作,当需要修改UI时,发送Message让主线程帮组修改UI。(后面重点学习)
  2. 在子线程中调用任何的View对象的post(Runnable)或postDelay(Runnable, tlong)方法,则Runnable中run方法的代码会在主线程中运行。(非主流,实际开发中使用不多)
  3. 在子线程中调用Activity的runOnUiThread(Runnalbe)方法,则Runnable对象的run()方法内的代码会嵌入到主线程运行。(非主流,实际开发中使用不多)
  4. 使用AsyncTask异步任务。(重点)
  5. 使用Loader(重点)。
  1. 什么是AsynTask  这个异步任务在这里面可以是一种非常简单的更新UI线程的类,如果我们不使用handler加线程的操作下,这个类允许我们去执行一个后台的操作并把结果发布给这个UI线程, 那么异步任务他其实是一个线程框架,在这里他也是一种线程加handler的这么一种机制来设计的,只不过他封装了这个代码的具体实现而不会让我们看见而以,所以异步任务在这里应用在一个短的耗时操作当中,比如说就是几秒钟的操作,如果你想用它来保持线程运行的长时间的操作,这里面会使用到线程池的这么一个包,后面会给大家讲到。

 

  1. AsynTask使用步骤

 

如果我们想要使用这个异步任务,我们必须要先去声明一个类来继承这个异步任务这个类(AsynTask),并且在这个doInbackground这个方法的回调当中去完成异步的操作。

如果我们想要更新我们的UI,应该是在onPostExecute这个方法当中去更新,如果我们想把这个结果发布到我们的UI主线程,应该去调用exetute()这个方法,这样就可以完成对数据的存取了。

要掌握AsyncTask,总结起来就是理解: 3个泛型,4个步骤。

  1. 三个泛型

3个泛型指的是什么呢?我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,我们需要为其指定3个泛型参数:

AsyncTask <Params, Progress, Result>

  1. Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型。通常指网络下载数据的路径,为String类型
  2. Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型。通常指进度的刻度,为Integer类型
  3. Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型

 我们在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果任何一个不想指定或者都不指定的话,则可将其写成Void,例如:

AsyncTask <Void, Void, Void>

 

注意:Void首字母必须大写,这个Void和java中空返回值void是不一样的。

  1. 个步骤

当我们执行一个异步任务的时候,其需要按照下面的4个步骤分别执行。

步骤一:

        onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出要给用户提示的ProgressDialog。

步骤二:

       doInBackground(Params... params): 在onPreExecute()方法执行完之后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread(子线程)来执行我们的这个方法,所以这个方法是在worker thread当中执行的,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作。这个方法执行完之后就可以将我们的执行结果发送给我们的最后一个 onPostExecute 方法。注意:此方法不是 UI线程中执行。在这个步骤里可以使用publishProgress这个方法 用来更新进度的刻度,那这些刻度的值会发布在UI的主线程上,通常发布来说也是和progressbar来结合使用的

步骤三:

onProgressUpdate(Progess... values): 在第二步里执行publishProgress这个方法后,UI线程就会去执行这个方法 ,这个方法是用来更新UI的进度条的

 

步骤四:

        onPostExecute(Result... result): 当我们的异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上,用来发布后台执行完的结果的

 

总结:以上4个方法中doInBackground是在work Thread线程中执行,其余3个方法均是在UI(main)线程中执行。

为什么我们的AsyncTask抽象类只有一个 doInBackground 的抽象方法呢??原因是,我们如果要做一个异步任务,我们必须要为其开辟一个新的Thread,让其完成一些操作,而在完成这个异步任务时,我可能并不需要弹出要给用户提示的ProgressDialog,我们可能并不需要随时更新我的ProgressDialog的进度条,我也可能并不需要将结果更新给我们的UI界面,所以除了 doInBackground 方法之外的三个方法,都不是必须有的,因此我们必须要实现的方法是 doInBackground 方法。

  1. 启动异步任务

 在主线程中执行如下代码开始执行异步任务:

new MyAsyncTask().execute(Params…ps);//其中的ps参数就是传递给doInBackgrount方法的。通常是一个下载网络资源的路径

  1. 停止异步任务
  1. 自然结束。当doInBackground方法执行完毕,异步任务自行结束
  2. 手动取消。我们可以在任何时刻来取消我们的异步任务的执行,通过调用 cancel(boolean)方法,调用完这个方法后系统会随后调用 isCancelled() 方法并且返回true。如果调用了这个方法,那么在 doInBackgroud() 方法执行完之后,就不会调用 onPostExecute() 方法了,取而代之的是调用 onCancelled() 方法。为了确保Task已经被取消了,我们需要经常调用 isCancelled() 方法来判断,如果有必要的话。

  1. 使用异步任务的一些线程规则

The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.

    The task instance must be created on the UI thread.

    execute(Params...) must be invoked on the UI thread.

    Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.

    The task can be executed only once (an exception will be thrown if a second execution is attempted.)

  • 使用AsyncTask从网上下载资源
    1. 下载图片并实现显示下载进度,下载完成显示

 

/**

 * 使用异步任务的规则

1.声明一个类继承AsyncTask,标注三个参数的类型

2.第一个参数表示要执行的任务,通常是网络的路径

 * 第二个参数表示进度的刻度,通常是整形 第三个参数表示任务执行的返回结果

 *

 */

 

public class MyTask2 extends AsyncTask<String, Integer, byte[]> {

 

// 执行异步任务的后台操作的

protected byte[] doInBackground(String... params) {

byte[] data = null;

String url = params[0]; // 得到传进来的网络地址

HttpClient hc = new DefaultHttpClient();

HttpGet get = new HttpGet(url);

InputStream is = null;

try {

HttpResponse resp = hc.execute(get);

if (resp.getStatusLine().getStatusCode() == 200) {

ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 创建一个内存输出流

is = resp.getEntity().getContent(); // 从结果里得到输入流

// 获取网络数据大小

long fileSize = resp.getEntity().getContentLength();

// 定义一个当前获取到的数据的大小

int curSize = 0;

int len = 0;

byte[] buffer = new byte[1024];

while ((len = is.read(buffer)) != -1) {

curSize += len;

// 计算进度的百分比

int progress = (int) (curSize / (float) fileSize * 100);

// 发布并更新进度

publishProgress(progress);

// 往内存流里写

baos.write(buffer, 0, len);

baos.flush();

}

data = baos.toByteArray();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

//关闭输入流

if (is != null) {

is.close();

}

} catch (IOException e) {

e.printStackTrace();

}

 

}

return data;

}

 

// 异步任务开始前执行

protected void onPreExecute() {

super.onPreExecute();

// 把进度条显示出来

dialog.show();

}

 

// 更新UI界面的进度条的

protected void onProgressUpdate(Integer... values) {

super.onProgressUpdate(values);

int progress = values[0];

dialog.setProgress(progress);

if (progress == 100) {

dialog.dismiss();

}

}

 

// 把异步任务操作的结果设置给UI界面的

protected void onPostExecute(byte[] result) {

super.onPostExecute(result);

// 创建位图

Bitmap bm = BitmapFactory.decodeByteArray(result, 0, result.length);

// 把位图设置给IV控件

iv.setImageBitmap(bm);

}

 

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android异步任务是一种常用的执行耗时操作的方式,但是在进行单元测试时,由于异步任务的特性,需要特别注意。下面将介绍如何进行Android异步任务的单元测试。 首先,创建一个测试类,并使用@RunWith和@LargeTest注解来告诉JUnit运行器我们正在进行测试: ``` @RunWith(AndroidJUnit4.class) @LargeTest public class MyTaskTest { } ``` 然后,在测试类中创建一个测试方法,使用@RunWith和@UiThreadTest注解来标记该方法需要在UI线程上运行: ``` @Test @UiThreadTest public void testMyTask() { // 测试代码 } ``` 接下来,创建一个CountDownLatch对象,在异步任务中的onPostExecute方法中,调用countDown()方法来通知主线程异步任务完成: ``` protected void onPostExecute(Result result) { // 异步任务完成,通知主线程 countDownLatch.countDown(); } ``` 在测试方法中,需要使用countDownLatch.await()来等待异步任务完成: ``` @Test @UiThreadTest public void testMyTask() throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(1); // 创建异步任务 MyTask myTask = new MyTask() { @Override protected void onPostExecute(Result result) { super.onPostExecute(result); // 异步任务完成,通知主线程 countDownLatch.countDown(); } }; // 执行异步任务 myTask.execute(); // 等待异步任务完成 countDownLatch.await(); // 进行断言 // ... } ``` 最后,在测试方法中,进行断言来验证异步任务的执行结果是否符合预期。 通过以上步骤,我们可以实现对Android异步任务的单元测试,确保其正确性和稳定性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值