recyclerview is empty when back pressed from fragment - android

On Fragment1 i have onClick method, when i click the button, i got the recycleview list of items. When i click the item in recycleview(use getPlaceFromItem method), i go to the Fragment2. if device is phone then put the
Fragment2 in container1, but if device is tablet(landscape) then i put Fragment2 into container2 next to Fragment1 in container1.
Now, when i press back button when device is phone, i get empty recycleview.
In addition i check orientation of the screen and when the device is phone and i am in Fragment2(i.e Fragment2 in container1), then when the screen will be landscape i will put into container1 Fragment1, and into container2 at Fragment2. My problem is how can i cut Fragment2 from container1 and put it into container2.
Main Activity :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
View v = findViewById(R.id.container2);
v.setVisibility(View.GONE);
getSupportFragmentManager().beginTransaction()
.add(R.id.container1, new FragmentA())
.commit();
}
#Override
public void getPlaceFromItem(Place place) {
Bundle bundle = new Bundle();
bundle.putDouble("lat", place.getLat());
bundle.putDouble("lng", place.getLng());
Fragment2 fragment2 = new Fragment2();
fragment2.setArguments(bundle);
if(getResources().getBoolean(R.bool.isTab)) {
View v = findViewById(R.id.container2);
v.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container2,fragment2)
.addToBackStack(null)
.commit();
}
else {
getSupportFragmentManager().beginTransaction()
.replace(R.id.container1, fragment2)
.addToBackStack(null)
.commit();
}
}
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
View v = findViewById(R.id.container2);
v.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container1, new Fragment1())
// The next row is a problematic!!!
.replace(R.id.container2, new Fragment2())
.commit();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
}
}

Remember when a fragment is popped out from back stack it comes back with no view. So you have to attach the view again.
I recommend for you to keep track of the main View in Fragment in order to avoid views from recreating. This way once you come back to the fragment with the RecyclerView it will be there. The code would look like this.
public class BlankFragment2 extends Fragment {
public View myRoot;
public BlankFragment2() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (myRoot == null) {
myRoot = inflater.inflate(R.layout.fragment_blank_fragment2, container, false);
}
return myRoot;
}
}

.addToBackStack(null) remove it from code
i hope it will work for you

Add .addToBackStack(fragment.getClass().getCanonicalName()) or .addToBackStack("anyString") to save fragment instance. Also use add method, not replace when you add new fragments.

when you are adding your first fragment you should not use addToBackStack(null).
for first fragment write like this
getSupportFragmentManager().beginTransaction()
.add(R.id.container1, FragmentA)
.commit();
for other fragments you should use
getSupportFragmentManager().beginTransaction()
.replace(R.id.container1, FragmentB)
.addToBackStack(null)
.commit();
hope it helps!

Related

why the app crashes when I use onclicklistener with Fragment?

public class MainActivity extends AppCompatActivity {
Context context;
LinearLayout menuClcick,gallerClcik,eventsClick;
LayoutInflater inflater;`enter code here`
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//we don't need to set view, our fragment will handle it
setPointer();
//Fragment Manger
FragmentManager fm = getFragmentManager();
//create instance of Fragment Transaction to handle fragment replace and animation
FragmentTransaction ft=fm.beginTransaction();
int displayMode = getResources().getConfiguration().orientation;
Log.e("WTF", "onCreate: "+displayMode );
//choose which fragment to display according to screen orientation
if (displayMode==1) //portrait
{
// that's the Fragment that I use to display a layout in the portrait and other layout in the landscape//
//create instance of our portrait fragment
Fragment1 f1=new Fragment1();
//change content of the screen to our new fragment
ft.replace(android.R.id.content,f1);
}
else
{
Fragment2 f2=new Fragment2();
ft.replace(android.R.id.content,f2);
}
//choose animation
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
//commit our changes
ft.commit();
}
private void setPointer() {
this.context=this;
menuClcick=findViewById(R.id.menuClick);
gallerClcik=findViewById(R.id.gallerClcik);
eventsClick=findViewById(R.id.eventsClick);
//this is the problem the app have no problem to find the buttons but it stops working when I try to put onclick listener in it//
menuClcick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "portrait", Toast.LENGTH_SHORT).show();
}
});
}
You are trying to access views that are not yet created,
As the documentation lifecycle shows, you should implement onCreateView() to inflate your layout and only there you have access to your R.id.menuClick.
So basically, you should call your setPointer() method on onCreateView().

