从 Android AsyncTask 返回数据
我试图在 SO 上提出类似的问题,但没有得到任何帮助。
在我的 Android 应用程序中,我计划实现用户访问过的最近报价,即类似于网络上最近访问的页面。
以下是我要执行的步骤:
1.) 每当用户打开任何公司视图时,从数据库中获取公司代码
2.) 然后存储当前代码以及日期时间在数据库中。
3.) 对于从数据库中获取的所有符号,获取其当前值
和%Change
并显示公司名称、当前值和%更改列表中的。
问题出现在 ASyncTask
类中,因为 postExecute
方法不允许其返回类型为 void
以外的任何类型。
我做错了什么吗?
任何帮助都将是救星!!!
String[] rsym,rcmp,rchg;
rdbM = new RecentDBManager(CompanyView.this);
try {
Calendar date1 = Calendar.getInstance();
SimpleDateFormat dateformatter = new SimpleDateFormat(
"dd/MM/yyyy HH:mm:ss");
String currentdate = dateformatter.format(date1.getTime());
rdbM.openDB();
//STEP 1
rsym = rdbM.getRecent_sym();
//STEP 2
rdbM.setData(currentsymbol, currentdate);
rdbM.closeDB();
} catch (Exception e) {
throw new Error(" *** ERROR in DB Access *** "+ e.toString());
}
//STEP 3
for(int i=0;i<rsym.length;i++)
{
DownloadRecentQuote quotetask = new DownloadRecentQuote();
recentquotetask
.execute(new String[] { "http://abc.com/stockquote.aspx?id="
+ rsym[i] });
//CURRENT VALUE and %CHANGE which should be returned from ASyncTask class
rcmp[i]=valuearr[0];
rchg[i]=valuearr[1];
}
list1 = new ArrayList<HashMap<String, String>>();
HashMap<String, String> addList1;
for (int i = 0; i < limit; i++)
{
addList1 = new HashMap<String, String>();
addList1.put(RecentSym_COLUMN, rsym[i]);
addList1.put(RecentCMP_COLUMN, rcmp[i]);
addList1.put(RecentChg_COLUMN, rchg[i]);
list1.add(addList1);
RecentAdapter adapter1 = new RecentAdapter(
CompanyView.this, CompanyView.this, list1);
listrecent.setAdapter(adapter1);
}
private class DownloadRecentQuote extends AsyncTask<String, Void, String> {
/* Fetching data for RecentQuote information */
@Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
@Override
protected void onPostExecute(String result) {
arr1 = result.split("@");
if (arr1[0].length() != 0) {
if (arr1[0].equals("1")) {
arr = arr1[1].split(";");
//RETURN 2 STRINGS
String valuearr[];
valuearr[0] = arr[3];
valuearr[1] = arr[6].concat("%");
//return valuearr;
}
}
}
I tried to refer similar question on SO, but didn't got any help.
In my android app, I'm planning to implement Recent Quote the user has visited i.e. similar to recently visited pages on web.
Following are the steps I'm following:
1.) Whenever user opens any company view, fetch the company symbols from database
2.) Then store the current symbol along with dateTime in database.
3.) For all symbols fetched from database, Fetch their current value
and %Change
and display Company name, current value and %Change in a list.
The problem arises in the ASyncTask
class as postExecute
method doesn't allow it's return type to be any other than void
.
Am I doing anything wrong?
Any help will be life saver !!!
String[] rsym,rcmp,rchg;
rdbM = new RecentDBManager(CompanyView.this);
try {
Calendar date1 = Calendar.getInstance();
SimpleDateFormat dateformatter = new SimpleDateFormat(
"dd/MM/yyyy HH:mm:ss");
String currentdate = dateformatter.format(date1.getTime());
rdbM.openDB();
//STEP 1
rsym = rdbM.getRecent_sym();
//STEP 2
rdbM.setData(currentsymbol, currentdate);
rdbM.closeDB();
} catch (Exception e) {
throw new Error(" *** ERROR in DB Access *** "+ e.toString());
}
//STEP 3
for(int i=0;i<rsym.length;i++)
{
DownloadRecentQuote quotetask = new DownloadRecentQuote();
recentquotetask
.execute(new String[] { "http://abc.com/stockquote.aspx?id="
+ rsym[i] });
//CURRENT VALUE and %CHANGE which should be returned from ASyncTask class
rcmp[i]=valuearr[0];
rchg[i]=valuearr[1];
}
list1 = new ArrayList<HashMap<String, String>>();
HashMap<String, String> addList1;
for (int i = 0; i < limit; i++)
{
addList1 = new HashMap<String, String>();
addList1.put(RecentSym_COLUMN, rsym[i]);
addList1.put(RecentCMP_COLUMN, rcmp[i]);
addList1.put(RecentChg_COLUMN, rchg[i]);
list1.add(addList1);
RecentAdapter adapter1 = new RecentAdapter(
CompanyView.this, CompanyView.this, list1);
listrecent.setAdapter(adapter1);
}
private class DownloadRecentQuote extends AsyncTask<String, Void, String> {
/* Fetching data for RecentQuote information */
@Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
@Override
protected void onPostExecute(String result) {
arr1 = result.split("@");
if (arr1[0].length() != 0) {
if (arr1[0].equals("1")) {
arr = arr1[1].split(";");
//RETURN 2 STRINGS
String valuearr[];
valuearr[0] = arr[3];
valuearr[1] = arr[6].concat("%");
//return valuearr;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
postExecute() 无法返回值,因为它会返回给谁或什么?调用 AsyncTask 的原始方法消失了,因为 AsyncTask 在后台运行。它是异步的,意味着当 AsyncTask.execute() 返回时它仍然在后台运行,因此 postExecute() 无法返回值,因为没有任何东西可以返回它。
相反,您的 AsyncTask 需要引用回您的 Activity 或其他某个对象,以便它可以将您的值发布回其中。在您的代码中,调用execute() 之后的行不能出现,因为您的任务尚未完成。相反,您应该创建一个名为 updateSymbol( currentPrice,percentChange) 的方法,将所有代码移到其中的execute() 下面,并且在您的 AsyncTask 中您应该传递对 Activity 的引用。然后从 onPostExecute() 方法调用 updateSymbol( currentPrice,percentChange )。
但是,请小心,如果您有对 Activity 的引用,则它可能会在 doInBackground() 运行时被销毁,并且当 postExecute() 运行时,它应该只删除结果或不尝试更新 UI。例如,用户旋转手机导致 Activity 被破坏。我发现最好在活动中保留对 AsyncTask 的引用,以便在活动被销毁时可以取消()它。您可以调用 AsyncTask.cancel() 然后检查您的任务是否被取消,如下所示:
为所有 Activity 创建基类非常容易,以便您可以轻松跟踪 AsyncTasks 的运行情况:
一些快速指针。你不需要execute( new String[] { "blah" + blah } )。 Java 中的 Varargs 允许您执行此操作。执行(“废话”+废话)。您还捕获异常并继续,但没有真正处理它们。当事情真的发生时,这会很困难,因为你的应用程序捕获了它们,然后继续好像什么也没发生一样。如果您收到错误,您可能需要向用户提供一些反馈并停止尝试执行该过程。停止,向用户显示错误,然后让他们做下一步。将 catch 块移至方法的底部。
postExecute() can't return a value because who or what would it return to? Your original method that invoked the AsyncTask is gone because your AsyncTask is running in the background. It's asynchronous meaning when AsyncTask.execute() returns it's still running in the background, and hence postExecute() can't return a value because there's nothing to return it to.
Instead your AsyncTask needs a reference back to your Activity or some other object so it can post your values back to it. In your code the lines after you call execute() can't be there because your task hasn't finished. Instead you should create a method called updateSymbol( currentPrice, percentChange), move all that code below execute() in there, and in your AsyncTask you should pass a reference to the Activity. Then call updateSymbol( currentPrice, percentChange ) from the onPostExecute() method.
But, be careful if you have a reference back to an Activity it can be destroyed while your doInBackground() is running, and when postExecute() runs it should just drop the results or not attempt to update the UI. For example, the user rotates their phone causing the Activity to be destroyed. I find it best to hold a reference to the AsyncTask in the activity so it can cancel() it if the Activity is destroyed. You can call AsyncTask.cancel() then check if your task was canceled like:
It's really easy to create a base class for all Activities so you can easily keep track of AsyncTasks running:
Some quick pointers. You don't need execute( new String[] { "blah" + blah } ). Varargs in Java allow you to do this. execute( "blah" + blah ). You also are catching exceptions and continuing without really handling them. It will be hard when something really happens because your app catches them, and just continues as if nothing happened. If you get an error you might want to provide some feedback to the user and stop trying to execute that process. Stop, show an error to the user, and let them do the next thing. Move the catch blocks to the bottom of the methods.
本质上,AsyncTask.onPostExecute() 就是在执行 AsyncTask 的 doInBackground() 并返回执行结果后,你可以做任何你想做的事情。这应该被视为最佳实践。
当从 UI 线程调用 AsyncTask().execute() 时(请注意,必须从 UI 线程调用此方法),Android 框架会创建一个工作线程,并开始在此工作线程上运行您在 AsyncTask.doInBackground() 中编写的任何内容线。此时(调用new AsyncTask().execute()后),UI线程继续执行new AsyncTask().execute()之后的代码。因此,现在在运行时,您有两个线程(UI 和工作线程)同时运行。
但是 AsyncTask 执行结果何时何地从工作线程返回到 UI 线程呢?
工作线程 (doInBackground()) 完成并返回到 UI 线程的点是 AysncTask.onPostExecute()。一旦 AsyncTask 完成,框架就会保证在 UI 线程上调用此方法。换句话说,我们不关心在运行时何时何地调用 AsyncTask.onPostExecute(),我们只需要保证它最终会在未来的某个阶段被调用。这就是为什么该方法不返回执行结果的原因 - 相反,它要求执行结果作为 doInBackground() 的唯一方法参数传入。
另外,Android API提供了一种在编码时返回AsyncTask执行结果的方法,AsyncTask.get():
请记住,AsyncTask.get() 会阻塞调用线程的执行,如果在 UI 上调用它,您可能会收到 ANR 异常这是使用 AsyncTask.get() 的有效负载,通过在 UI 线程上调用它,您实际上使 AsyncTask(工作线程)与 UI 线程同步运行(通过使 UI 线程等待)。综上所述,这是可行的,但不推荐。
Essentially, AsyncTask.onPostExecute() is where you do whatever you want to do after AsyncTask's doInBackground() is executed and the execution result gets returned. This should be considered the best practice.
When AsyncTask().execute() is called from the UI thread (note that this method must be called from the UI thread), the Android framework creates a worker thread and starts running whatever you wrote in AsyncTask.doInBackground() on this worker thread. At this point (after calling new AsyncTask().execute()), the UI thread continues to execute code after new AsyncTask().execute(). So now during run time, you have two threads (UI and worker thread) both running simultaneously.
But where and when does the AsyncTask execution result get returned from the worker thread back to the UI thread?
The point where your worker thread (doInBackground()) finishes and returns to the UI thread is AysncTask.onPostExecute(). This method is guaranteed to be called by the framework on the UI thread as soon as AsyncTask finishes. In other words, we don't care where and when AsyncTask.onPostExecute() gets called at run time, we just need to guarantee it will be called ultimately at some stage in the future. This is the reason why this method does not return an execution result - instead, it requires that the execution result gets passed in as the only method parameter from doInBackground().
In addition, the Android API provides a way to return an AsyncTask execution result at coding time, AsyncTask.get():
Bear in mind that AsyncTask.get() will block the calling thread's execution, and you will probably get an ANR exception if you call it on the UI thread. This is the payload of using AsyncTask.get(), by calling it on the UI thread, you are actually making your AsyncTask (worker thread) run synchronously with UI thread (by making UI thread wait). To sum up, this is doable but not recommended.
仅供将来参考,因为这篇文章有点旧:
我创建了一个 Activity 类,它有一个 onStart() 方法和一个单独的 AsyncTask 类。根据我的测试,在 doInbackground() 方法之后,结果将首先发送到活动,然后 onPostExecute() 将运行。这是因为基于 logcat,我首先有第一个响应数据(由服务器发送),然后该响应将从活动中再次显示,最后将显示 onPostExecute() 中的消息。
活动代码:
AsyncTask 代码:
Just for future reference, because this post is a little old:
I have created an Activity class which has an onStart() method and a separate class for the AsyncTask. Based on my test, after the doInbackground() method the result will be sent to the activity first and after that onPostExecute() will run. This is because based off of logcat, I have my first response data (sent by server) first, then this response will show again from the activity and the last the message in onPostExecute() will show.
Code for the activity:
AsyncTask code: