Fatal Exception: java.lang.IllegalStateException: android.os.TransactionTooLargeException - android

I get this error at certian times inside my fragment
Fatal Exception: java.lang.IllegalStateException: android.os.TransactionTooLargeException
at com.google.android.youtube.api.jar.client.RemoteEmbeddedPlayer.x(SourceFile:532)
at com.google.android.apps.youtube.api.jar.a.a.w(SourceFile:472)
at com.google.android.youtube.player.internal.h.onTransact(SourceFile:390)
at android.os.Binder.transact(Binder.java:361)
at com.google.android.youtube.player.internal.d$a$a.r(Unknown Source)
at com.google.android.youtube.player.internal.s.h(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerView.e(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerSupportFragment.onSaveInstanceState(Unknown Source)
at com.redeagle07.alahly.youtube.YouTubeFragment.onSaveInstanceState(YouTubeFragment.java:161)
Here's the line that brings up the error
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putString(KEY_VIDEO_ID, mVideoId);
}
And this is how I add the fragment from the MainActivity
final YouTubeFragment fragment = YouTubeFragment.newInstance(list.get(position).getID());
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slideup, R.anim.slideout, R.anim.slideup, R.anim.slideout);
ft.addToBackStack("xyz");
ft.add(android.R.id.content, fragment).commitAllowingStateLoss();
edit1:
The whole YoutubeFragment class
public class YouTubeFragment extends BackYoutubeFragment implements YouTubePlayer.OnInitializedListener {
private static final int RECOVERY_DIALOG_REQUEST = 1;
private static final String KEY_VIDEO_ID = "KEY_VIDEO_ID";
private String mVideoId;
private ShowingAd mListener;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mListener = (ShowingAd) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement DrawerLockout");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* Returns a new instance of this Fragment
*
* #param videoId The ID of the video to play
*/
public static YouTubeFragment newInstance(final String videoId) {
final YouTubeFragment youTubeFragment = new YouTubeFragment();
final Bundle bundle = new Bundle();
bundle.putString(KEY_VIDEO_ID, videoId);
youTubeFragment.setArguments(bundle);
return youTubeFragment;
}
#Override
public String getTagText() {
return null;
}
#Override
public boolean onBackPressed() {
try {
getFragmentManager().popBackStack();
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}catch (NullPointerException e){
return true;
}
return false;
}
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
final Bundle arguments = getArguments();
if (bundle != null && bundle.containsKey(KEY_VIDEO_ID)) {
mVideoId = bundle.getString(KEY_VIDEO_ID);
} else if (arguments != null && arguments.containsKey(KEY_VIDEO_ID)) {
mVideoId = arguments.getString(KEY_VIDEO_ID);
}
initialize("xxxx", this);
}
/**
* Set the video id and initialize the player
* This can be used when including the Fragment in an XML layout
* #param videoId The ID of the video to play
*/
public void setVideoId(final String videoId) {
mVideoId = videoId;
initialize("xxxx", this);
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean restored) {
try {
mListener.showingAds(0);
if (mVideoId != null) {
youTubePlayer.setShowFullscreenButton(false);
if (restored) {
youTubePlayer.play();
youTubePlayer.setFullscreen(true);
} else {
youTubePlayer.loadVideo(mVideoId);
youTubePlayer.setFullscreen(true);
}
}
}catch (NullPointerException| IllegalStateException e){
e.printStackTrace();
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
if (youTubeInitializationResult.isUserRecoverableError()) {
youTubeInitializationResult.getErrorDialog(getActivity(), RECOVERY_DIALOG_REQUEST).show();
} else {
//Handle the failure
Toast.makeText(getActivity(), "FAIL", Toast.LENGTH_LONG).show();
}
}
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putString(KEY_VIDEO_ID, mVideoId);
}
}

Related

YouTube Player API throwing exception

