在AsyncTask中等待异步网络任务的最佳方法

时间:2016-09-03 20:04:00

标签: android android-asynctask vimeo-api

我正在使用我的Android应用中的Vimeo API从我的Vimeo Pro帐户中提取特定vimeo视频的链接,然后通过AsyncTask下载此视频。读/写文件很好,但是我在拉链接并将其传递给该方法时遇到了麻烦。

代码如下:

 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()打印出链接,并将其用作代码的测试链接。当我在vimeoClient.fetchNetworkContent之外运行string link = xxx和DownloadFile时(在最后注释掉),代码工作,而当它们放在fetchNetworkContent()方法中时,它会遇到NetworkOnMainThreadException。

问题是我需要在DownloadFile()运行之前检索链接。有没有办法让我在fetchNetworkContent中解决这个问题?或者有没有办法强制系统在注释掉的DownloadFile()之前等待,直到networkFetchContent完成?

编辑:所以我根据cricket_007链接AsyncTasks的答案更新了我的代码。我没有创建第二个AsyncTask,而是决定用逻辑系统将它循环到同一个任务中。

首先运行的DownloadFileFromURL()基本上询问,我给出了哪些信息?

如果给出了一个url,它将运行DownloadFile(url,outputsFileName)。 如果没有,如果它收到关键字&#34; vimeo&#34;,它使用vimeoClient查找链接,然后从内部运行DownloadFileFromURL(vimeoLinkURL,outputsFileName)。我想我只是使用了逻辑树。

    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();
        }
    }
}

我已经将他的答案标记为正确,而不是因为它是最终的代码,但我发现它比我使用的特定代码更具信息性。我的代码确实特定于我在这个用例中的特定解决方案,但他的解释是真正的解决方案。

2 个答案:

答案 0 :(得分:0)

您可以尝试这样做。

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);
}

答案 1 :(得分:0)

目前还不清楚DownloadFile方法正在做什么,但您可能需要一个辅助AsyncTask。

旁注:我希望VimeoClient.getInstance().fetchNetworkContent无论如何都会在其自己的主题中运行,因此它不应该需要AsyncTask,但我们会假装它不会。

推荐的方法&#34;等待&#34;对于AsyncTask,要小心地将调用链接在一起。例如,如果给一个AsyncTask回调,那么success方法就会运行。在success内,你可以开始一个新的任务,调用DownloadFile(如果你想下载所有的链接,可能会给它整个ArrayList<VideoFile>而不是一个链接)

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");