Android,AsyncTask 不调用 onProgressUpdate 和 onPostExecute

Posted

技术标签:

【中文标题】Android,AsyncTask 不调用 onProgressUpdate 和 onPostExecute【英文标题】:Android, AsyncTask not calling onProgressUpdate and onPostExecute 【发布时间】:2018-05-24 15:12:46 【问题描述】:

请建议我解决此问题:

我无法弄清楚为什么在执行 doInBackground 或 onPreExecute 后没有调用 AsyncTask 类的 onProgressUpdate 和 onPostExecute。

这是我的 Fragment 类渲染 Youtube 播放列表,我想在其中实现 ProgressBar。

public class YouTubeRecyclerViewFragment extends Fragment 
// the fragment initialization parameter
private static final String ARG_YOUTUBE_PLAYLIST_IDS = "YOUTUBE_PLAYLIST_IDS";
private String[] mPlaylistIds;
private ArrayList<String> mPlaylistTitles;
//private RecyclerView mRecyclerView;
private RecyclerViewPager mRecyclerView;
private PlaylistVideos mPlaylistVideos;
private RecyclerView.LayoutManager mLayoutManager;
private PlaylistCardAdapter mPlaylistCardAdapter;
private YouTube mYouTubeDataApi;


public static YouTubeRecyclerViewFragment newInstance(YouTube youTubeDataApi, String[] playlistIds) 
    YouTubeRecyclerViewFragment fragment = new YouTubeRecyclerViewFragment();
    Bundle args = new Bundle();
    args.putStringArray(ARG_YOUTUBE_PLAYLIST_IDS, playlistIds);
    fragment.setArguments(args);
    fragment.setYouTubeDataApi(youTubeDataApi);
    return fragment;


public YouTubeRecyclerViewFragment() 
    // Required empty public constructor


public void setYouTubeDataApi(YouTube api) 
    mYouTubeDataApi = api;


@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    if (getArguments() != null) 
        mPlaylistIds = getArguments().getStringArray(ARG_YOUTUBE_PLAYLIST_IDS);
    

    // start fetching the playlist titles
    new GetPlaylistTitlesAsyncTask(mYouTubeDataApi) 
        @Override
        protected void onPostExecute(PlaylistListResponse playlistListResponse) 
            // if we didn't receive a response for the playlist titles, then there's nothing to update
            if (playlistListResponse == null)
                return;

            mPlaylistTitles = new ArrayList();
            for (com.google.api.services.youtube.model.Playlist playlist : playlistListResponse.getItems()) 
                mPlaylistTitles.add(playlist.getSnippet().getTitle());
            
        
    .execute(mPlaylistIds);


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    // set the Picasso debug indicator only for debug builds
    Picasso.with(getActivity()).setIndicatorsEnabled(BuildConfig.DEBUG);

    // Inflate the layout for this fragment
    //View rootView = inflater.inflate(R.layout.youtube_recycler_view_fragment, container, false);
    View rootView = inflater.inflate(R.layout.youtube_recycler_view_fragment, container, false);

    //mRecyclerView = (RecyclerView) rootView.findViewById(R.id.youtube_recycler_view);
    mRecyclerView = (RecyclerViewPager) rootView.findViewById(R.id.youtube_recycler_view);

    // use this setting to improve performance if you know that changes
    // in content do not change the layout size of the RecyclerView
    mRecyclerView.setHasFixedSize(true);

    Resources resources = getResources();
    if (resources.getBoolean(R.bool.isTablet)) 
        // use a staggered grid layout if we're on a large screen device
        mLayoutManager = new StaggeredGridLayoutManager(resources.getInteger(R.integer.columns), StaggeredGridLayoutManager.VERTICAL);
     else 
        // use a linear layout on phone devices
        //mLayoutManager = new LinearLayoutManager(getActivity());
        mLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
    

    mRecyclerView.setLayoutManager(mLayoutManager);

    return rootView;


@Override
public void onActivityCreated(Bundle savedInstanceState) 
    super.onActivityCreated(savedInstanceState);

    // if we have a playlist in our retained fragment, use it to populate the UI
    if (mPlaylistVideos != null) 
        // reload the UI with the existing playlist.  No need to fetch it again
        reloadUi(mPlaylistVideos, false);
     else 
        // otherwise create an empty playlist using the first item in the playlist id's array
        mPlaylistVideos = new PlaylistVideos(mPlaylistIds[0]);
        // and reload the UI with the selected playlist and kick off fetching the playlist content
        reloadUi(mPlaylistVideos, true);
    