I looked into other threads, but found no solution for this, except it was originally detected for API 21, i.e. Lollipop. While, I am facing this issue in Lollipop as well as post-Lollipop versions.
I am using YouTube Data API, to display the content of the particular channel in my app. And I am successful in getting the response from the API and displaying content in the RecyclerView.
But when I try to load the video in the YouTubeSupportFragment, the app crashes while invoking the cueVideo() of YouTubeSupportFragment with the following exception.
Note: I am using the latest version (1.2.2) of the YouTube API.
Here's the exception thrown by the YouTube Player:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.acme.youtubeplayer, PID: 16757
java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.google.android.youtube.api.service.START }
at android.app.ContextImpl.validateServiceIntent(ContextImpl.java:2101)
at android.app.ContextImpl.bindServiceCommon(ContextImpl.java:2225)
at android.app.ContextImpl.bindService(ContextImpl.java:2203)
at android.content.ContextWrapper.bindService(ContextWrapper.java:560)
at com.google.android.youtube.player.internal.r.e(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerView.a(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerSupportFragment.a(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerSupportFragment.onCreateView(Unknown Source)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2192)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:758)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2363)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2149)
at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2103)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2013)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:710)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:7007)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
Here's my ListFragment.java, where the app crashes:
public class ListFragment extends android.support.v4.app.Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private static final String KEY_TRANSITION_EFFECT = "transition_effect";
private static final int RECOVERY_REQUEST = 1;
private int mCurrentTransitionEffect = JazzyHelper.HELIX;
private JazzyRecyclerViewScrollListener jazzyScrollListener;
YouTubePlayerView youtube_player;
MyPlayerStateChangeListener playerStateChangeListener;
MyPlaybackEventListener playbackEventListener;
YouTubePlayer playerFragment;
JSONObject jObjectAPI;
JSONArray jArrayResponse;
int listSize;
JSONObject jObjectResponse, jObject;
public static final String YOUTUBE_API = "https://www.googleapis.com/youtube/v3/search?key=" + Config.YOUTUBE_API_KEY + "&channelId=" + Config.YOUTUBE_CHANNEL_ID + "&part=snippet,id&order=date&maxResults=20";
//Local Variables
RecyclerView recyclerView;
Button seekToButton;
YouTubePlayerSupportFragment youTubePlayerFragment;
String[] thumbnailVideo;
String[] titleVideo;
String[] descriptionVideo;
String[] idVideo;
int itemLayoutRes = R.layout.item;
boolean isStaggered = false;
private OnFragmentInteractionListener mListener;
private ProgressDialog pDialog;
public ListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment ListFragment.
*/
// TODO: Rename and change types and number of parameters
public static ListFragment newInstance(String param1, String param2) {
ListFragment fragment = new ListFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
// Inflate the layout for this fragment
recyclerView = (RecyclerView) view.findViewById(R.id.rv_video_list);
recyclerView.setLayoutManager(createLayoutManager(itemLayoutRes, isStaggered));
recyclerView.setHasFixedSize(false);
new GetList().execute();
return view;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
private RecyclerView.LayoutManager createLayoutManager(int itemLayoutRes, boolean isStaggered) {
if (itemLayoutRes == R.layout.item) {
return new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
} else {
if (isStaggered) {
return new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
} else {
return new GridLayoutManager(getActivity(), 1);
}
}
}
private void setupJazziness(int effect) {
mCurrentTransitionEffect = effect;
jazzyScrollListener.setTransitionEffect(mCurrentTransitionEffect);
}
private void showMessage(String message) {
Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
}
public final class MyPlaybackEventListener implements YouTubePlayer.PlaybackEventListener {
#Override
public void onPlaying() {
// Called when playback starts, either due to user action or call to play().
showMessage("Playing");
}
#Override
public void onPaused() {
// Called when playback is paused, either due to user action or call to pause().
showMessage("Paused");
}
#Override
public void onStopped() {
// Called when playback stops for a reason other than being paused.
showMessage("Stopped");
}
#Override
public void onBuffering(boolean b) {
// Called when buffering starts or ends.
}
#Override
public void onSeekTo(int i) {
// Called when a jump in playback position occurs, either
// due to user scrubbing or call to seekRelativeMillis() or seekToMillis()
}
}
public final class MyPlayerStateChangeListener implements YouTubePlayer.PlayerStateChangeListener {
#Override
public void onLoading() {
// Called when the youtube_player is loading a video
// At this point, it's not ready to accept commands affecting playback such as play() or pause()
playerFragment.loadVideo(idVideo.toString());
}
#Override
public void onLoaded(String s) {
// Called when a video is done loading.
// Playback methods such as play(), pause() or seekToMillis(int) may be called after this callback.
playerFragment.play();
}
#Override
public void onAdStarted() {
// Called when playback of an advertisement starts.
playerFragment.pause();
}
#Override
public void onVideoStarted() {
// Called when playback of the video starts.
}
#Override
public void onVideoEnded() {
// Called when the video reaches its end.
if (playerFragment.hasNext()) {
playerFragment.next();
}
}
#Override
public void onError(YouTubePlayer.ErrorReason errorReason) {
// Called when an error occurs.
Toast.makeText(getActivity(), "Please check your Internet Connection", Toast.LENGTH_LONG).show();
}
}
public static JSONObject getJSONObjectFromURL(String urlString) throws IOException, JSONException {
HttpURLConnection urlConnection = null;
URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setDoOutput(true);
urlConnection.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
char[] buffer = new char[1024];
String jsonString;
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
jsonString = sb.toString();
System.out.println("JSON: " + jsonString);
return new JSONObject(jsonString);
}
private class GetList extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
pDialog = new ProgressDialog(getActivity());
pDialog.setMessage("Please wait...");
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
try {
jObjectAPI = getJSONObjectFromURL(YOUTUBE_API);
Log.e("response", String.valueOf(jObjectAPI));
jArrayResponse = jObjectAPI.getJSONArray("items");
Log.e("array", String.valueOf(jArrayResponse));
listSize = jArrayResponse.length();
thumbnailVideo = new String[listSize];
titleVideo = new String[listSize];
descriptionVideo = new String[listSize];
idVideo = new String[listSize];
for (int i = 0; i < listSize; i++) {
jObjectResponse = jArrayResponse.getJSONObject(i);
thumbnailVideo[i] = jObjectResponse.getJSONObject("snippet").getJSONObject("thumbnails")
.getJSONObject("default")
.optString("url");
titleVideo[i] = jObjectResponse.getJSONObject("snippet").optString("title");
if (!(jObjectResponse.getJSONObject("snippet").optString("description").equals(""))
&& !(jObjectResponse.getJSONObject("snippet").optString("description").equals(null))
&& (jObjectResponse.getJSONObject("snippet").optString("description").length() > 0)) {
descriptionVideo[i] = jObjectResponse.getJSONObject("snippet").optString("description");
} else {
descriptionVideo[i] = "No Description Found";
}
idVideo[i] = jObjectResponse.getJSONObject("id").optString("videoId");
}
} catch (JSONException e) {
e.printStackTrace();
Log.e("JSON Exception", e.toString());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
/**
* Updating parsed JSON data into ListView
**/
recyclerView.setAdapter(new VideoListAdapter(thumbnailVideo, titleVideo, descriptionVideo, idVideo, itemLayoutRes, getActivity()));
jazzyScrollListener = new JazzyRecyclerViewScrollListener();
recyclerView.setOnScrollListener(jazzyScrollListener);
setupJazziness(R.anim.slide_left_in);
playerStateChangeListener = new MyPlayerStateChangeListener();
playbackEventListener = new MyPlaybackEventListener();
youTubePlayerFragment = new YouTubePlayerSupportFragment();
youTubePlayerFragment.initialize(Config.YOUTUBE_API_KEY, new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
playerFragment = player;
player.setPlayerStateChangeListener(playerStateChangeListener);
player.setPlaybackEventListener(playbackEventListener);
if (!wasRestored) {
player.cueVideos(Arrays.asList(idVideo));
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider arg0, YouTubeInitializationResult errorReason) {
// TODO Auto-generated method stub
if (errorReason.isUserRecoverableError()) {
errorReason.getErrorDialog(getActivity(), RECOVERY_REQUEST).show();
} else {
String error = String.format(getString(R.string.player_error), errorReason.toString());
Toast.makeText(getActivity(), error, Toast.LENGTH_LONG).show();
}
}
});
android.support.v4.app.FragmentManager fmPlayer = getFragmentManager();
FragmentTransaction transaction = fmPlayer.beginTransaction();
transaction.replace(R.id.youtube_player_view, youTubePlayerFragment);
transaction.commit();
}
}
}
Here's my Adapter class:
public class VideoListAdapter extends Adapter<VideoListAdapter.VideoListViewHolder> {
private List<String> thumbnail;
private List<String> title;
private List<String> desc;
private List<String> id;
private int itemLayoutRes;
private static Activity mContext;
public VideoListAdapter(String[] videoThumbnail, String[] videoTitle, String[] videoDesc, String[] videoId, int itemLayoutRes, Activity context) {
this.thumbnail = Arrays.asList(videoThumbnail);
this.title = Arrays.asList(videoTitle);
this.desc = Arrays.asList(videoDesc);
this.id = Arrays.asList(videoId);
this.itemLayoutRes = itemLayoutRes;
this.mContext = context;
}
#Override
public VideoListAdapter.VideoListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view;
view = inflater.inflate(itemLayoutRes, parent, false);
return new VideoListViewHolder(view);
}
#Override
public void onBindViewHolder(final VideoListViewHolder holder, final int position) {
Picasso.with(mContext).load(thumbnail.get(position)).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// loaded bitmap is here (bitmap)
holder.thumbnailVideo.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Toast.makeText(mContext, "Image load failed", Toast.LENGTH_LONG).show();
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
Log.e("thumbnail Adapter", String.valueOf(thumbnail.get(position)));
holder.titleVideo.setText(title.get(position));
holder.descVideo.setText(desc.get(position));
holder.idVideo = id.get(position);
}
#Override
public int getItemCount() {
return title.size();
}
#Override
public int getItemViewType(int position) {
// return isStaggered ? position % 2 : 0;
return position;
}
public static class VideoListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
final TextView titleVideo, descVideo;
final YouTubeThumbnailView thumbnailVideo;
String idVideo;
public VideoListViewHolder(View view) {
super(view);
thumbnailVideo = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail_video);
titleVideo = (TextView) view.findViewById(R.id.title_video);
descVideo = (TextView) view.findViewById(R.id.desc_video);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(mContext, YouTubeBaseActivity.class);
//Intent intent = YouTubeStandalonePlayer.createVideoIntent((Activity) v.getContext(), Config.YOUTUBE_API_KEY, idVideo);
v.getContext().startActivity(intent);
}
}
}
Finally I got rid of this issue. I replaced the YouTubeSupportFragment with YouTubeBaseActivity and used YouTubePlayerView to play the video.
In other words, I used an Activity extending YouTubeBaseActivity to play the video instead of a Fragment.
Hope it helps someone getting the issue.

