current I'm facing a problem which I cannot solve, I have a controller, a fragment, and an Activity, the problem is, I need the application context inside the controller, so I created an instance of the controller from the Fragment, and passed the appContext as an argument in its constructor, but an exception is thrown which is class cast exception in function getReligions() inside my controller at the line where I have a call back, any ideas how to solve this?
Here is my code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
controller = new Controller(getActivity().getApplicationContext());
imageUploadHandler = new ImageHandler(getApplicationContext());
rootView = inflater.inflate(R.layout.setup_edit_profile, container, false);
}
public void getReligions() {
if (religions != null) {
religionSpinner();
return;
}
controller.getReligions();
}
In the controller class
public void getReligions(){
JSONObject params = new JSONObject();
RequestQueue queue = Volley.newRequestQueue(context);
String url = "https://www.doyousonder.com/api/1.0.0/religion";
queue.add(new JsonObjectRequest(com.android.volley.Request.Method.GET, url, params,
new Response.Listener<JSONObject>() {
public void onResponse(JSONObject response) {
((GeneralCallBack)context).VolleyResponse(response,"Religions");
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Authorization", orientation_adj.getContext().getResources().getString(R.string.bearer));
return params;
}
});
}
myLogCat:
java.lang.ClassCastException:
com.eseed.sonder.utils.orientation_adj cannot be cast to
com.eseed.sonder.utils.GeneralCallBack
at com.eseed.sonder.utils.Controller$61.onResponse(Controller.java:904)
at com.eseed.sonder.utils.Controller$61.onResponse(Controller.java:902)
at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:65)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Here're my callbacks
#Override
public void VolleyResponse(String data) {
}
#Override
public void VolleyResponse(JSONObject response) {
}
#Override
public void VolleyResponse(JSONObject response, String data) {
Gson gson = new Gson();
if(data.equals("Religions")){
try {
Type t = new TypeToken<ReligionData[]>() {}.getType();
religions = gson.fromJson(String.valueOf(response.getJSONObject("data").getJSONArray("list_of_religions")), t);
religion_names = new String[religions.length + 1];
religion_names[0] = "Select";
for (int i = 0; i < religions.length; i++) {
religion_names[i + 1] = (religions[i].religion_name);
}
religionSpinner();
} catch (JSONException e) {
e.printStackTrace();
}
}else if(data.equals("Nationalities")){
try {
Type t = new TypeToken<NationalityData[]>() {
}.getType();
nationalities = gson.fromJson(String.valueOf(response.getJSONObject("data").getJSONArray("list_of_nationalities")), t);
nationality_names = new String[nationalities.length + 1];
nationality_names[0] = "Select";
for (int i = 0; i < nationalities.length; i++) {
nationality_names[i + 1] = (nationalities[i].nationality_name);
}
nationalitySpinner();
loadingIcon.hide();
} catch (JSONException e) {
System.out.println(e.getMessage());
}
}
}
`public class orientation_adj extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
mContext = this;
// register to be informed of activities starting up
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
#Override
public void onActivityCreated(Activity activity,
Bundle savedInstanceState) {
// new activity created; force its orientation to portrait
activity.setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
});
}
public static Context getContext(){
return mContext;
}
}
Your problem is here
class orientation_adj extends Application
And here
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
controller = new Controller(getActivity().getApplicationContext());
Your Application class isn't the context that implemented the interface, I assume the Activity is
In that case, you only need
controller = new Controller(getActivity());
After that, set up some additional log statements and breakpoints to debug the callback code better
Related
I have multiple instances of the same CustomView inside one fragment.
I implemented savedInstance for this CustomView but the problem is since there are multiple instances of this CustomView, savedInstance of the last one, overrides them all.
for example, if there are 3 instances of this CustomView which has a recyclerview inside, If I scroll the last one, it applies to them all. because i'm using key value pairs and the key is the same for all of them. (I can change the key to differ for each one but I think there is a better way)
Here is the code for savedInstance saving and restoring inside my CustomView:
#Nullable
#Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(SavedInstanceKey.SUPERSTATE.name(), super.onSaveInstanceState());
bundle.putParcelable(SavedInstanceKey.RECYCLERVIEW.name(), recyclerView.getLayoutManager().onSaveInstanceState()); // ... save stuff
return bundle;
}
#Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) // implicit null check
{
Bundle bundle = (Bundle) state;
this.recyclerView.getLayoutManager().onRestoreInstanceState(bundle.getParcelable(SavedInstanceKey.RECYCLERVIEW.name())); // ... load stuff
state = bundle.getParcelable(SavedInstanceKey.SUPERSTATE.name());
}
super.onRestoreInstanceState(state);
}
and here is my fragment's OnCreateView:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_artist, container, false);
final GridListView gv_new = view.findViewById(R.id.gridlist_new_songs);
final GridListView gv_best = view.findViewById(R.id.gridlist_best);
final GridListView gv_singles = view.findViewById(R.id.gridlist_singles);
final GridListView gv_feats = view.findViewById(R.id.gridlist_feats);
final RecyclerView rc_albums = view.findViewById(R.id.rcview_album);
if(!alreadyInitialized) {
alreadyInitialized = true;
apiService = new ApiService(getContext());
try {
artistID = getArguments().getString(KeyIntent.ARTIST.name());
} catch (Exception e) {
Log.e(TAG, "onCreateView: Artist Fragment doesnt have args.\t", e);
}
apiService.getArtist(artistID, new ApiService.OnArtistReceived() {
#Override
public void onSuccess(Artist artist) {
ArtistFragment.this.artist=artist;
setArtistToViews(artist, view);
}
#Override
public void onFail() {
Toast.makeText(getContext(), "Error on receiving artist.", Toast.LENGTH_LONG).show();
}
});
apiService.getNewSongs(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.newSongs=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_new.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
Toast.makeText(getContext(), "Error on receiving artist.", Toast.LENGTH_LONG).show();
}
});
apiService.getBestSongs(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.bestSongs=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_best.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
Toast.makeText(getContext(), "Error on receiving artist.", Toast.LENGTH_LONG).show();
}
});
apiService.getSingleSongs(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.singleSongs=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_singles.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
}
});
apiService.getFeats(artistID, new ApiService.OnSongsReceived() {
#Override
public void onSuccess(List<Song> songs) {
ArtistFragment.this.feats=songs;
List<GridListable> gridListables = new ArrayList<>();
gridListables.addAll(songs);
gv_feats.load(gridListables, 1);
}
#Override
public void onFail(ApiService.ApiResponse response) {
}
});
apiService.getAlbums(artistID, new ApiService.OnAlbumsReceived() {
#Override
public void onSuccess(List<Album> albums) {
ArtistFragment.this.albums=albums;
List<Projective> projectives = new ArrayList<>();
projectives.addAll(albums);
rc_albums.setAdapter(new AlbumAdapter(getContext(), projectives));
rc_albums.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, true));
}
#Override
public void onFail(ApiService.ApiResponse response) {
Toast.makeText(getContext(), "Loading albums failed.", Toast.LENGTH_SHORT).show();
}
});
}else {
Log.i(TAG, "onCreateView: Fragment already initialized, restoring from existing artist");
setArtistToViews(artist,view);
gv_new.load(new ArrayList<>(newSongs),1);
gv_best.load(new ArrayList<>(bestSongs),1);
gv_singles.load(new ArrayList<>(singleSongs),1);
gv_feats.load(new ArrayList<>(feats),1);
rc_albums.setAdapter(new AlbumAdapter(getContext(), new ArrayList<>(albums)));
rc_albums.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, true));
}
return view;
}
I think the problem is the Keys that you use for your Bundles. All your instances of the custom view use the same SavedInstanceKey.SUPERSTATE.name().
You could try to have the Fragment pass a different key to each of the custom views (BEST, NEW...). This way, each of your GridView has its own unique key to use in the saveInstanceState and restoreInstanceState methods.
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.
I am fetching data from json with Volley and populating RecyclerView with the parsed data but I ran into a bit of problem:
The call to get the items is in onCreate method, so the call is repeated each time the activity is recreated both from configuration changes and otherwise; hence the data is reloaded. So I found this answer that uses parcelables
and this article on Codepath (still on parcelables). After I have followed the instructions explicitly (or so I feel), there seems to be no change: the call to get data is repeated each time the activity is recreated.
FruitItems
public class FruitItems implements Parcelable {
private String fruit_title;
private String fruit_description;
private String fruit_image;
public String getFruit_title() {
return fruit_title;
}
public void setFruit_title(String fruit_title) {
this.fruit_title = fruit_title;
}
public String getFruit_description() {
return fruit_description;
}
public void setFruit_description(String fruit_description) {
this.fruit_description = fruit_description;
}
public String getFruit_image() {
return fruit_image;
}
public void setFruit_image(String fruit_image) {
this.fruit_image = fruit_image;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.fruit_title);
dest.writeString(this.fruit_description);
dest.writeString(this.fruit_image);
}
public FruitItems() {
}
protected FruitItems(Parcel in) {
this.fruit_title = in.readString();
this.fruit_description = in.readString();
this.fruit_image = in.readString();
}
public static final Parcelable.Creator<FruitItems> CREATOR = new Parcelable.Creator<FruitItems>() {
#Override
public FruitItems createFromParcel(Parcel source) {
return new FruitItems(source);
}
#Override
public FruitItems[] newArray(int size) {
return new FruitItems[size];
}
};
}
MainActivity
public class MainActivity extends AppCompatActivity {
private final String TAG = "MainActivity";
private final String KEY_POST_ITEMS = "fruititems";
//List of fruits
private List<FruitItems> mFruitItemsList;
//Views
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private ProgressDialog mProgressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate called");
//Initializing Views
recyclerView = (RecyclerView) findViewById(R.id.fruit_recycler);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_POST_ITEMS)) {
mFruitItemsList = savedInstanceState.getParcelableArrayList(KEY_POST_ITEMS);
} else {
//Initializing the fruitlist
mFruitItemsList = new ArrayList<>();
if (NetworkCheck.isAvailableAndConnected(this)) {
getData();
} else {
final Context mContext;
mContext = this;
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(R.string.alert_titl);
alertDialogBuilder.setCancelable(false);
alertDialogBuilder.setIcon(R.mipmap.ic_launcher);
alertDialogBuilder.setMessage(R.string.alert_mess);
alertDialogBuilder.setPositiveButton(R.string.alert_retry, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
if (!NetworkCheck.isAvailableAndConnected(mContext)) {
alertDialogBuilder.show();
} else {
getData();
}
}
});
alertDialogBuilder.setNegativeButton(R.string.alert_cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDialogBuilder.show();
}
}
adapter = new FruitAdapter(mFruitItemsList, this);
recyclerView.setAdapter(adapter);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putParcelableArrayList(KEY_POST_ITEMS, ArrayList<? extends Parcelable>))mFruitItemsList);
super.onSaveInstanceState(savedInstanceState);
}
//Getting json data
private void getData(){
Log.d(TAG, "getData called");
//Show progress dialog
mProgressDialog = new ProgressDialog(MainActivity.this);
mProgressDialog.setCancelable(false);
mProgressDialog.setMessage(this.getResources().getString(R.string.load_fruit));
mProgressDialog.show();
//Creating a json request
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(ConfigFruit.GET_URL,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, "onResponse called");
//Dismissing the progress dialog
if (mProgressDialog != null) {
mProgressDialog.hide();
}
//calling method to parse json array
parseData(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
//Creating request queue
RequestQueue requestQueue = Volley.newRequestQueue(this);
//Adding request to the queue
requestQueue.add(jsonArrayRequest);
}
//parsing json data
private void parseData(JSONArray array){
Log.d(TAG, "Parsing array");
for(int i = 0; i<array.length(); i++) {
FruitItems fruitItem = new FruitItems();
JSONObject jsonObject = null;
try {
jsonObject = array.getJSONObject(i);
fruitItem.setFruit_title(jsonObject.getString(ConfigFruit.TAG_POST_TITLE));
fruitItem.setFruit_description(jsonObject.getString(ConfigFruit.TAG_POST_DESCRIPTION));
//Parsing image
JSONObject fruitImage = jsonObject.getJSONObject("thumbnail");
fruitItem.setFruit_image(fruitImage.getString("url"));
} catch (JSONException w) {
w.printStackTrace()
}
mFruitItemsList.add(fruitItem);
}
adapter.notifyItemRangeChanged(0, adapter.getItemCount());
}
}
I may not be a pro but I know that I have goofed somewhere in the codes above, else it should have worked.
Now, my question is where did I goof and how do I plug this mistake?
EDIT
I have edited the codes above to reflect the answer that I accepted. It works fine but there is still a problem.
I start Activity B from MainActivity. If I press the back-button in Activity B the data is saved but when I press the up-button, the getData is called again and the data is re-fetched.
Please, is there anyway around this?
You don't seem to have an onSaveInstanceState in your mainactivity. You need something like
#Override
protected void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(KEY_POST_ITEMS,mFruitItemsList) ;
}
In order to retain your data for the activity that is about to be destructed and the one that is being created, you need to override the onSaveInstance callback
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putParcelableArrayList(KEY_POST_ITEMS, (ArrayList)mFruitItemsList);
super.onSaveInstanceState(savedInstanceState);
}
NOTE: always remember to call the superclass.
Everything was running fine. But after some testing through my app it crashes and in my Logcat I see this "Content View Not Yet Created". I'm using a BaseAdapter with ListFragment.
My ListFragment Code is :
public class TaskFragment extends ListFragment {
// Adapter class for driver's task list.
private TaskListAdapter mTaskListAdapter;
// all driver trip list setter getter
private ArrayList<TaskModel> mTaskModelArrayList;
// Creating flag for view is created or not.
private boolean hasViewCreated;
private boolean mHasNewTask;
public static TaskFragment newInstance(){
return new TaskFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Fix for styling list fragment :- Starts
View layout = super.onCreateView(inflater, container,
savedInstanceState);
assert layout != null;
ListView lv = (ListView) layout.findViewById(android.R.id.list);
ViewGroup parent = (ViewGroup) lv.getParent();
// Remove ListView and add CustomView in its place
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
RelativeLayout mRelativeLayout = (RelativeLayout) inflater.inflate(
R.layout.fragment_task, container, false);
parent.addView(mRelativeLayout, lvIndex, lv.getLayoutParams());
return layout;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fix for styling list fragment ends
setHasOptionsMenu(true);
hasViewCreated = true;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mTaskModelArrayList = new ArrayList<>();
mTaskListAdapter = new TaskListAdapter(getActivity(), mTaskModelArrayList, this);
setListAdapter(mTaskListAdapter);
setListShown(false);
}
#Override
public void onResume() {
super.onResume();
loadTasks(false, false);
}
private void loadTasks(boolean showError, boolean startButtonFlag) {
// Load task from SQLite
loadTaskFromSQLiteDb();
// Check Online for new data
loadTaskFromServer(showError, startButtonFlag);
}
/**
* Fetching driver's task from mobile.
*/
private void loadTaskFromSQLiteDb() {
try {
if (mTaskModelArrayList.size() == mDBHelper.getActiveTaskCount())
return;
mTaskModelArrayList.clear();
if (mDBHelper.getActiveTaskCount() > 0) {
ArrayList<TaskModel> tasks = mDBHelper.getAllTaskView();
for (TaskModel task : tasks) {
mTaskModelArrayList.add(task);
}
setListShown(true);
}
refreshTaskList(); // notify data change
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Fetching driver's task list from server if showError value true.
* #param showError
* passing boolean value 'true'.
*/
private void loadTaskFromServer(final boolean showError, final boolean startButtonFlag) {
// if showError value true then show progress bar.
if (showError)
showProgress();
JSONObject params = new JSONObject();
JSONObject appBranchId = new JSONObject();
try {
appBranchId.put("branchId", getString(R.string.app_client_id));
params.put("myParam", appBranchId);
params.put("mobileImei", ApplicationController.getInstance()
.getDeviceInfo().get(ApplicationController.DEVICE_IMEI));
} catch (JSONException e) {
e.printStackTrace();
}
new VolleyHelper().doJsonObjectRequest(getActivity(),
VolleyHelper.POST, UrlConstants.DRIVER_TASK_LIST, params,
new VolleyResponseCallBack() {
#Override
public void onResponse(JSONObject response) {
super.onResponse(response);
try {
ApplicationController.getInstance().getRequestQueue().getCache().clear();
endProgress();
if (response.has("data")) {
switch (response.getJSONObject("data").getString("status")) {
case "success":
JSONArray employeeDetailData = response.getJSONObject("data")
.getJSONArray("empDetails");
for (int i = 0; i < employeeDetailData.length(); i++) {
TaskModel taskModel = new TaskModel();
JSONObject employeeDetailJsonObject = employeeDetailData
.getJSONObject(i);
if (!mDBHelper.isTaskExist(employeeDetailJsonObject
.getString("requestId"))) {
taskModel.setmTaskEmployeeRequestId(employeeDetailJsonObject
.getString("requestId"));
taskModel.setmTaskEmployeeId(employeeDetailJsonObject
.getString("employeeId"));
taskModel.setmTaskEmployeeName(employeeDetailJsonObject
.getString("name"));
taskModel.setmTaskEmployeeAddress(employeeDetailJsonObject
.getString("address"));
taskModel.setmTaskEmployeeShiftTime(employeeDetailJsonObject
.getString("tripTime"));
if (response.getJSONObject("data")
.getString("tripType").equalsIgnoreCase("PICKUP")) {
taskModel.setmTaskEmployeePickupTime(employeeDetailJsonObject
.getString("pickUpTime"));
taskModel.setmTaskDriverArrivedFlag(employeeDetailJsonObject
.getString("reachedFlg"));
} else if (response.getJSONObject("data")
.getString("tripType").equalsIgnoreCase("DROP")) {
taskModel.setmTaskEmployeePickupTime("No");
}
taskModel.setmTaskEmployeeLocationStatus(employeeDetailJsonObject
.getString("locationStatus"));
taskModel.setmTaskEmployeeTripType(response.getJSONObject("data")
.getString("tripType"));
taskModel.setmTaskEmployeeBoardedFlag(employeeDetailJsonObject
.getString("boardedFlg"));
if (employeeDetailJsonObject
.getString("boardedFlg").equalsIgnoreCase("N")) {
taskModel.setIsCheckBoxSelected(false);
} else {
taskModel.setIsCheckBoxSelected(true);
}
taskModel.setIsActive(true);
mHasNewTask = true;
mTaskModelArrayList.add(taskModel);
mDBHelper.addTask(taskModel);
}
}
break;
default:
break;
}
} else {
mBtnViewMap.setVisibility(Button.GONE);
}
if (mHasNewTask) {
mHasNewTask = false;
}
if (hasViewCreated)
refreshTaskList();
} catch (JSONException e) {
e.printStackTrace();
}
if (hasViewCreated)
setListShown(true);
if (showError) {
endProgress();
}
}
#Override
public void onError(VolleyError Error) {
endProgress();
}
}, true, new DialogCallBack() {
#Override
protected void onPositiveBtnClick() {
super.onPositiveBtnClick();
loadTaskFromServer(showError, startButtonFlag);
}
#Override
protected void onNegativeBtnClick() {
super.onNegativeBtnClick();
}
});
}
/**
* This method will refresh the entire task list of
* driver if something new comes from server.
*/
private void refreshTaskList() {
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (mTaskListAdapter != null) {
mTaskListAdapter.notifyDataSetChanged();
}
}
});
}
}}
My Logcat error is :
java.lang.IllegalStateException: Content view not yet created
at android.support.v4.app.ListFragment.ensureList(ListFragment.java:328)
at android.support.v4.app.ListFragment.setListShown(ListFragment.java:280)
at android.support.v4.app.ListFragment.setListShown(ListFragment.java:258)
at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:65)
at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
I'm stuck with communication between activity and fragment using interface. I have created activity with child fragment. I wanna do some stuff with continuous thread defined in activity and during that thread when I'm getting some result at that time I wanna trigger to child fragment to do something.
My Container Activity
public class MySpaceActivity extends BaseDrawerActivity {
private OnSetLastSeenListener mListner;
public static Thread mThread = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHeaders(Const.MY_SPACE);
super.setSubmenus(Const.MY_SPACE,
Utils.getSubmenuList(Const.MY_SPACE, MySpaceActivity.this),
submenuBean);
// super.attachFragment(submenuBean);
}
#Override
public void setHeaderSubMenu(SubmenuBean subMenuBean) {
// txt_submenu.setText(subMenuBean.getSubmenu_name());
this.submenuBean = subMenuBean;
Log.print("::::: setHeaderSubMenu ::::");
super.attachFragment(submenuBean);
}
public void setsubFragment(SubmenuBean subMenuBean) {
this.submenuBean = subMenuBean;
super.attachSubFragment(submenuBean);
}
#Override
public void onBackPressed() {
super.onBackPressed();
popLastFragment();
}
private void popLastFragment() {
if (super.getNumberOfChilds() > 1) {
super.popSubFragment();
} else {
finish();
}
}
#Override
protected Fragment getFragement() {
StudentsFragment fragment = new StudentsFragment(Const.MY_SPACE,
getSubmenubean());
return fragment;
}
public SubmenuBean getSubmenubean() {
return submenuBean;
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mThread = new Thread(new CountDownTimer(MySpaceActivity.this));
mThread.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (mThread.isAlive()) {
mThread.interrupt();
mThread = null;
}
}
public void updateLastSeen(){
Log.print("::::::Call Interface::::::");
mListner.updateLastSeen();
}
class CountDownTimer implements Runnable {
private Context mContext;
private JSONObject mJsonObject;
private JSONArray mJsonArray;
public CountDownTimer(Context mContext) {
this.mContext = mContext;
}
// #Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
HttpChatLastSeen mChat = new HttpChatLastSeen();
mJsonObject = mChat.Http_ChatLastSeen(mContext);
String mResult = mJsonObject.getString("Result");
if (mResult.equalsIgnoreCase(String
.valueOf(Const.RESULT_OK))) {
mJsonArray = mJsonObject.getJSONArray("UserData");
for (int i = 0; i < mJsonArray.length(); i++) {
mJsonObject = mJsonArray.getJSONObject(i);
new DbStudentMasterBll(mContext).update(
"last_seen", mJsonObject
.getString("LastSeen"), Integer
.parseInt(mJsonObject
.getString("UserId")));
}
} else {
Log.print("MY LAST SEEN Response : "
+ mJsonObject.toString());
}
updateLastSeen();
Thread.sleep(15000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
Log.print("ChatLastSeenThread : ", e.getMessage());
}
}
}
}
}
My Child Fragment With Interface :
public class StudentsFragment extends Fragment implements OnSetLastSeenListener{
TextView txt_submenu;
ListView list_students;
SubmenuBean submenuBean;
int Mainmenu;
MySpaceActivity mMySpaceActivity;
ArrayList<DbStudentMasterBean> studentsList;
StudentsAdapter mAdapter = null;
OnSetLastSeenListener mListner;
public StudentsFragment() {
super();
}
public StudentsFragment(int Mainmenu, SubmenuBean submenuBean) {
this.submenuBean = submenuBean;
this.Mainmenu = Mainmenu;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_students, container,
false);
mMySpaceActivity = (MySpaceActivity) getActivity();
txt_submenu = (TextView) view.findViewById(R.id.txt_submenu);
txt_submenu.setText(submenuBean.getSubmenu_name());
txt_submenu.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mMySpaceActivity.openDrawer();
}
});
list_students = (ListView) view.findViewById(R.id.list_colleagues);
studentsList = new DbStudentMasterBll(getActivity()).getAllRecords();
mAdapter = new StudentsAdapter(getActivity(), studentsList, handler);
list_students.setAdapter(mAdapter);
list_students.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
DbStudentMasterBean bean = (DbStudentMasterBean) parent
.getAdapter().getItem(position);
Message msg = new Message();
msg.what = CHAT;
msg.obj = bean;
handler.sendMessage(msg);
}
});
return view;
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CHAT:
submenuBean.setTag(VIEWCHATSTUDENT);
DbStudentMasterBean bean = (DbStudentMasterBean) msg.obj;
mMySpaceActivity.setsubFragment(submenuBean);
break;
}
};
};
#Override
public void updateLastSeen() {
// TODO Auto-generated method stub
Log.print("!!!!!!!!!Refresh Adapter!!!!!!!!!!!");
mAdapter.notifyDataSetChanged();
}
}
My Interface :
public interface OnSetLastSeenListener {
public void updateLastSeen();
}
So I have implemented interface OnSetLastSeenListener with my child fragment StudentsFragment . Now I'm calling method of tht interface updateLastSeen() from my container activity with thread. But it is not getting trigger to child fragment where I have implemented interface. So I don't know whether it is good way to communicate or not? Let me take your help to suggest on this solution or best way to communicate from child fragment to parent activity.
Thanks,
It is better to use interface when you want to communicate something from Fragment to Activity and not vice versa.
In your case, you can directly call the method in Fragment from Activity through fragment object. No need to use interface.
Something like this (For static fragments)
StudentsFragment fragment = (StudentsFragment) getFragmentManager()
.findFragmentById(R.id.fragmentid);
if (fragment != null && fragment.isInLayout()) {
fragment.updateLastSeen();
}
For dynamic fragment you can use the fragment object directly.