在 AsyncTask 中等待异步网络任务的最佳方式
Best way to wait for an asychronous network task within AsyncTask
我正在通过我的 android 应用程序中的 Vimeo API 从我的 Vimeo Pro 帐户中提取特定 vimeo 视频的 link,然后通过异步任务。文件的 read/write 没问题,但我无法提取 link 并将其传递给该方法。
代码如下:
class DownloadFileFromURL extends AsyncTask<String, String, String> {
...
@Override
protected String doInBackground(final String... args) {
// args[1]/name is the output file name
String name = args[1];
...
// pos is the position within the vimeo channel's array
final int pos = Integer.parseInt(args[3]);
//Here is the main code, args[2] is the channel id for
//the specific vimeo channel that the code
//needs to pull the video files from.
VimeoClient.getInstance().fetchNetworkContent(args[2], new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
//If the video exists, get the video object,
//and then get the video files related to that object from download[].
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
// Get the video file, and then get it's link, store as string.
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
**link = [test direct link to mp4];
DownloadFile(link, args[1]);**
}
}
}
...
});
**//String link = [test direct link to mp4];
//DownloadFile(link, args[1]);**
}
...
}
代码末尾的字符串变量和 DownloadFile(String link, string outputName) 行是我的主要问题。我从 videoFile.getLink() 中打印出 link,并将其用作代码的测试 link。当我 运行 字符串 link = xxx 和 vimeoClient.fetchNetworkContent 之外的 DownloadFile(如最后注释掉)时,代码在将它们放在 fetchNetworkContent() 方法中时工作,它会遇到 NetworkOnMainThreadException。
问题是我需要在 DownloadFile() 运行 之前检索 link。我有办法在 fetchNetworkContent 中解决这个问题吗?或者有没有办法让我强制系统在被注释掉的 DownloadFile() 之前等待,直到 networkFetchContent 完成?
编辑:所以我根据 cricket_007 对链接 AsyncTasks 的回答更新了我的代码。不过,我没有创建第二个 AsyncTask,而是决定使用逻辑系统在同一个任务中循环它。
首先 运行ning DownloadFileFromURL() 基本上会问,我得到了什么信息?
如果给定 url,它将 运行 DownloadFile(url, outputtedFileName)。
如果不是,如果它收到关键字 "vimeo",它会使用 vimeoClient 查找 link,然后 运行s DownloadFileFromURL(vimeoLinkURL, outputtedFileName) 从内部。我想我只是用了一个逻辑树。
class DownloadFileFromURL extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* Downloading file in background thread
*/
@Override
protected String doInBackground(final String... args) {
final String name = args[1];
// Check if this is already a url link ending in .mp4
if(FilenameUtils.isExtension(args[0], "mp4")){
DownloadFile(args[0], args[1]);
}
//If not, is it a vimeo video? Check with keyword "vimeo"
else if (args[0].contains("vimeo")){
final int pos = Integer.parseInt(args[3]);
VimeoClient.getInstance().fetchNetworkContent(args[2], new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
Log.d("VimeoClient", "Success in VimeoList Reading");
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
new DownloadFileFromURL().execute(link, args[1], args[2], args[3]);
}
}
}
@Override
public void failure(VimeoError error) {
Log.d("VimeoError", "Failure in VideoList Reading in VideoDownloader class");
}
});
// return null so that the Toast is not created for completion
// since this ends in DownloadFile()
return null;
}
return name;
}
@Override
protected void onPostExecute(String fileName) {
if(fileName != null) {
Toast.makeText(mContext, "Completed download of " + fileName, Toast.LENGTH_LONG).show();
}
}
}
我将他的回答标记为正确,不是因为它是最终代码,而是我发现它比我使用的特定代码提供更多信息。我的代码确实特定于我在这个用例中的特定解决方案,但他的解释是真正的解决方案。
这是您可以尝试做的事情。
class DownloadFileFromURL extends AsyncTask<String, String, String> implements LinkReceivedListener{
...
LinkRecievedListener callbackListener;
@Override
protected void onPostExecute(String result) {
// The result is the returned String link value from doInbackground()
DownloadFile(result, args[1]);
}
@Override
protected String doInBackground(final String... args) {
String name = args[1];
final int pos = Integer.parseInt(args[3]);
VimeoClient.getInstance().fetchNetworkContent(args[2], new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
//If the video exists, get the video object,
//and then get the video files related to that object from download[].
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
// Get the video file, and then get it's link, store as string.
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
callbackListener.onSuccess(link);
}
}
}
...
});
}
...
}
public interface LinkRecievedListener {
void onSuccess(String linkString);
}
尚不清楚 DownloadFile 方法的作用,但您可能需要一个辅助 AsyncTask。
旁注:我希望 VimeoClient.getInstance().fetchNetworkContent
无论如何都会 运行 在它自己的线程中,所以它不应该需要 AsyncTask,但我们会假装它不需要。
针对 AsyncTask "wait" 的推荐方法是小心地将调用链接在一起。例如,如果你给一个 AsyncTask 回调,那么 success
方法得到 运行。从那个 success
中,你可以开始一个新的任务,它将调用 DownloadFile
(如果你想下载所有的,可能给它整个 ArrayList<VideoFile>
而不是一个 link links)
class DownloadFileFromURL extends AsyncTask<String, Void, Void> {
private ModelCallback<VideoList> callback;
public DownloadFileFromURL(ModelCallback<VideoList> callback) {
this.callback = callback;
}
@Override
protected Void doInBackground(final String... args) {
//Here is the main code, args[0] is the channel id for
//the specific vimeo channel that the code
//needs to pull the video files from.
VimeoClient.getInstance().fetchNetworkContent(args[0], callback);
}
...
}
然后,无论您在哪里调用该任务,都传入要执行的操作的接口
// Need these values inside the callback - have to be final
final String arg1;
final int pos;
// The callback that is hit from doInBackground()
ModelCallback<VideoList> callback = new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
//If the video exists, get the video object,
//and then get the video files related to that object from download[].
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
// Get the video file, and then get it's link, store as string.
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
// TODO: Might need to execute another AsyncTask
DownloadFile(link, arg1);
}
}
}
...
};
// pass the callback to the task
new DownloadFileFromURL(callback).execute("channel_id");
我正在通过我的 android 应用程序中的 Vimeo API 从我的 Vimeo Pro 帐户中提取特定 vimeo 视频的 link,然后通过异步任务。文件的 read/write 没问题,但我无法提取 link 并将其传递给该方法。
代码如下:
class DownloadFileFromURL extends AsyncTask<String, String, String> {
...
@Override
protected String doInBackground(final String... args) {
// args[1]/name is the output file name
String name = args[1];
...
// pos is the position within the vimeo channel's array
final int pos = Integer.parseInt(args[3]);
//Here is the main code, args[2] is the channel id for
//the specific vimeo channel that the code
//needs to pull the video files from.
VimeoClient.getInstance().fetchNetworkContent(args[2], new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
//If the video exists, get the video object,
//and then get the video files related to that object from download[].
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
// Get the video file, and then get it's link, store as string.
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
**link = [test direct link to mp4];
DownloadFile(link, args[1]);**
}
}
}
...
});
**//String link = [test direct link to mp4];
//DownloadFile(link, args[1]);**
}
...
}
代码末尾的字符串变量和 DownloadFile(String link, string outputName) 行是我的主要问题。我从 videoFile.getLink() 中打印出 link,并将其用作代码的测试 link。当我 运行 字符串 link = xxx 和 vimeoClient.fetchNetworkContent 之外的 DownloadFile(如最后注释掉)时,代码在将它们放在 fetchNetworkContent() 方法中时工作,它会遇到 NetworkOnMainThreadException。
问题是我需要在 DownloadFile() 运行 之前检索 link。我有办法在 fetchNetworkContent 中解决这个问题吗?或者有没有办法让我强制系统在被注释掉的 DownloadFile() 之前等待,直到 networkFetchContent 完成?
编辑:所以我根据 cricket_007 对链接 AsyncTasks 的回答更新了我的代码。不过,我没有创建第二个 AsyncTask,而是决定使用逻辑系统在同一个任务中循环它。
首先 运行ning DownloadFileFromURL() 基本上会问,我得到了什么信息?
如果给定 url,它将 运行 DownloadFile(url, outputtedFileName)。 如果不是,如果它收到关键字 "vimeo",它会使用 vimeoClient 查找 link,然后 运行s DownloadFileFromURL(vimeoLinkURL, outputtedFileName) 从内部。我想我只是用了一个逻辑树。
class DownloadFileFromURL extends AsyncTask<String, String, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
/**
* Downloading file in background thread
*/
@Override
protected String doInBackground(final String... args) {
final String name = args[1];
// Check if this is already a url link ending in .mp4
if(FilenameUtils.isExtension(args[0], "mp4")){
DownloadFile(args[0], args[1]);
}
//If not, is it a vimeo video? Check with keyword "vimeo"
else if (args[0].contains("vimeo")){
final int pos = Integer.parseInt(args[3]);
VimeoClient.getInstance().fetchNetworkContent(args[2], new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
Log.d("VimeoClient", "Success in VimeoList Reading");
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
new DownloadFileFromURL().execute(link, args[1], args[2], args[3]);
}
}
}
@Override
public void failure(VimeoError error) {
Log.d("VimeoError", "Failure in VideoList Reading in VideoDownloader class");
}
});
// return null so that the Toast is not created for completion
// since this ends in DownloadFile()
return null;
}
return name;
}
@Override
protected void onPostExecute(String fileName) {
if(fileName != null) {
Toast.makeText(mContext, "Completed download of " + fileName, Toast.LENGTH_LONG).show();
}
}
}
我将他的回答标记为正确,不是因为它是最终代码,而是我发现它比我使用的特定代码提供更多信息。我的代码确实特定于我在这个用例中的特定解决方案,但他的解释是真正的解决方案。
这是您可以尝试做的事情。
class DownloadFileFromURL extends AsyncTask<String, String, String> implements LinkReceivedListener{
...
LinkRecievedListener callbackListener;
@Override
protected void onPostExecute(String result) {
// The result is the returned String link value from doInbackground()
DownloadFile(result, args[1]);
}
@Override
protected String doInBackground(final String... args) {
String name = args[1];
final int pos = Integer.parseInt(args[3]);
VimeoClient.getInstance().fetchNetworkContent(args[2], new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
//If the video exists, get the video object,
//and then get the video files related to that object from download[].
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
// Get the video file, and then get it's link, store as string.
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
callbackListener.onSuccess(link);
}
}
}
...
});
}
...
}
public interface LinkRecievedListener {
void onSuccess(String linkString);
}
尚不清楚 DownloadFile 方法的作用,但您可能需要一个辅助 AsyncTask。
旁注:我希望 VimeoClient.getInstance().fetchNetworkContent
无论如何都会 运行 在它自己的线程中,所以它不应该需要 AsyncTask,但我们会假装它不需要。
针对 AsyncTask "wait" 的推荐方法是小心地将调用链接在一起。例如,如果你给一个 AsyncTask 回调,那么 success
方法得到 运行。从那个 success
中,你可以开始一个新的任务,它将调用 DownloadFile
(如果你想下载所有的,可能给它整个 ArrayList<VideoFile>
而不是一个 link links)
class DownloadFileFromURL extends AsyncTask<String, Void, Void> {
private ModelCallback<VideoList> callback;
public DownloadFileFromURL(ModelCallback<VideoList> callback) {
this.callback = callback;
}
@Override
protected Void doInBackground(final String... args) {
//Here is the main code, args[0] is the channel id for
//the specific vimeo channel that the code
//needs to pull the video files from.
VimeoClient.getInstance().fetchNetworkContent(args[0], callback);
}
...
}
然后,无论您在哪里调用该任务,都传入要执行的操作的接口
// Need these values inside the callback - have to be final
final String arg1;
final int pos;
// The callback that is hit from doInBackground()
ModelCallback<VideoList> callback = new ModelCallback<VideoList>(VideoList.class) {
@Override
public void success(VideoList videoList) {
//If the video exists, get the video object,
//and then get the video files related to that object from download[].
if (videoList != null && videoList.data != null && !videoList.data.isEmpty()) {
Video video = videoList.data.get(pos);
ArrayList<VideoFile> videoFiles = video.download;
// Get the video file, and then get it's link, store as string.
if(videoFiles != null && !videoFiles.isEmpty()) {
VideoFile videoFile = videoFiles.get(2); // you could sort these files by size, fps, width/height
String link = videoFile.getLink();
// TODO: Might need to execute another AsyncTask
DownloadFile(link, arg1);
}
}
}
...
};
// pass the callback to the task
new DownloadFileFromURL(callback).execute("channel_id");