get Data to Fragment from Activity

I want to get data from activity but I keep getting error this error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference.
TrafficActivity.class (Activity)
public class TrafficActivity extends AppCompatActivity {
public static final String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_traffic);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_traffic);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(TrafficActivity.this, IpuclariSayfasi.class));
}
});
if (savedInstanceState == null)
{
getFragmentManager().beginTransaction()
.add(R.id.container, new PdfRendererBasicFragment(), FRAGMENT_PDF_RENDERER_BASIC)
.commit();
}
}}
PdfRendererBasicFragment.class(Fragment)
public class PdfRendererBasicFragment extends Fragment implements
View.OnClickListener
{
private static final String O_ANKI_SAYFA_DURUMU = "guncel_sayfa_index";
private ParcelFileDescriptor mFileDescriptor;
private PdfRenderer mPdfRenderer;
private PdfRenderer.Page mGuncelSayfa;
private ImageView mImageView;
private ImageButton mOncekiButon;
private ImageButton mSonrakiButon;
public static String FILENAME;
public PdfRendererBasicFragment()
{
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_pdf_renderer_basic, container, false);
}
#Override
public void onClick(View view)
{
switch (view.getId()) {
case R.id.onceki: {
//onceki sayfaya geç
showPage(mGuncelSayfa.getIndex() - 1);
break;
}
case R.id.sonraki: {
// sonraki sayfaya geç
showPage(mGuncelSayfa.getIndex() + 1);
break;
}
}
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mImageView = (ImageView) view.findViewById(R.id.pdf_goruntusu);
mOncekiButon = (ImageButton) view.findViewById(R.id.onceki);
mSonrakiButon = (ImageButton) view.findViewById(R.id.sonraki);
mOncekiButon.setOnClickListener(this);
mSonrakiButon.setOnClickListener(this);
int index = 0;
if (null != savedInstanceState) {
index = savedInstanceState.getInt(O_ANKI_SAYFA_DURUMU, 0);
}
showPage(index);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
openRenderer(activity);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(activity, "Beklenmedik hata: " + e.getMessage(), Toast.LENGTH_SHORT).show();
activity.finish();
}
}
#Override
public void onDetach() {
try {
closeRenderer();
} catch (IOException e) {
e.printStackTrace();
}
super.onDetach();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (null != mGuncelSayfa) {
outState.putInt(O_ANKI_SAYFA_DURUMU, mGuncelSayfa.getIndex());
}
}
private void openRenderer(Context context) throws IOException
{
// bu ornekte, asset klasöründeki PDF'i okuyoruz.
FILENAME= getArguments().getString("file_name");
File file = new File(context.getCacheDir(), FILENAME);
if (!file.exists())
{
InputStream asset = context.getAssets().open(FILENAME);
FileOutputStream output = new FileOutputStream(file);
final byte[] buffer = new byte[1024];
int size;
while ((size = asset.read(buffer)) != -1) {
output.write(buffer, 0, size);
}
asset.close();
output.close();
}
mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
mPdfRenderer = new PdfRenderer(mFileDescriptor);
}
private void closeRenderer() throws IOException {
if (null != mGuncelSayfa) {
mGuncelSayfa.close();
}
mPdfRenderer.close();
mFileDescriptor.close();
}
private void showPage(int index) {
if (mPdfRenderer.getPageCount() <= index) {
return;
}
if (null != mGuncelSayfa) {
mGuncelSayfa.close();
}
mGuncelSayfa = mPdfRenderer.openPage(index);
// ÖNEMLİ: Hedef bitmap ARGB olmalı, RGB olmamalı.
Bitmap bitmap = Bitmap.createBitmap(mGuncelSayfa.getWidth(), mGuncelSayfa.getHeight(),
Bitmap.Config.ARGB_8888);
mGuncelSayfa.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
mImageView.setImageBitmap(bitmap);
sayfayıGuncelle();
}
private void sayfayıGuncelle() {
int index = mGuncelSayfa.getIndex();
int pageCount = mPdfRenderer.getPageCount();
mOncekiButon.setEnabled(0 != index);
mSonrakiButon.setEnabled(index + 1 < pageCount);
getActivity().setTitle(getString(R.string.app_name_with_index, index + 1, pageCount));
}
public int sayfaSayisiniGetir()
{
return mPdfRenderer.getPageCount();
}
You are setting the argument on the Fragment but calling the Activity
#Override
public void onClick(View view) {
Bundle bundle = new Bundle();
bundle.putString("file_name", "sample3.pdf");
PdfRendererBasicFragment ff=new PdfRendererBasicFragment();
ff.setArguments(bundle);
startActivity(new Intent(IpuclariSayfasi.this,TrafficActivity.class));
}
And when you really commit the Fragment, you creating a new instance, without any argument:
if (savedInstanceState == null)
{
getFragmentManager().beginTransaction()
.add(R.id.container, new PdfRendererBasicFragment(), FRAGMENT_PDF_RENDERER_BASIC)
.commit();
}
Make the first implementation on the real Fragment call, like this:
if (savedInstanceState == null) {
Bundle bundle = new Bundle();
bundle.putString("file_name", "sample3.pdf");
PdfRendererBasicFragment ff=new PdfRendererBasicFragment();
ff.setArguments(bundle);
getFragmentManager().beginTransaction()
.add(R.id.container, ff, FRAGMENT_PDF_RENDERER_BASIC)
.commit();
}
You have the problem here
FILENAME= getArguments().getString("file_name");
getArguments() is null since you are setting arguments for
PdfRendererBasicFragment ff=new PdfRendererBasicFragment();
ff.setArguments(bundle);
but then you're creating a new Fragment in TrafficActivity.class
.add(R.id.container, new PdfRendererBasicFragment(), FRAGMENT_PDF_RENDERER_BASIC)
and this is the one you're using, but this one does not have any arguments in it