How to get back to previous activity from a fragment

I'm building a simple app and I want to go back from fragment to activity with physical button. How do I do that? I have tried to kill the fragment but it isn't working.
You can get a reference to the FragmentActivity by calling getActivity() on your current Fragment and then call from the Activity retrieved onBackPressed() method.
getActivity().onBackPressed();
I do it like this and it's working very fine.
Start fragment:
public void showMyFragment(View V){
Fragment fragment = null;
fragment = new MyFragment();
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).addToBackStack(null).commit();
}
}
This is how to end fragment with back button:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
getFragmentManager().popBackStack();
}
}
Your Fragment:
public class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.activity_info, null);
return v;
}
}
Show fragment with this:
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.replace(R.id.frame_container,fragment.class,null).addToBackStack("desc_fragment")
.commit();
and then override onBackPressed in your activity:
#Override
public void onBackPressed() {
if(getSupportFragmentManager().getBackStackEntryCount() > 0)
getSupportFragmentManager().popBackStack();
else
super.onBackPressed();
}

Trying to make a flexible UI

I'am trying to make a app with a flexible UI.
I already implemented for handset devices (I have one activity and multiple fragments), and what I done was: The main fragment is a dashboard, and when I click in one button of it, he dashboard is replaced by a new fragment ( the clicked feature). Here is the code:
Dashboard fragment:
public class DashboardFragment extends Fragment {
GridView gridView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
return inflater.inflate(R.layout.activity_dashboard, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
gridView=(GridView)getView().findViewById(R.id.dashboard_grid);
gridView.setAdapter(new ImageAdapter(getActivity()));
gridView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
Fragment fragment = null ;
switch (position) {
case 0:
fragment = new TestFragment();
break;
case 1 :
fragment = new TestFragment();
break;
case 2 :
fragment = new TestFragment();
break;
case 3 :
fragment = new TestFragment();
break;
case 4 :
fragment = new TestFragment();
break;
}
transaction.replace(R.id.container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
}
}
and my Main Activity:
public class MainActivity extends FragmentActivity{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.container) != null) {
if (savedInstanceState != null) {
return;
}
// Create an instance of ExampleFragment
DashboardFragment firstFragment = new DashboardFragment();
firstFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.container, firstFragment).commit();
}
}
}
Now, what I want is to adapt this code and use a layout for tablets, with the dashboard on the left and the choosen fragment on the right, like this:
What could I do? I already tried to adapt this example, but I can't because they only update the fragment, they don't replace it.
Check this great article about multi-pane development.
It also includes an example (Sections 10 and 11)
Basically you can check whether there is a fragment element for your "Fragment B" in the current layout. If yes, you just update its content, if no, then start an activity which has it in its layout, or replace one in the current layout.
DetailFragment fragment = (DetailFragment) getFragmentManager().findFragmentById(R.id.detail_frag);
if (fragment==null || ! fragment.isInLayout()) {
// start new Activity or replace
}
else {
fragment.update(...);
}

WebView inside SherlockFragment - FragmentTransaction.Detach() does not remove the webview

