我想报告 Android独立计算函数在进行不间断计算时的进度。
通过Android-Independant,我的意思是包的代码不能依赖于任何Android包。
理想情况下,我希望能够监控任何需要时间才能完成的功能的进度。 我使用AsyncTask定期向UI线程报告。 AsyncTask启动一个运行该函数的Thread。 因此,每一秒,AsyncTask都会询问Thread的进度并将其发布到UI Thread。
所以我有三个主题:
它几乎可以工作,但我对结果不满意,我认为我的实现很麻烦而且坏了。
我发现了两个问题:
1-:
04-07 15:34:31.416 18706-18834/com.example.android.elevationdrag D/yo? loop(99)0.0 0.0 0.0 0
04-07 15:34:32.416 18706-18834/com.example.android.elevationdrag D/yo? loop(98)0.0 0.0 0.0 0
04-07 15:34:33.416 18706-18834/com.example.android.elevationdrag D/yo? loop(97)0.0 0.0 0.0 0
04-07 15:34:34.416 18706-18834/com.example.android.elevationdrag D/yo? loop(96)0.0 0.0 0.0 0
04-07 15:34:34.826 18706-18835/com.example.android.elevationdrag D/yoSVC? 0.0
04-07 15:34:35.006 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 5547K, 50% free 5614K/11228K, paused 29ms, total 30ms
04-07 15:34:35.416 18706-18834/com.example.android.elevationdrag D/yo? loop(95)0.16882964936278524 0.0 0.0 0
04-07 15:34:35.456 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 1341K, 44% free 6321K/11228K, paused 24ms, total 24ms
04-07 15:34:35.916 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 812K, 33% free 7556K/11228K, paused 31ms, total 31ms
04-07 15:34:36.356 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 835K, 22% free 8769K/11228K, paused 40ms, total 40ms
04-07 15:34:36.426 18706-18834/com.example.android.elevationdrag D/yo? loop(94)0.461804305565497 0.16957664338683295 1696.0 1696
04-07 15:34:36.776 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 870K, 12% free 9946K/11228K, paused 47ms, total 47ms
04-07 15:34:37.286 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 854K, 8% free 11370K/12340K, paused 61ms, total 61ms
04-07 15:34:37.426 18706-18834/com.example.android.elevationdrag D/yo? loop(93)0.7725448196430245 0.461804305565497 4618.0 4618
04-07 15:34:37.796 18706-18835/com.example.android.elevationdrag D/dalvikvm? GC_FOR_ALLOC freed 1149K, 10% free 12877K/14236K, paused 68ms, total 68ms
04-07 15:34:38.126 18706-18835/com.example.android.elevationdrag D/yo? Released from DoCalculatePlan.run()
04-07 15:34:38.436 18706-18834/com.example.android.elevationdrag D/yo? loop(92)100.0 0.7728058175550427 7728.0 7728
yo
行来自AsyncTask,我在其中放置以下行:
Log.d("yo", "loop("+loops+")" +String.valueOf(cpt_plan.getPercentProgress())+" "+String.valueOf(progressr)+" "+String.valueOf(progressd)+" "+String.valueOf(progress));
yoSVC
行来自函数本身,我在其中放置以下行:
Log.d("yoSVC", String.valueOf(this.percentProgress));
从服务类进行更多日志记录。可以观察到在15:53:45.096发生的上下文切换,在调用Thread.sleep()后恰好一秒钟。
04-07 15:53:43.096 24348-24421/com.example.android.elevationdrag D/yo? loop(99)0.0 0.0 0.0 0
04-07 15:53:44.096 24348-24421/com.example.android.elevationdrag D/yo? loop(98)0.0 0.0 0.0 0
04-07 15:53:44.486 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.011000550888307417
04-07 15:53:44.506 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.022001101776615132
04-07 15:53:44.546 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.04500068861038525
04-07 15:53:44.566 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.05600123949869297
04-07 15:53:44.606 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.0790008263324631
04-07 15:53:44.626 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.09000137722077081
04-07 15:53:44.666 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.11300096405454094
04-07 15:53:44.706 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.13600055088830218
04-07 15:53:44.726 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.14700110177660103
04-07 15:53:44.756 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.1700006886103526
04-07 15:53:44.776 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.18100123949865146
04-07 15:53:44.816 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.20400082633240305
04-07 15:53:44.836 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.2150013772207019
04-07 15:53:44.866 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.23800096405445348
04-07 15:53:44.906 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.26100055088822277
04-07 15:53:44.926 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.27200110177653936
04-07 15:53:44.956 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.295000688610328
04-07 15:53:44.976 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.3060012394986446
04-07 15:53:45.016 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.32900082633243327
04-07 15:53:45.026 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.34000137722074986
04-07 15:53:45.066 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.3630009640545385
04-07 15:53:45.096 24348-24421/com.example.android.elevationdrag D/yo? loop(97)0.38391750447598555 0.0 0.0 0
04-07 15:53:45.106 24348-24422/com.example.android.elevationdrag D/yoSVC? 0.3860005508883272
“service”类使用double进行检测,以便发布进度:
class Plan
{
//...
// In order to inform users of the calculation progress, the service itself has
// to publish its progress.
private volatile double percentProgress;
//...
}
从Activity中提取的Android应用程序代码:
private class CalculatePlanTask extends AsyncTask<BigDecimal, Integer, Plan>
{
volatile boolean released = false;
volatile Plan cpt_plan;
CalculatePlanTask()
{
cpt_plan = new Plan();
}
private class DoCalculatePlan implements Runnable
{
final BigDecimal period;
final BigDecimal principal;
final BigDecimal rate;
private DoCalculatePlan(BigDecimal period, BigDecimal principal, BigDecimal rate)
{
this.period = period;
this.principal = principal;
this.rate = rate;
}
/**
* Starts executing the active part of the class' code. This method is
* called when a thread is started that has been created with a class which
* implements {@code Runnable}.
*/
@Override
public void run()
{
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
Situation situation = new Situation(principal, period.intValue());
cpt_plan.setSituationDeDepart(situation);
cpt_plan.setUniqueEvent(new RateChange(0, rate.movePointLeft(2), RateChange.RateChangeMode.KEEP_DURATION));
cpt_plan.computeSituation();
released = true;
//Log.d("yo", "Released from DoCalculatePlan.run()");
}
}
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
protected Plan doInBackground(BigDecimal... bds) {
publishProgress(0);
BigDecimal bdPeriods = bds[0];
BigDecimal bdPrincipal = bds[1];
BigDecimal bdRate = bds[2];
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
Thread calculator = new Thread(new DoCalculatePlan(bdPeriods, bdPrincipal, bdRate));
calculator.start();
final int timeoutMilli = 100 * 1000;
final int sleeptime = 1000;
final int maxLoops = timeoutMilli / sleeptime;
int loops = maxLoops;
int progress = 0;
boolean thrown = false;
while (!released && !thrown && --loops >= 0)
{
//DO NOT use this variable : progress = (int) Math.round(cpt_plan.getPercentProgress()*100.0);
//double progressr = cpt_plan.getPercentProgress(); //cpt_plan.percentProgress;
//double progressd = Math.round(cpt_plan.percentProgress*10000);
progress = (int) Math.round(cpt_plan.percentProgress*10000);
//DONE:
try
{
Thread.sleep(sleeptime);
publishProgress((int) Math.round(cpt_plan.getPercentProgress()*10000)); // Use directly the volatile variable which value is copied.
//Log.d("yo", "loop("+loops+")" +String.valueOf(cpt_plan.getPercentProgress())+" "+String.valueOf(progressr)+" "+String.valueOf(progressd)+" "+String.valueOf(progress));
}
catch (InterruptedException e)
{
released = true;
thrown = true;
}
}
//DONE : put the thread in an interrupted state.
// we cannot kill it :(
calculator.interrupt();
if (0 == loops || thrown)
return null;
return cpt_plan;
}
protected void onProgressUpdate(Integer... progress)
{
int p = progress[0];
EditText principal = (EditText) findViewById(R.id.editPrincipal);
principal.setText(progress[0].toString());
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
protected void onPostExecute(Plan p_plan)
{
if (null == p_plan)
plan = new Plan();
else
plan = p_plan;
postCalculateImpl();
}
}
代码已被修改很多次以进行实验,所以可能看起来有点奇怪,然而,建设性意见表示赞赏。
在进一步讨论之前,我想知道我是否误解了某些内容,而且到目前为止我发现的大多数问题或博客条目都是在任务中或使用Android代码实现的。
我想知道为什么我的计算线程在AsyncTask中调用sleep之后不会立即开始工作(可能是这样且日志记录容易出错)。
我也想知道如何在不将丑陋的线程代码放入计算功能的情况下中断我的线程。每次设置percentProgress时调用Thread.isInterrupted()都是我最容易接受的。
我必须注意这里的文档: http://developer.android.com/reference/android/os/AsyncTask.html
说
首次引入时,AsyncTasks在单个上串行执行 背景线程。从DONUT开始,这被改成了一个池 允许多个任务并行运行的线程。从...开始 HONEYCOMB,任务在单个线程上执行以避免常见 并行执行导致的应用程序错误。
如果您真的想要并行执行,可以调用 executeOnExecutor(java.util.concurrent.Executor,Object [])with THREAD_POOL_EXECUTOR
因此,当我测试executeOnExecutor()时,我期望并发执行,但只看到顺序执行。
此答案Running multiple AsyncTasks at the same time -- not possible?可能会解释此行为,因为我的设备在Android 4.4下运行。但是我身上的错误更有可能发生。