java.lang.IllegalStateException: YouTubeServiceEntity not initialized error when using YouTubePlayerApi

I'm using YouTubePlayerAPI and YouTubePlayerSupportFragment in my app and I'm getting the following error, but I couldn't find out what is causing it. I've been looking for information but I haven't found anything useful.
java.lang.IllegalStateException: YouTubeServiceEntity not initialized
at android.os.Parcel.readException(Parcel.java:1433)
at android.os.Parcel.readException(Parcel.java:1379)
at com.google.android.youtube.player.internal.l$a$a.a(Unknown Source)
at com.google.android.youtube.player.internal.o.a(Unknown Source)
at com.google.android.youtube.player.internal.ad.a(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerView.a(Unknown Source)
at com.google.android.youtube.player.YouTubePlayerView$1.a(Unknown Source)
at com.google.android.youtube.player.internal.r.g(Unknown Source)
at com.google.android.youtube.player.internal.r$c.a(Unknown Source)
at com.google.android.youtube.player.internal.r$b.a(Unknown Source)
at com.google.android.youtube.player.internal.r$a.handleMessage(Unknown Source)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5041)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
In the stackstrace there isn't any line number pointing to any of my classes or activities.
Any idea of it?
Thanks!
EDIT
My custom YoutubePlayerFragment Class: YouTubeVideoPlayerFragment.java
public class YouTubeVideoPlayerFragment extends YouTubePlayerSupportFragment {
private static final String ARG_URL = "url";
// ===========================================================
// Constructors
// ===========================================================
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public YouTubeVideoPlayerFragment() {
}
/**
* Factory method to generate a new instance of the fragment given a video URL.
*
* #param url The video url this fragment represents
* #return A new instance of this fragment with itemId extras
*/
public static YouTubeVideoPlayerFragment newInstance(String url) {
final YouTubeVideoPlayerFragment mFragment = new YouTubeVideoPlayerFragment();
// Set up extras
final Bundle args = new Bundle();
args.putString(ARG_URL, url);
mFragment.setArguments(args);
// Initialize YouTubePlayer
mFragment.init();
return mFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private void init(){
initialize(Constants.API_KEY, new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) {
if (!wasRestored) {
youTubePlayer.cueVideo(getArguments().getString(ARG_URL));
youTubePlayer.setShowFullscreenButton(false);
}
}
}
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#color/black" >
<!-- For YoutubeFragment -->
<FrameLayout
android:id="#+id/youtube_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
calling method:
// Create a new instance of YouTubeVideoPlayerFragment providing video id
// and place it in the corresponding FrameLayout
final YouTubeVideoPlayerFragment youTubeVideoPlayerFragment = YouTubeVideoPlayerFragment.newInstance(VIDEO_ID);
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.youtube_fragment, youTubeVideoPlayerFragment);
ft.commit();
EDIT
I've found out the origin of that error. This is the scenario:
The activity starts. In onCreate() it instantiates a new YouTubeVideoPlayerFragment and initializes YouTube object (which starts the YouTubeServiceEntity internally) in its newInstance() method. Then the YouTube fragment that was instantiated before, is attached with FragmentManager to the corresponding FrameLayout while video is loading.
Here is the issue: If user exits the activity before video had been loaded, the exception is thrown.
So if user want to exit from the activity in that case, what should I do and how? I don't really know what to do!
Once again, do NOT use fragment constructors or factory methods to work with lifecycle or context bound entities. Simply put, such entities can only be used after super.onCreate(...) has been called.
The question now is, when to call the init method?
Here's what YouTubePlayerFragment documentation says:
The YouTubePlayer associated with this fragment will be released whenever its onDestroyView() method is called. You will therefore have to re-call initialize(String, YouTubePlayer.OnInitializedListener) whenever the activity associated with this fragment is recreated, even if the fragment instance is retained across activity re-creation by setting setRetainInstance(boolean).
You may be tempted to put init() in onActivityCreated but that's too late, since onStart was already called and layout already performed.
Counterpart to onDestroyView is onViewCreated and that's the perfect candidate.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
init();
}
As suggested call setRetainInstance(true) in the fragment's constructor. When the activity is recreated the fragment will not be recreated, only its UI will go through lifecycle events.
I see the same error reported from a Huawei cellphone.
I see an explanation here:
https://github.com/youtube/yt-android-player/issues/23
Not sure if there is a way to catch the exception in our code.
The problem is the initialization of the Youtube fragment. YouTubePlayerSupportFragment has to be extended in a class of yours and overrides some methods. You have to control the screen orientation and the onSaveInstanceState.
public class YouTubePlayerFragment extends YouTubePlayerSupportFragment {
private YouTubePlayer mPlayer;
public static YouTubePlayerFragment newInstance() {
return new YouTubePlayerFragment();
}
#Override public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setRetainInstance(true);
}
#Override
public void initialize(String s, YouTubePlayer.OnInitializedListener onInitializedListener) {
super.initialize(s, new YouTubePlayer.OnInitializedListener() {
#Override public void onInitializationSuccess(YouTubePlayer.Provider provider,
YouTubePlayer youTubePlayer, boolean b) {
mPlayer = youTubePlayer;
onInitializedListener.onInitializationSuccess(provider, youTubePlayer, b);
}
#Override public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult youTubeInitializationResult) {
onInitializedListener.onInitializationFailure(provider, youTubeInitializationResult);
}
});
}
#Override public void onDestroyView() {
if (mPlayer != null) {
mPlayer.release();
}
super.onDestroyView();
}
public YouTubePlayer getPlayer() {
return mPlayer;
}
}
YoutubeFragment.class
public class YoutubeFragment extends Fragment {
private static final String EXTRA_PLAYED_VIDEO = "EXTRA_PLAYED_VIDEO";
private static final String EXTRA_IS_PLAYING = "EXTRA_IS_PLAYING";
private static final String YOUTUBE_FRAGMENT = "YOUTUBE_FRAGMENT";
private static final String EXTRA_YOUTUBE_ID = "EXTRA_YOUTUBE_ID";
private RelativeLayout youtubeLayoutContainer;
private String youtubeId;
private int playedVideo;
private boolean isPlaying;
YouTubePlayer.OnInitializedListener onInitializedListener =
new YouTubePlayer.OnInitializedListener() {
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player,
boolean wasRestored) {
if (!wasRestored) {
setYouTubePlayer(player);
}
}
#Override public void onInitializationFailure(YouTubePlayer.Provider provider,
YouTubeInitializationResult error) {
}
};
public static YoutubeFragment newInstance(String youtubeId) {
YoutubeFragment youtubeElements = new YoutubeFragment();
Bundle bundle = new Bundle();
bundle.putString(EXTRA_YOUTUBE_ID, youtubeId);
youtubeElements.setArguments(bundle);
return youtubeElements;
}
#Override public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Nullable #Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View mView = inflater.inflate(R.layout.view_youtube_elements_item, container, false);
initViews(mView);
initYoutubeFragment();
return mView;
}
private void initViews(View view) {
youtubeLayoutContainer = (RelativeLayout) view.findViewById(R.id.youtubeLayoutContainer);
youtubeLayoutContainer.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#TargetApi(Build.VERSION_CODES.JELLY_BEAN) #Override public void onGlobalLayout() {
FrameLayout.LayoutParams lp =
new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.MATCH_PARENT);
youtubeLayoutContainer.setLayoutParams(lp);
if (AndroidSdkVersion.hasJellyBean16()) {
youtubeLayoutContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
}
private void initYoutubeFragment() {
try {
YouTubePlayerFragment youTubePlayerFragment2 = YouTubePlayerFragment.newInstance();
youTubePlayerFragment2.initialize(BuildConfig.YOUTUBE_DEVELOPER_KEY, onInitializedListener);
if (this.getActivity() != null && !this.getActivity().isFinishing()) {
getChildFragmentManager().beginTransaction()
.replace(R.id.youtubePlayerFragmentContent, youTubePlayerFragment2, YOUTUBE_FRAGMENT)
.commitAllowingStateLoss();
}
} catch (Exception ignored) {
}
}
public void setYouTubePlayer(final YouTubePlayer player) {
try {
if (player == null) {
return;
}
player.setShowFullscreenButton(true);
player.setPlayerStyle(YouTubePlayer.PlayerStyle.DEFAULT);
if (playedVideo >= 0) {
if (playedVideo == 0 || isPlaying) {
player.loadVideo(youtubeId, playedVideo);
} else {
player.cueVideo(youtubeId, playedVideo);
}
}
} catch (Exception ignored) {
}
}
#Override public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState != null) {
playedVideo = savedInstanceState.getInt(EXTRA_PLAYED_VIDEO);
isPlaying = savedInstanceState.getBoolean(EXTRA_IS_PLAYING);
}
}
#Override public void onSaveInstanceState(Bundle outState) {
try {
YouTubePlayerFragment youTubePlayerSupportFragment =
(YouTubePlayerFragment) getChildFragmentManager().findFragmentByTag(YOUTUBE_FRAGMENT);
YouTubePlayer mPlayer = youTubePlayerSupportFragment.getPlayer();
if (mPlayer != null) {
outState.putInt(EXTRA_PLAYED_VIDEO, mPlayer.getCurrentTimeMillis());
outState.putBoolean(EXTRA_IS_PLAYING, mPlayer.isPlaying());
}
} catch (Exception ignored) {
}
super.onSaveInstanceState(outState);
}
}
Activity containing Youtube Fragment
public class YoutubeContentDataActivity extends BaseActivity {
private static final String EXTRA_YOUTUBE_VIDEO_ID = "EXTRA_YOUTUBE_VIDEO_ID";
private static final String TAG_RETAINED_FRAGMENT = "TAG_RETAINED_FRAGMENT";
public static void open(Context context, String videoId) {
Intent intent = new Intent(context, YoutubeContentDataActivity.class);
intent.putExtra(EXTRA_YOUTUBE_VIDEO_ID, videoId);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_youtube_main_container_layout);
FragmentManager fm = getSupportFragmentManager();
YoutubeFragment youtubeElementsFragment =
(YoutubeFragment) fm.findFragmentByTag(TAG_RETAINED_FRAGMENT);
// create the fragment and data the first time
if (youtubeElementsFragment == null) {
String videoId = getIntent().getStringExtra(EXTRA_YOUTUBE_VIDEO_ID);
// videoId = "17uHCHfgs60";//"ikO91fQBsTQ";
youtubeElementsFragment = YoutubeFragment.newInstance(videoId);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.youtube_main_container, youtubeElementsFragment, TAG_RETAINED_FRAGMENT)
.commit();
}
}
#Override public void onPause() {
super.onPause();
if (isFinishing()) {
FragmentManager fm = getSupportFragmentManager();
YoutubeFragment youtubeElementsFragment =
(YoutubeFragment) fm.findFragmentByTag(TAG_RETAINED_FRAGMENT);
fm.beginTransaction().remove(youtubeElementsFragment).commit();
}
}
}
I could fix this error by using a ProgressDialog to wait until the player is loaded.