private void reloadUi(final PlaylistVideos playlistVideos, boolean fetchPlaylist) 
    // initialize the cards adapter
    initCardAdapter(playlistVideos);

    if (fetchPlaylist) 
        // start fetching the selected playlistVideos contents
        new GetPlaylistAsyncTask(mYouTubeDataApi,getContext()) 
            @Override
            public void onPostExecute(Pair<String, List<Video>> result) 
                handleGetPlaylistResult(playlistVideos, result);
            
        .execute(playlistVideos.playlistId, playlistVideos.getNextPageToken());
    


private void initCardAdapter(final PlaylistVideos playlistVideos) 
    // create the adapter with our playlistVideos and a callback to handle when we reached the last item
    mPlaylistCardAdapter = new PlaylistCardAdapter(playlistVideos, new LastItemReachedListener() 
        @Override
        public void onLastItem(int position, String nextPageToken) 
            new GetPlaylistAsyncTask(mYouTubeDataApi,getContext()) 
                @Override
                public void onPostExecute(Pair<String, List<Video>> result) 
                    handleGetPlaylistResult(playlistVideos, result);
                
            .execute(playlistVideos.playlistId, playlistVideos.getNextPageToken());
        
    );
    mRecyclerView.setAdapter(mPlaylistCardAdapter);


private void handleGetPlaylistResult(PlaylistVideos playlistVideos, Pair<String, List<Video>> result) 
    if (result == null) return;
    final int positionStart = playlistVideos.size();
    playlistVideos.setNextPageToken(result.first);
    playlistVideos.addAll(result.second);
    mPlaylistCardAdapter.notifyItemRangeInserted(positionStart, result.second.size());


/**
 * Interface used by the @link PlaylistCardAdapter to inform us that we reached the last item in the list.
 */
public interface LastItemReachedListener 
        void onLastItem(int position, String nextPageToken);
    

下面是用于从提供的播放列表中获取视频的 AsyncTask 类:

public abstract class GetPlaylistAsyncTask extends AsyncTask<String, Void, Pair<String, List<Video>>> 
private static final String TAG = "GetPlaylistAsyncTask";
private static final Long YOUTUBE_PLAYLIST_MAX_RESULTS = 10L;

//see: https://developers.google.com/youtube/v3/docs/playlistItems/list
private static final String YOUTUBE_PLAYLIST_PART = "snippet";
private static final String YOUTUBE_PLAYLIST_FIELDS = "pageInfo,nextPageToken,items(id,snippet(resourceId/videoId))";
//see: https://developers.google.com/youtube/v3/docs/videos/list
private static final String YOUTUBE_VIDEOS_PART = "snippet,contentDetails,statistics"; // video resource properties that the response will include.
private static final String YOUTUBE_VIDEOS_FIELDS = "items(id,snippet(title,description,thumbnails/high),contentDetails/duration,statistics)"; // selector specifying which fields to include in a partial response.

private YouTube mYouTubeDataApi;
Context mContext;
ProgressDialog progressBar;


public GetPlaylistAsyncTask(YouTube api, Context context) 
    mYouTubeDataApi = api;
    mContext = context;
    progressBar = new ProgressDialog(mContext);


@Override
protected Pair<String, List<Video>> doInBackground(String... params) 
    final String playlistId = params[0];
    final String nextPageToken;

    if (params.length == 2) 
        nextPageToken = params[1];
     else 
        nextPageToken = null;
    

    PlaylistItemListResponse playlistItemListResponse;
    try 
        playlistItemListResponse = mYouTubeDataApi.playlistItems()
                .list(YOUTUBE_PLAYLIST_PART)
                .setPlaylistId(playlistId)
                .setPageToken(nextPageToken)
                .setFields(YOUTUBE_PLAYLIST_FIELDS)
                .setMaxResults(YOUTUBE_PLAYLIST_MAX_RESULTS)
                .setKey(ApiKey.YOUTUBE_API_KEY)
                .execute();
     catch (IOException e) 
        e.printStackTrace();
        return null;
    

    if (playlistItemListResponse == null) 
        Log.e(TAG, "Failed to get playlist");
        return null;
    

    List<String> videoIds = new ArrayList();

    // pull out the video id's from the playlist page
    for (PlaylistItem item : playlistItemListResponse.getItems()) 
        videoIds.add(item.getSnippet().getResourceId().getVideoId());
    

    // get details of the videos on this playlist page
    VideoListResponse videoListResponse = null;
    try 
        videoListResponse = mYouTubeDataApi.videos()
                .list(YOUTUBE_VIDEOS_PART)
                .setFields(YOUTUBE_VIDEOS_FIELDS)
                .setKey(ApiKey.YOUTUBE_API_KEY)
                .setId(TextUtils.join(",", videoIds)).execute();
     catch (IOException e) 
        e.printStackTrace();
    

    return new Pair(playlistItemListResponse.getNextPageToken(), videoListResponse.getItems());