I am using ActionBarSherlock's action bar tabs in my application with each tab populated by a single fragment inside a SherlockActivity Tabs.
One of my Tabs contains a fragment, FragmentHome, with a list of news articles. When an article is selected, FragmentHome is replaced by another fragment, FragmentNews.
FragmentNews just contains a webview to load the selected article. The article is loaded fine. I override the onBackPressed in my activity so that FragmentHome is reattached and FragmentNews is removed.
While there are no errors, the webview inside FragmentHome is never removed from the view and overlaps with other fragments. (See screenshots)
Its weird because the same code works for a another SherlockFragment with ListView in it but is messed up when using a WebView. Here is the code to replace FragmentHome with FragmentNews initially:
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
listNews.setItemChecked(position, true);
Bundle bundle = new Bundle();
bundle.putStringArray("NEWS",
new String[] {
mNews.newsFeed.get(position).getTitle(),
mNews.newsFeed.get(position).getLink()
.toExternalForm() });
FragmentTransaction ft = getSherlockActivity()
.getSupportFragmentManager().beginTransaction();
Fragment frag = SherlockFragment.instantiate(getSherlockActivity(),
FragmentNews.class.getName(), bundle);
ft.detach(getSherlockActivity().getSupportFragmentManager()
.findFragmentById(getId()));
ft.add(android.R.id.content, frag, Tabs.FRAG_NEWS);
ft.commit();
}
Overriden onBackPressed in Tabs:
#Override
public void onBackPressed() {
Fragment frag = getSupportFragmentManager().findFragmentByTag(
FRAG_DETAILS);
if (frag != null && frag.isVisible()) {
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.remove(frag);
Fragment mFragment = getSupportFragmentManager().findFragmentByTag(
TAB_PORTFOLIO);
if (mFragment == null) {
mFragment = SherlockFragment.instantiate(this,
FragmentPortfolioList.class.getName(), null);
ft.add(android.R.id.content, mFragment, TAB_PORTFOLIO);
} else {
ft.attach(mFragment);
}
ft.commit();
} else {
frag = getSupportFragmentManager().findFragmentByTag(FRAG_NEWS);
if (frag != null && !frag.isDetached()) {
Log.e("onBackPressed", "for " + frag.getTag());
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
ft.remove(frag);
Fragment mFragment = getSupportFragmentManager()
.findFragmentByTag(TAB_HOME);
if (mFragment == null) {
mFragment = SherlockFragment.instantiate(this,
FragmentHome.class.getName(), null);
ft.add(android.R.id.content, mFragment, TAB_HOME);
} else {
ft.attach(mFragment);
}
ft.commit();
} else {
Log.e("onBackPressed", "inside else");
super.onBackPressed();
}
}
}
Snippet from FragmentNews
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
arr = getArguments().getStringArray("NEWS");
setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_news, container);
newsView = (WebView) view.findViewById(R.id.news_WV_Brief);
newsView.getSettings()
.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
newsView.getSettings().setGeolocationEnabled(false);
newsView.getSettings().setAllowFileAccess(false);
newsView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.e("override", url);
return true;
}
});
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
newsView.loadUrl(arr[1]);
}
I have seen posts talking about FlashPlayer causing issues because of SurfaceView cutting a hole but I am just displaying simple webpages without any videos. Help highly appreciated.
I figured out the problem while going over the source code of WebViewFragment. I realized there isn't much going on other than pause/resume of webview.
I had two serious errors in my code:
I never returned the inflated view in onCreatView in
FragmentNews. I was returning super.onCreateView(inflater,
container, savedInstanceState).
I forgot to set attachToRoot to false in onCreateView when
inflating the XML layout - View view =
inflater.inflate(R.layout.fragment_news, container, **false**)
Therefore, the inflated view was just standing on its own without being attached to the fragment. When the fragment was replaced, it resulted in a mashed up display because the inflated layout containing the WebView was never removed. Unfortunately, this complied without errors.

Add different fragment to an activity based on Intent-given identifier