In which case getFragmentManager() return null?

Problem : getFragmentManager() return null randomly.
Case: I have one activity with tab. On each tab press I'm replacing the content container with fragment. In case of two fragment I'm doing network hit to fetch data from a server. For that I have written the following code:
public class FetchMessagesyFragmentTask extends Fragment {
private static final String TAG_EXTRA = "tab_extra";
private static final String TAG = "Test";
private String mData;
public static final FetchMessagesyFragmentTask newInstance(String data) {
FetchMessagesyFragmentTask fragment = new FetchMessagesyFragmentTask();
Bundle bundle = new Bundle();
bundle.putString(TAG_EXTRA, data);
fragment.setArguments(bundle);
return fragment;
}
public static interface TaskCallbacks {
void onPreExecute();
void onCancelled();
void onPostExecute(MessageResponse response);
}
private TaskCallbacks mCallbacks;
private FetchMessage mTask;
private boolean mRunning;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(getTargetFragment() instanceof TaskCallbacks)) {
throw new IllegalStateException(
"Target fragment must implement the TaskCallbacks interface.");
}
mCallbacks = (TaskCallbacks) getTargetFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mData = getArguments().getString(TAG_EXTRA);
}
#Override
public void onDestroy() {
super.onDestroy();
cancel();
}
public void execute(String data) {
if (!mRunning) {
mTask = new FetchMessage();
mTask.execute(data);
mRunning = true;
}
}
public void cancel() {
if (mRunning) {
mTask.cancel(false);
mTask = null;
mRunning = false;
}
}
public boolean isRunning() {
return mRunning;
}
private class FetchMessage extends AsyncTask<String, Void, MessageResponse> {
private ProgressDialogFragment progressDialog;
#Override
protected void onPreExecute() {
progressDialog = new ProgressDialogFragment.Builder().setMessage(
"Please wait...").build();
progressDialog.show(((Fragment) mCallbacks).getFragmentManager(),
"task_progress");
mCallbacks.onPreExecute();
mRunning = true;
}
#Override
protected MessageResponse doInBackground(String... params) {
//Doing network hit here and returning value.
return value;
}
#Override
protected void onCancelled() {
mCallbacks.onCancelled();
mRunning = false;
}
#Override
protected void onPostExecute(MessageResponse response) {
if (mCallbacks != null) {
FragmentManager manager = ((Fragment) mCallbacks)
.getFragmentManager();
//XXXXXXXX GETTING MANAGER AS NULL HERE SOMETIME XXXXXXXXXXXXXX
progressDialog.dismiss(manager);
if (response != null) {
if (Integer.parseInt(response.getResponseCode()) == NetworkConstant.SUCCESS
&& response.getChatMessage() != null) {
saveDataToDb(response);
}
}
mCallbacks.onPostExecute(response);
mRunning = false;
}
}
private void saveDataToDb(MessageResponse response) {
//SaveToDB
}
}
}
I'm following this url to handle network hit on orientation change. I have commented the line where I'm getting the issue.
Note
This code work fine in normal situation but crash when I switch tabs very fast.