@Override
protected void onPreExecute() 
    progressBar = new ProgressDialog(mContext);
    progressBar.setCancelable(true);
    progressBar.setMessage("Processing Request");
    progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressBar.setIndeterminate(true);
    progressBar.show();


@Override
protected void onProgressUpdate(Void... values) 
    progressBar.setMessage("I have found :");


@Override
protected void onPostExecute(Pair<String, List<Video>> stringListPair) 
        progressBar.dismiss();
    

【问题讨论】:

它是否丢失在 doInBackground 某处?你调试过代码吗? 除了显示progressBar没有被终止之外,它没有显示任何错误。 【参考方案1】:

你需要使用监听接口,像这里处理onPostExecute函数:

How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

并更改代码sn-p

 new GetPlaylistAsyncTask(mYouTubeDataApi,getContext()) 
            @Override
            public void onPostExecute(Pair<String, List<Video>> result) 
                handleGetPlaylistResult(playlistVideos, result);
            
        .execute(playlistVideos.playlistId, playlistVideos.getNextPageToken());

作为

 new GetPlaylistAsyncTask(mYouTubeDataApi,getContext(),YouTubeRecyclerViewFragment.this)
          .execute(playlistVideos.playlistId, playlistVideos.getNextPageToken());

    @Override
    public void handleGetPlaylistResult(PlaylistVideos playlistVideos, Pair<String, List<Video>> result) 
        if (result == null) return;
        if (playlistVideos == null)
             playlistVideos = mPlaylistVideos;
        
        final int positionStart = playlistVideos.size();
        playlistVideos.setNextPageToken(result.first);
        playlistVideos.addAll(result.second);
        mPlaylistCardAdapter.notifyItemRangeInserted(positionStart, result.second.size());
    

GetPlaylistAsyncTask.java

 public class GetPlaylistAsyncTask

 private AsyncResponse theListener;

 public GetPlaylistAsyncTask(YouTube api, Context context, YouTubeRecyclerViewFragment frag ) 
    mYouTubeDataApi = api;
    mContext = context;
    theListener = (AsyncResponse)frag;
 

 @Override
       public void onPostExecute(Pair<String, List<Video>> result) 
          progressBar.dismiss();
          theListener.handleGetPlaylistResult(null,result);
      

【讨论】:

确实,它正在关闭progressBar但不显示结果。 您需要使用监听器检查我发送的链接。你的 Async 类应该是这样的(我会更新我的答案)@Rauhayl 谢谢@mismanc。我非常高兴能得到您如此宝贵的支持。我在 YouTubeRecyclerViewFragment 中创建了 AsyncResponse 类并实现了 handleGetPlaylistResult() 方法。但是GetPlaylistAsyncTask类不能识别从onPostExecute方法传入handleGetPlaylistResult()的playlistVideos参数。 你不需要发送playlistVideos参数。在您的片段中,您已经拥有它。 请查看以下课程以获得清晰的视图。 AsyncResponse 类link、GetPlaylistAsyncTask 类link 和YouTubeRecyclerViewFragment 类link

以上是关于Android,AsyncTask 不调用 onProgressUpdate 和 onPostExecute的主要内容,如果未能解决你的问题,请参考以下文章

没有 SD 卡时,ProgressDialog 不显示在 Galaxy S3 上

在上下文不工作的情况下从 AsyncTask onPostExecute 调用 Android Intent

Android AsyncTask 不运行

Android中的AsyncTask是如何执行的

Android 从 AsyncTask 调用 notifyDataSetChanged

未调用 Google 游戏服务 onPeersDisconnected/onP2PDisconnected