展会信息港展会大全

Android 处理多线程 UserTask
来源:互联网   发布日期:2016-01-13 22:11:37   浏览:2154次  

导读:Android 处理多线程时,不能在线程范围内调用UI,通过这个方式能够很好的在线程中,对UI进行控制。/*多线程处理-程序加载线程*/private class LoginFromTask extends UserTaskString, Integer, String{......

Android 处理多线程时,不能在线程范围内调用UI,通过这个方式能够很好的在线程中,对UI进行控制。

/*多线程处理-程序加载线程*/

private class LoginFromTask extends UserTask<String, Integer, String>

{

/**

* 线程启动初始化操作

*/

@Override

public void onPreExecute()

{

//在这儿进行线程运行前的初始化,比如显示一个提示框或进度条

}

/**

* 需要长时间阻塞处理的任务

*/

@Override

public String doInBackground(String...stgs)

{线程中的处理,这儿不能操作UI

return null;

//publishProgress();//调用这个函数好后会激活onProgressUpdate()事件

}

/**

* 线程内更新处理

*/

@Override

public void onProgressUpdate(Integer... progress){

//这边用于处理线程未完成的提示处理,例如进度条更新

}

/**

* 阻塞任务执行完后的清理工作

*/

@Override

public void onPostExecute(String result)

{

//线程处理结束,操作UI,关闭提示框或者关闭进度条

}

}

完整代码如下:

/*

* Copyright (C) 2008 Google Inc.

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

*http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package com.google.android.photostream;

import android.os.*;

import android.os.Process;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.LinkedBlockingQueue;

import java.util.concurrent.ThreadFactory;

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.TimeoutException;

import java.util.concurrent.CancellationException;

import java.util.concurrent.atomic.AtomicInteger;

/**

* <p>UserTask enables proper and easy use of the UI thread. This class allows to

* perform background operations and publish results on the UI thread without

* having to manipulate threads and/or handlers.</p>

*

* <p>A user task is defined by a computation that runs on a background thread and

* whose result is published on the UI thread. A user task is defined by 3 generic

* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,

* and 4 steps, called <code>begin</code>, <code>doInBackground</code>,

* <code>processProgress<code> and <code>end</code>.</p>

*

* <h2>Usage</h2>

* <p>UserTask must be subclassed to be used. The subclass will override at least

* one method ({@link #doInBackground(Object[])}), and most often will override a

* second one ({@link #onPostExecute(Object)}.)</p>

*

* <p>Here is an example of subclassing:</p>

* <pre>

* private class DownloadFilesTask extends UserTask&lt;URL, Integer, Long&gt; {

*public File doInBackground(URL... urls) {

*int count = urls.length;

*long totalSize = 0;

*for (int i = 0; i < count; i++) {

*totalSize += Downloader.downloadFile(urls[i]);

*publishProgress((int) ((i / (float) count) * 100));

*}

*}

*

*public void onProgressUpdate(Integer... progress) {

*setProgressPercent(progress[0]);

*}

*

*public void onPostExecute(Long result) {

*showDialog("Downloaded " + result + " bytes");

*}

* }

* </pre>

*

* <p>Once created, a task is executed very simply:</p>

* <pre>

* new DownloadFilesTask().execute(new URL[] { ... });

* </pre>

*

* <h2>User task's generic types</h2>

* <p>The three types used by a user task are the following:</p>

* <ol>

*<li><code>Params</code>, the type of the parameters sent to the task upon

*execution.</li>

*<li><code>Progress</code>, the type of the progress units published during

*the background computation.</li>

*<li><code>Result</code>, the type of the result of the background

*computation.</li>

* </ol>

* <p>Not all types are always used by a user task. To mark a type as unused,

* simply use the type {@link Void}:</p>

* <pre>

* private class MyTask extends UserTask<Void, Void, Void) { ... }

* </pre>

*

* <h2>The 4 steps</h2>

* <p>When a user task is executed, the task goes through 4 steps:</p>

* <ol>

*<li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task

*is executed. This step is normally used to setup the task, for instance by

*showing a progress bar in the user interface.</li>

*<li>{@link #doInBackground(Object[])}, invoked on the background thread

*immediately after {@link # onPreExecute ()} finishes executing. This step is used

*to perform background computation that can take a long time. The parameters

*of the user task are passed to this step. The result of the computation must

*be returned by this step and will be passed back to the last step. This step

*can also use {@link #publishProgress(Object[])} to publish one or more units

*of progress. These values are published on the UI thread, in the

*{@link #onProgressUpdate(Object[])} step.</li>

*<li>{@link # onProgressUpdate (Object[])}, invoked on the UI thread after a

*call to {@link #publishProgress(Object[])}. The timing of the execution is

*undefined. This method is used to display any form of progress in the user

*interface while the background computation is still executing. For instance,

*it can be used to animate a progress bar or show logs in a text field.</li>

*<li>{@link # onPostExecute (Object)}, invoked on the UI thread after the background

*computation finishes. The result of the background computation is passed to

*this step as a parameter.</li>

* </ol>

*

* <h2>Threading rules</h2>

* <p>There are a few threading rules that must be followed for this class to

* work properly:</p>

* <ul>

*<li>The task instance must be created on the UI thread.</li>

*<li>{@link #execute(Object[])} must be invoked on the UI thread.</li>

*<li>Do not call {@link # onPreExecute ()}, {@link # onPostExecute (Object)},

*{@link #doInBackground(Object[])}, {@link # onProgressUpdate (Object[])}

*manually.</li>

*<li>The task can be executed only once (an exception will be thrown if

*a second execution is attempted.)</li>

* </ul>

*/

public abstract class UserTask<Params, Progress, Result> {

private static final String LOG_TAG = "UserTask";

private static final int CORE_POOL_SIZE = 1;

private static final int MAXIMUM_POOL_SIZE = 10;

private static final int KEEP_ALIVE = 10;

private static final BlockingQueue<Runnable> sWorkQueue =

new LinkedBlockingQueue<Runnable>(MAXIMUM_POOL_SIZE);

private static final ThreadFactory sThreadFactory = new ThreadFactory() {

private final AtomicInteger mCount = new AtomicInteger(1);

public Thread newThread(Runnable r) {

return new Thread(r, "UserTask #" + mCount.getAndIncrement());

}

};

private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,

MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);

private static final int MESSAGE_POST_RESULT = 0x1;

private static final int MESSAGE_POST_PROGRESS = 0x2;

private static final int MESSAGE_POST_CANCEL = 0x3;

private static final InternalHandler sHandler = new InternalHandler();

private final WorkerRunnable<Params, Result> mWorker;

private final FutureTask<Result> mFuture;

private volatile Status mStatus = Status.PENDING;

/**

* Indicates the current status of the task. Each status will be set only once

* during the lifetime of a task.

*/

public enum Status {

/**

* Indicates that the task has not been executed yet.

*/

PENDING,

/**

* Indicates that the task is running.

*/

RUNNING,

/**

* Indicates that {@link UserTask#onPostExecute(Object)} has finished.

*/

FINISHED,

}

/**

* Creates a new user task. This constructor must be invoked on the UI thread.

*/

public UserTask() {

mWorker = new WorkerRunnable<Params, Result>() {

public Result call() throws Exception {

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

return doInBackground(mParams);

}

};

mFuture = new FutureTask<Result>(mWorker) {

@Override

protected void done() {

Message message;

Result result = null;

try {

result = get();

} catch (InterruptedException e) {

android.util.Log.w(LOG_TAG, e);

} catch (ExecutionException e) {

throw new RuntimeException("An error occured while executing doInBackground()",

e.getCause());

} catch (CancellationException e) {

message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,

new UserTaskResult<Result>(UserTask.this, (Result[]) null));

message.sendToTarget();

return;

} catch (Throwable t) {

throw new RuntimeException("An error occured while executing "

+ "doInBackground()", t);

}

message = sHandler.obtainMessage(MESSAGE_POST_RESULT,

new UserTaskResult<Result>(UserTask.this, result));

message.sendToTarget();

}

};

}