Fragment able to start task which is not interrupted during configuration changes

Sorry for my English
This is not question. I post it because this is may be helpful for someone. My solution based on the solution which was placed here several months ago, but later its author removed it. But there were several bugs in his solution, and I tried to fix them.
My solution works fine even if you'll open another app while there is a long-executed task executed in your app, then change screen orientation in another app, and return to your app after task will be finished.
If you'll find a bug in my solution, please let me know.
Have a look:
public interface AbleToStartTask {
void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task);
void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task, Integer titleId);
}
public interface TaskResultReceiver {
void onTaskResult(int requestCode, int resultCode, Serializable result);
}
public abstract class TaskNotBeInterruptedDuringConfigurationChange extends AsyncTask<Void, Void, Serializable> {
private TaskFragment fragment;
final void setFragment(TaskFragment fragment) {
this.fragment = fragment;
}
#Override
protected final void onPostExecute(Serializable result) {
if (fragment != null) {
fragment.onTaskFinished(result);
}
}
}
public class TaskFragment extends android.support.v4.app.DialogFragment {
public static final Integer NO_TITLE_ID = null;
private boolean isNeedToReturnResult = false;
private boolean isResultReturned = false;
private TaskNotBeInterruptedDuringConfigurationChange task;
private int resultCode = Activity.RESULT_CANCELED;
private Serializable result = null;
private Integer titleId;
public void setTask(TaskNotBeInterruptedDuringConfigurationChange task) {
task.setFragment(this);
this.task = task;
}
public void setTitle(Integer titleId) {
this.titleId = titleId;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
if (savedInstanceState == null && task != null) {
task.execute();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
initDialog();
return inflater.inflate(R.layout.fragment_task, container);
}
private void initDialog() {
if (titleId == NO_TITLE_ID) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
} else {
getDialog().setTitle(titleId);
}
getDialog().setCanceledOnTouchOutside(false);
}
#Override
public void onDestroyView() {
if ((getDialog() != null) && getRetainInstance()) {
getDialog().setDismissMessage(null);
}
super.onDestroyView();
}
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (task != null) {
task.cancel(false);
}
tryReturnResult();
}
private void tryReturnResult() {
task = null;
if (isResultReturned) {
return;
}
if (getTargetFragment() != null) {
returnResult();
}
}
private void returnResult() {
isResultReturned = true;
FragmentAbleToStartTask ableToStartTask = (FragmentAbleToStartTask) getTargetFragment();
if (ableToStartTask.isAbleToReceiveResult()) {
ableToStartTask.onResult(FragmentAbleToStartTask.TASK_FRAGMENT_TARGET, resultCode, result);
isNeedToReturnResult = false;
finishFragment();
} else {
isNeedToReturnResult = true;
}
}
private void finishFragment() {
if (isResumed()) {
dismiss();
}
}
#Override
public void onResume() {
super.onResume();
if (task == null) {
dismiss();
}
}
public void onTaskFinished(Serializable result) {
setResult(Activity.RESULT_OK, result);
tryReturnResult();
}
private void setResult(int resultCode, Serializable result) {
this.resultCode = resultCode;
this.result = result;
}
public void getResultIfItReturnedDuringPause() {
if (isNeedToReturnResult) {
returnResult();
}
}
}
public abstract class FragmentAbleToStartTask extends android.support.v4.app.Fragment
implements AbleToStartTask, TaskResultReceiver {
public static final int TASK_FRAGMENT_TARGET = 123;
protected static final String TAG_TASK_FRAGMENT = FragmentAbleToStartTask.class.getName() + "TAG_TASK_FRAGMENT";
private static final String KEY_TASK_REQUEST_CODE = "KEY_TASK_REQUEST_CODE";
private FragmentManager fragmentManager;
private int taskRequestCode;
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_TASK_REQUEST_CODE, taskRequestCode);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
restoreState(savedInstanceState);
}
fragmentManager = getFragmentManager();
TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
taskFragment.setTargetFragment(this, TASK_FRAGMENT_TARGET);
}
}
private void restoreState(Bundle savedInstanceState) {
taskRequestCode = savedInstanceState.getInt(KEY_TASK_REQUEST_CODE);
}
private TaskFragment getTaskFragment() {
return (TaskFragment) fragmentManager.findFragmentByTag(TAG_TASK_FRAGMENT);
}
public void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task) {
startTask(requestCode, task, TaskFragment.NO_TITLE_ID);
}
public void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task, Integer title) {
this.taskRequestCode = requestCode;
TaskFragment taskFragment = new TaskFragment();
taskFragment.setTitle(title);
taskFragment.setTask(task);
taskFragment.setTargetFragment(this, TASK_FRAGMENT_TARGET);
startFragment(taskFragment);
}
private void startFragment(TaskFragment taskFragment) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment previousTaskFragment = fragmentManager.findFragmentByTag(TAG_TASK_FRAGMENT);
if (previousTaskFragment != null) {
transaction.remove(previousTaskFragment);
}
transaction.add(taskFragment, TAG_TASK_FRAGMENT);
transaction.commit();
}
public final void onResult(int requestCode, int resultCode, Serializable result) {
if ((requestCode == TASK_FRAGMENT_TARGET)) {
onTaskResult(this.taskRequestCode, resultCode, result);
}
}
public abstract void onTaskResult(int requestCode, int resultCode, Serializable result);
public boolean isAbleToReceiveResult() {
return isResumed();
}
#Override
public void onResume() {
super.onResume();
TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
taskFragment.getResultIfItReturnedDuringPause();
}
}
}
So each inheritor of FragmentAbleToStartTask must implement onTaskResult(requestCode, resultCode, result). In onTaskResult() - requestCode is value that was passed to startTask(requestCode, ...). And note, that this fragment is able to execute only one task at the same time.
Example of TaskNotBeInterruptedDuringConfigurationChange's subclass:
public class SomeLongTask extends TaskNotBeInterruptedDuringConfigurationChange {
private final Context context;
private final Worker worker;
public SomeLongTask (Worker worker, Context context) {
this.worker= worker;
this.context = context;
}
#Override
protected Serializable doInBackground(Void... voids) {
return (Serializable) worker.work(context);
}
}
And example of FragmentAbleToStartTask's subclass:
public class NameListFragment extends FragmentAbleToStartTask {
private static final int TASK_REQUEST_CODE_RECEIVING_NAMES = 461;
private static final String KEY_PATTERN = "KEY_PATTERN";
private static final String KEY_NAMES = "KEY_NAMES";
private List<String> names;
private ListView listView;
public static Fragment newInstance(String patternToSearchNames) {
Fragment fragment = new NameListFragment();
Bundle args = new Bundle();
args.putString(KEY_PATTERN, patternToSearchNames);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.example_list_fragment, null);
listView = (ListView) root.findViewById(R.id.listView);
return root;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState == null) {
startTaskReceivingNames();
} else {
restoreState(savedInstanceState);
}
}
// !!! Key Point
private void startTaskReceivingNames() {
String pattern = getArguments().getString(KEY_PATTERN);
TaskNotBeInterruptedDuringConfigurationChange task = new NamesReceiverTask(getActivity(), pattern);
startTask(TASK_REQUEST_CODE_RECEIVING_NAMES, task);
}
private void restoreState(Bundle savedInstanceState) {
names = (List<String>) savedInstanceState.getString(KEY_NAMES);
if (names != null) {
initList();
}
}
private void initList() {
setEmptyListView();
ArrayList<String> adapter = new ArrayList<String>(getActivity(), android.R.layout.simple_list_item_1, names);
listView.setAdapter(adapter);
}
private void setEmptyListView() {
View emptyListView = getView().findViewById(R.id.emptyListView);
listView.setEmptyView(emptyListView);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(KEY_NAMES, (Serializable) names);
}
// !!! Key Point
#Override
public void onTaskResult(int requestCode, int resultCode, Serializable result) {
if (requestCode == TASK_REQUEST_CODE_RECEIVING_NAMES) {
onReceivingNamesFinished(resultCode, result);
}
}
private void onReceivingNamesFinished(int resultCode, Serializable result) {
if (resultCode != Activity.RESULT_OK) {
getActivity().finish();
return;
}
this.names = (List<String>) result;
initList();
}
}

Categories

Resources