I'm working on an application where in layout layout-small-portrait I want to launch different fragments contained in a single "container activity", named SingleActivity. I will handle this differnetly in layouts layout-land, layout-large etc. but that is unrelated to my problem.
I have an activity MainActivity which is, as the name indicates, the main activity (launcher) of my application. This will initially contain a ListFragment with different items for the user to press.
Based on the item that the user presses the SingleActivity will launch and its content will correspond to a specific Fragment related to this item. My problem starts here. When the user presses an item I have a reference to the corresponding fragment I want to be displayed in SingleFragment. Illustrated below:
String tag = myFragmentReference.getTag();
Intent i = new Intent(this, SingleActivity.class);
i.putExtra(SingleActivity.CONST_TAG, tag);
startActivity(i);
The activity launches successfully. In SingleActivity I have the following onCreate() method:
...
// Retrieve the fragment tag from the intent
String tag = getIntent().getStringExtra(CONST_TAG);
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
if(fragment == null) {
// always end up here, this is my problem.
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, fragment);
ft.commit();
...
I suspect that the fact that fragment is always null is because the fragment has not been inflated yet. If I am right what I need to do is define a fragment's tag before it is inflated, so that it can be found by findFragmentByTag(). Is that possible?
If anything is unclear please let me know.
I look forward to hearing some good ideas! If there are better or more clever ways to implement this I would love to hear your thoughts! Thanks :)
Since you are jumping to another activity, it will have its own Fragment BackStack and that fragment will not exist.
You will have to inflate the fragment in the new activity something along these lines:
String tag = intent.getStringExtra(CONST_TAG);
if (getSupportFragmentManager().findFragmentByTag(tag) == null) {
Fragment fragment = Fragment.instantiate(this, tag, extras);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, fragment, tag);
ft.commit();
}
The tag string will need to have the package location of the fragment such as "com.android.myprojectname.myfragment"
First use SlidingMenu library: https://github.com/jfeinstein10/SlidingMenu
This will help you, and your app will be more cool, that´s the only way that I can help you make what you need so, here is the code:
Here is your MainActivity:
I´ll try to explain this sample code and you use for your need.
This is the ListFragment of your BehindContent (SlidingMenu):
public class ColorMenuFragment extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.list, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] colors = getResources().getStringArray(R.array.color_names);
ArrayAdapter<String> colorAdapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, colors);
setListAdapter(colorAdapter);
//This array is only to fill SlidingMenu with a Simple String Color.
//I used MergeAdapter from Commonsware to create a very nice SlidingMenu.
}
#Override
public void onListItemClick(ListView lv, View v, int position, long id) {
//This switch case is a listener to select wish item user have been selected, so it Call
//ColorFragment, you can change to Task1Fragment, Task2Fragment, Task3Fragment.
Fragment newContent = null;
switch (position) {
case 0:
newContent = new ColorFragment(R.color.red);
break;
case 1:
newContent = new ColorFragment(R.color.green);
break;
case 2:
newContent = new ColorFragment(R.color.blue);
break;
case 3:
newContent = new ColorFragment(android.R.color.white);
break;
case 4:
newContent = new ColorFragment(android.R.color.black);
break;
}
if (newContent != null)
switchFragment(newContent);
}
// the meat of switching the above fragment
private void switchFragment(Fragment fragment) {
if (getActivity() == null)
return;
if (getActivity() instanceof FragmentChangeActivity) {
FragmentChangeActivity fca = (FragmentChangeActivity) getActivity();
fca.switchContent(fragment);
} else if (getActivity() instanceof ResponsiveUIActivity) {
ResponsiveUIActivity ra = (ResponsiveUIActivity) getActivity();
ra.switchContent(fragment);
}
}
}
Here is your BaseActivity Class:
It dont have swipe, as I could understand, you don't need this.
public class FragmentChangeActivity extends BaseActivity {
private Fragment mContent;
public FragmentChangeActivity() {
super(R.string.changing_fragments);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the Above View
if (savedInstanceState != null)
mContent = getSupportFragmentManager().getFragment(savedInstanceState, "mContent");
if (mContent == null)
mContent = new ColorFragment(R.color.red);
// set the Above View
//This will be the first AboveView
setContentView(R.layout.content_frame);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, mContent)
.commit();
// set the Behind View
//This is the SlidingMenu
setBehindContentView(R.layout.menu_frame);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.menu_frame, new ColorMenuFragment())
.commit();
// customize the SlidingMenu
//This is opcional
getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "mContent", mContent);
}
public void switchContent(Fragment fragment) {
// the meat of switching fragment
mContent = fragment;
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
getSlidingMenu().showContent();
}
}
Ok, So If you want to change the ColorFragment to anything else, do this:
First, choice the item that you want to use:
case 0:
newContent = new ColorFragment(R.color.red);
break;
to:
case 0:
newContent = new ArrayListFragment();
break;
I have made just a arraylist, it is just a simple example, you can do a lot of thing, then you can read about Fragment to learn how to do different things.
public class ArrayListFragment extends ListFragment {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, Listnames.TITLES));
//Listnames is a class with String[] TITLES;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Log.i("FragmentList2", "Item clicked: " + id);
String item = (String) getListAdapter().getItem(position);
Toast.makeText(getActivity(), item, Toast.LENGTH_LONG).show();
}
}
As you see, it can display a different fragment based on which item in the ListFragment (MainActivity) the user presses.
Well, if you misunderstood something, just tell me.

Categories

Resources