/**

* Returns the current status of this task.

*

* @return The current status.

*/

public final Status getStatus() {

return mStatus;

}

/**

* Override this method to perform a computation on a background thread. The

* specified parameters are the parameters passed to {@link #execute(Object[])}

* by the caller of this task.

*

* This method can call {@link #publishProgress(Object[])} to publish updates

* on the UI thread.

*

* @param params The parameters of the task.

*

* @return A result, defined by the subclass of this task.

*

* @see #onPreExecute()

* @see #onPostExecute(Object)

* @see #publishProgress(Object[])

*/

public abstract Result doInBackground(Params... params);

/**

* Runs on the UI thread before {@link #doInBackground(Object[])}.

*

* @see #onPostExecute(Object)

* @see #doInBackground(Object[])

*/

public void onPreExecute() {

}

/**

* Runs on the UI thread after {@link #doInBackground(Object[])}. The

* specified result is the value returned by {@link #doInBackground(Object[])}

* or null if the task was cancelled or an exception occured.

*

* @param result The result of the operation computed by {@link #doInBackground(Object[])}.

*

* @see #onPreExecute()

* @see #doInBackground(Object[])

*/

@SuppressWarnings({"UnusedDeclaration"})

public void onPostExecute(Result result) {

}

/**

* Runs on the UI thread after {@link #publishProgress(Object[])} is invoked.

* The specified values are the values passed to {@link #publishProgress(Object[])}.

*

* @param values The values indicating progress.

*

* @see #publishProgress(Object[])

* @see #doInBackground(Object[])

*/

@SuppressWarnings({"UnusedDeclaration"})

public void onProgressUpdate(Progress... values) {

}

/**

* Runs on the UI thread after {@link #cancel(boolean)} is invoked.

*

* @see #cancel(boolean)

* @see #isCancelled()

*/

public void onCancelled() {

}

/**

* Returns <tt>true</tt> if this task was cancelled before it completed

* normally.

*

* @return <tt>true</tt> if task was cancelled before it completed

*

* @see #cancel(boolean)

*/

public final boolean isCancelled() {

return mFuture.isCancelled();

}

/**

* Attempts to cancel execution of this task.This attempt will

* fail if the task has already completed, already been cancelled,

* or could not be cancelled for some other reason. If successful,

* and this task has not started when <tt>cancel</tt> is called,

* this task should never run.If the task has already started,

* then the <tt>mayInterruptIfRunning</tt> parameter determines

* whether the thread executing this task should be interrupted in

* an attempt to stop the task.

*

* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this

*task should be interrupted; otherwise, in-progress tasks are allowed

*to complete.

*

* @return <tt>false</tt> if the task could not be cancelled,

*typically because it has already completed normally;

*<tt>true</tt> otherwise

*

* @see #isCancelled()

* @see #onCancelled()

*/

public final boolean cancel(boolean mayInterruptIfRunning) {

return mFuture.cancel(mayInterruptIfRunning);

}

/**

* Waits if necessary for the computation to complete, and then

* retrieves its result.

*

* @return The computed result.

*

* @throws CancellationException If the computation was cancelled.

* @throws ExecutionException If the computation threw an exception.

* @throws InterruptedException If the current thread was interrupted

*while waiting.

*/

public final Result get() throws InterruptedException, ExecutionException {

return mFuture.get();

}

/**

* Waits if necessary for at most the given time for the computation

* to complete, and then retrieves its result.

*

* @param timeout Time to wait before cancelling the operation.

* @param unit The time unit for the timeout.

*

* @return The computed result.

*

* @throws CancellationException If the computation was cancelled.

* @throws ExecutionException If the computation threw an exception.

* @throws InterruptedException If the current thread was interrupted

*while waiting.

* @throws TimeoutException If the wait timed out.

*/

public final Result get(long timeout, TimeUnit unit) throws InterruptedException,

ExecutionException, TimeoutException {

return mFuture.get(timeout, unit);

}

/**

* Executes the task with the specified parameters. The task returns

* itself (this) so that the caller can keep a reference to it.

*

* This method must be invoked on the UI thread.

*

* @param params The parameters of the task.

*

* @return This instance of UserTask.

*

* @throws IllegalStateException If {@link #getStatus()} returns either

*{@link UserTask.Status#RUNNING} or {@link UserTask.Status#FINISHED}.

*/

public final UserTask<Params, Progress, Result> execute(Params... params) {

if (mStatus != Status.PENDING) {

switch (mStatus) {

case RUNNING:

throw new IllegalStateException("Cannot execute task:"

+ " the task is already running.");

case FINISHED:

throw new IllegalStateException("Cannot execute task:"

+ " the task has already been executed "

+ "(a task can be executed only once)");

}

}

mStatus = Status.RUNNING;

onPreExecute();

mWorker.mParams = params;

sExecutor.execute(mFuture);

return this;

}

/**

* This method can be invoked from {@link #doInBackground(Object[])} to

* publish updates on the UI thread while the background computation is

* still running. Each call to this method will trigger the execution of

* {@link #onProgressUpdate(Object[])} on the UI thread.

*

* @param values The progress values to update the UI with.

*

* @see # onProgressUpdate (Object[])

* @see #doInBackground(Object[])

*/

protected final void publishProgress(Progress... values) {

sHandler.obtainMessage(MESSAGE_POST_PROGRESS,

new UserTaskResult<Progress>(this, values)).sendToTarget();

}

private void finish(Result result) {

onPostExecute(result);

mStatus = Status.FINISHED;

}

private static class InternalHandler extends Handler {

@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})

@Override

public void handleMessage(Message msg) {

UserTaskResult result = (UserTaskResult) msg.obj;

switch (msg.what) {

case MESSAGE_POST_RESULT:

// There is only one result

result.mTask.finish(result.mData[0]);

break;

case MESSAGE_POST_PROGRESS:

result.mTask.onProgressUpdate(result.mData);

break;

case MESSAGE_POST_CANCEL:

result.mTask.onCancelled();

break;

}

}

}

private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {

Params[] mParams;

}

@SuppressWarnings({"RawUseOfParameterizedType"})

private static class UserTaskResult<Data> {

final UserTask mTask;

final Data[] mData;

UserTaskResult(UserTask task, Data... data) {

mTask = task;

mData = data;

}

}

}

赞助本站

人工智能实验室

相关热词: 多线程 UserTask

AiLab云推荐
推荐内容
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港