Refresh fragments after coming back from an activity - java

I'm working on an activity which uses a TabLayout to house two fragments. Each of the fragments uses RecyclerView. The activity also has an options menu. When any of the options is clicked, a new activity will start. One of the new activities has a "Save" button which when clicked will update the first activity's data set and return to the first activity. However, the first activity's fragments don't show the changed data set even though the data set itself changes.
RecordAddActivity.java (First Activity)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FileUtils.initDataDir(this);
MySQLiteHelper db = new MySQLiteHelper(this);
Bundle bundle = getIntent().getExtras();
siteID = bundle.getLong(Constants.INTENT_EXTRA_SITE_ID);
site = db.getSiteByID(siteID);
trapFileName = site.getId() + "_" + site.getName() + ".csv";
inputString = site.getName();
setContentView(R.layout.activity_add_record_new);
viewPager = (ViewPager) findViewById(R.id.view_pager);
adapter = new PagerAdapter(getSupportFragmentManager());
insectsAddRecordFragment = new InsectsAddRecordFragment();
naturalPestsAddRecordFragment = new NaturalPestsAddRecordFragment();
if (!doesRecordExist) {
insectsAddRecordFragment.setInsects(site.getInsectsNames());
naturalPestsAddRecordFragment.setNaturalPests(site.getNaturalPestsNames());
} else {
IsDefaultInsectTypes isDefaultInsectTypes = new IsDefaultInsectTypes(trapFileName);
insectsAddRecordFragment.setInsects(isDefaultInsectTypes.getInsectNamesList());
naturalPestsAddRecordFragment.setNaturalPests(isDefaultInsectTypes.getPestNamesList());
site.setInsects(isDefaultInsectTypes.getInsectNamesList());
site.setNaturalPests(isDefaultInsectTypes.getPestNamesList());
}
adapter.addFragment(insectsAddRecordFragment, "Serangga Perosak");
adapter.addFragment(naturalPestsAddRecordFragment, "Musuh Semulajadi");
viewPager.setAdapter(adapter);
final TabLayout tabLayout = (TabLayout) findViewById(R.id.tablayoutbar);
tabLayout.setTabTextColors(Color.BLACK, Color.WHITE);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
#Override
public void onTabSelected(TabLayout.Tab tab) {
super.onTabSelected(tab);
tabLayout.requestFocus();
hideKeyboard(viewPager);
}
});
}
//The options menu which start the new activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_edit_insects_type){
final int EDIT_INSECT_TYPE_REQUEST = 1;
Intent intent = new Intent(RecordAddActivity.this, EditInsectsTypeActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_REPORT_TRAP_FILE, trapFileName);
intent.putExtra(Constants.INTENT_EXTRA_SITE_OBJECT, site);
startActivityForResult(intent, EDIT_INSECT_TYPE_REQUEST);
return true;
}
}
//The FragmentPagerAdapter
public class PagerAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragmentList = new ArrayList<>();
private List<String> mFragmentTitleNames = new ArrayList<>();
public PagerAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleNames.add(title);
}
public void swapItems(Fragment insectFragment, Fragment naturalPestFragment) {
mFragmentList.clear();
mFragmentList.add(insectFragment);
mFragmentList.add(naturalPestFragment);
Log.d(TAG, "Items swapped");
notifyDataSetChanged();
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleNames.get(position);
}
}
What I've tried:
Using onResume()
#Override
public void onResume() {
Log.d(TAG, "onResume");
super.onResume(); // Always call the superclass method first
doesRecordExist = FileUtils.doesRecordExists(trapFileName);
if (doesRecordExist) {
IsDefaultInsectTypes isDefaultInsectTypes = new IsDefaultInsectTypes(trapFileName);
insectsAddRecordFragment = new InsectsAddRecordFragment();
naturalPestsAddRecordFragment = new NaturalPestsAddRecordFragment();
//The log shows that the data set has changed
Log.d(TAG, "Nama serangga:" + isDefaultInsectTypes.getInsectNamesList());
//Trying to update the fragments
insectsAddRecordFragment.setInsects(isDefaultInsectTypes.getInsectNamesList());
naturalPestsAddRecordFragment.setNaturalPests(isDefaultInsectTypes.getPestNamesList());
adapter.swapItems(insectsAddRecordFragment, naturalPestsAddRecordFragment);
}
}
Using a Global variable to update the fragment
EditInsectsTypeActivity.java (The new activity)
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_save) {
Globals2 allowRefresh = Globals2.getInstance();
ArrayList<String> insectsNameList = insectsViewFragment.getInsectsNameList();
ArrayList<String> pestsNameList = naturalPestsViewFragment.getInsectsNameList();
FileUtils.updateSiteInsects(this, trapFileName, insectsNameList, pestsNameList);
allowRefresh.setData(true);
Log.d(TAG, "allowRefresh: " + allowRefresh.getData());
finish();
Utils.showToast(getBaseContext(), "Rekod disimpan");
}
return true;
}
InsectsAddRecordFragment.java (The fragment to be refreshed/updated)
#Override
public void onResume() {
Log.d(TAG, "onResume");
super.onResume(); // Always call the superclass method first
Globals2 allowRefresh = Globals2.getInstance();
IsDefaultInsectTypes isDefaultInsectTypes = new IsDefaultInsectTypes("27_Cgtv.csv");
Log.d(TAG, "Nama serangga:" + isDefaultInsectTypes.getInsectNamesList());
setInsects(isDefaultInsectTypes.getInsectNamesList());
Log.d(TAG, "allowRefresh: " + allowRefresh.getData());
if (allowRefresh.getData()) {
allowRefresh.setData(false);
getFragmentManager().beginTransaction().detach(this).attach(this).commit();
}
}
I've spent hours trying to fix this without any luck. Any help will be much appreciated.

So here's what you need to do, in your Activity's onPause() method update the list in your InsectsAddRecordFragment like so:
public void onPause()
{
... // your logic for data-set changed.
if (doesRecordExist)
insectsAddRecordFragment.setInsects(isDefaultInsectTypes.get‌​InsectNamesList());
...
}
And within setInsects of InsectsAddRecordFragment something similar to this.
public void setInsects() {
// Here adapter is the Adapter for the RecyclerView
adapter.setAdapterList(isDefaultInsectTypes.get‌​InsectNamesList());
// notifyDataSetChanged() is important here because without this the Adapter has no idea
// that data has changed.
adapter.notifyDataSetChanged();
}
While in your RecyclerViewAdapter for InsectsAddRecordFragment's RecyclerView items. Do the following.
// ArrayList<String> list is just an example you may have some different data set.
public void setAdapterList(ArrayList<String> list) {
this.adapterList = list;
}
Using this approach there is no need recreate the fragment, instead you can just update the dataset within the Adapter.
I'd also suggest reading some blogs and how-to's on Fragments, RecyclerView and RecyclerView.Adapter before you work any further.

Override:
protected void onActivityResult(int requestCode, int resultCode, Intent data)
In the first Activity.
[EDIT] More info on startActivityForResult() here:
https://developer.android.com/training/basics/intents/result.html

Related

How to refresh a Textview in a fragment which receives data from a Listview in an activity which doesn't host that fragment

I have created a bottomNavigation bar which consists of 5 Fragments, so once each tab is clicked it will switch from one fragment to another.
The question is:The second fragment (Search fragment) have 1 TextView with setOnClickListener so once it is been licked a layout activity will open on the top which includes a ListView to allow the user to select/click on a specific Item, so later on this selected item info should be displayed on that TextView within the(Search fragment).
The issue is that this Textview won't be updated, unless I call the mainActivity to so all fragments in bottom Navigation bar will be updated
My question is how I can refresh that specific fragment without calling the MainActivity.
public class MainActivity extends AppCompatActivity {
final Fragment f1 = new HomeFragment();
final Fragment f2 = new SearchFragment();
final Fragment f3 = new CameraFragment();
final Fragment f4 = new ChatFragment();
final Fragment f6 = new LogginFragment();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = f1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationViewEx bnve = (BottomNavigationViewEx) findViewById(R.id.bottom_navigation);
bnve.enableAnimation(false);
bnve.enableShiftingMode(false);
bnve.enableItemShiftingMode(false);
bnve.setOnNavigationItemSelectedListener(navListener);
if(SharePrefManager.getInstance(this).isLoggedin()){
finish();
startActivity(new Intent(this, SuccessActivity.class));
return;
}
fm.beginTransaction().add(R.id.fragment_container, f6, "6").hide(f6).commit();
//fm.beginTransaction().add(R.id.fragment_container, f5, "5").hide(f5).commit();
fm.beginTransaction().add(R.id.fragment_container, f4, "4").hide(f4).commit();
fm.beginTransaction().add(R.id.fragment_container, f3, "3").hide(f3).commit();
fm.beginTransaction().add(R.id.fragment_container, f2, "2").hide(f2).commit();
fm.beginTransaction().add(R.id.fragment_container, f1, "1").commit();
}
public BottomNavigationViewEx.OnNavigationItemSelectedListener navListener =
new BottomNavigationViewEx.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_home:
fm.beginTransaction().hide(active).show(f1).commit();
active = f1;
return true;
case R.id.nav_search:
fm.beginTransaction().hide(active).show(f2).commit();
active = f2;
return true;
case R.id.nav_camera:
fm.beginTransaction().hide(active).show(f3).commit();
active = f3;
return true;
case R.id.nav_chat:
fm.beginTransaction().hide(active).show(f4).commit();
active = f4;
return true;
case R.id.nav_account:
fm.beginTransaction().hide(active).show(f6).commit();
active = f6;
return true;
}
return false;
}
};
}
------------------------SearchFragment Class----------------------------------
This is the search fragment which has the textView (Categories) which supposed to be updated/be refershed without calling the MainActivity
public class SearchFragment extends Fragment {
private Context mContext;
TextView Categories;
static boolean status = false;
String SelectedItem;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_search,container,false);
Categories = (TextView) v.findViewById(R.id.categories);
SelectedItem = DataHolder.getInstance().getItem();
Categories.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(mContext, AllCateActivity.class));
}
});
if(status){Categories.setText(SelectedItem);}
return v;
}
public void ChangeStatus(Boolean status){
this.status = status;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext=context;
}
}
--------------------------DataHolder Class---------------------------------
This works as a design pattern to share arguments between the search fragment and Categories_Activity
public class DataHolder {
private static DataHolder dataHolder = null;
private DataHolder() {
}
public static DataHolder getInstance() {
if (dataHolder == null)
{
dataHolder = new DataHolder();
}
return dataHolder;
}
private String item;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
}
--------------------------Categories_Activity---------------------------------
This Activity once it's being called a listview will show allowing user to select an item. So once an Item has been selected it will start the MainActivity in order to refresh the Text field in the search Fragment
public class Categories_Activity extends AppCompatActivity implements View.OnClickListener {
ImageView BacktoMainCate;
ListView subCate;
public String selectedItem;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab_subcategory);
subCate = (ListView)findViewById(R.id.listview_subcate);
BacktoMainCate = (ImageView)findViewById(R.id.BacktoMainCate);
BacktoMainCate.setOnClickListener(this);
final SearchFragment SF = new SearchFragment();
subCate.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectedItem = String.valueOf(parent.getItemAtPosition(position));
DataHolder.getInstance().setItem(selectedItem);
SF.ChangeStatus(true);
Intent in = new Intent(Categories_Activity.this,SuccessActivity.class);
startActivity(in);
});
}
#Override
public void onClick(View v) {
if (v == BacktoMainCate){
//startActivity(new Intent(this,AllCateActivity.class));
finish();
}
}
}
I have used SharedPreferences on both Fragment/Activity life cycle.
So once the Categories_Activity get started, Main Activity will go in onPause and with it all its Fragments will be put in onPause. When user clicks on one of the ListView items in the Categories_Activity, data of that selected item will be store inside SharedPreferences like:
PreferenceManager.getDefaultSharedPreferences(Categories_Activity .this)
.edit().putString(key, selectedItemInfo).apply();
Then override onResume() method inside MainActivity and SearchFragment:
#Override
public void onResume() {
super.onResume();
String value = PreferenceManager.getDefaultSharedPreferences(getContext())
.getString(key, "");
if (value != null && !value.isEmpty()) {
Categories.setText(value);
PreferenceManager.getDefaultSharedPreferences(getContext()).edit().remove(key);
}
}

Starting Fragment method from MainActivity causes Exception

I work on an app which contains Fragments and a ViewPager. I fetch location data in my MainActivity and want to use it inside the fragments, so I created a method to pass the variables and process with them. Unfortunately I get a NullPointerException on all view objects, like the progressBar or the CollapsingToolbarLayout inside of the Fragment when the method is called. I guess the fragment is not correctly started just by calling a method, but how can I change it, so the view objects are created? Or is there another way to first fetch location data and use it inside the fragments afterwards?
My MainActivity:
public class MainActivity extends AppCompatActivity implements Serializable {
private ViewPager viewPager;
BottomNavigationView bottomNavigationView;
FragmentA FragmentA;
FragmentB FragmentB;
FragmentC FragmentC;
MenuItem prevMenuItem;
public double lat;
public double lon;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
bottomNavigationView = (BottomNavigationView)findViewById(R.id.bottom_navigation);
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_umkreis:
viewPager.setCurrentItem(0);
break;
case R.id.navigation_karte:
viewPager.setCurrentItem(1);
break;
case R.id.navigation_einstellungen:
viewPager.setCurrentItem(2);
break;
}
return false;
}
});
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if (prevMenuItem != null) {
prevMenuItem.setChecked(false);
}
else
{
bottomNavigationView.getMenu().getItem(0).setChecked(false);
}
Log.d("page", "onPageSelected: "+position);
bottomNavigationView.getMenu().getItem(position).setChecked(true);
prevMenuItem = bottomNavigationView.getMenu().getItem(position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
setupViewPager(viewPager);
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
callsFragment = new CallsFragment();
chatFragment = new ChatFragment();
contactsFragment = new ContactsFragment();
adapter.addFragment(callsFragment);
adapter.addFragment(chatFragment);
adapter.addFragment(contactsFragment);
viewPager.setAdapter(adapter);
int limit = adapter.getCount();
viewPager.setOffscreenPageLimit(limit);
}
public void start() {
//Location data fetched here
FragmentB fb = new FragmentB();
fb.start(lat, lon);
}
}
My FragmentB:
public class FragmentB extends Fragment {
private ProgressBar progressBar;
private double lat;
private double lon;
String title;
private BaseAdapter mItemsAdapter;
private final List<HashMap<String, String>> mItemList = new ArrayList<>();
ArrayList<HashMap<String, String>> resultList = new ArrayList<>();
public FragmentB() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_b, container, false);
progressBar = (ProgressBar) view.findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);
((ListView) view.findViewById(R.id.list))
.setAdapter(mItemsAdapter);
return view;
}
public void start(double latGet, double lonGet){
lat = latGet;
lon = lonGet;
new GetContacts().execute();
}
private class GetContacts extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
}
#Override
protected Void doInBackground(Void... arg0) {
//Fetch And Process Data -> Result into resultList
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Dismiss the progress dialog
final CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) getActivity().findViewById(R.id.toolbar_layout);
AppBarLayout appBarLayout = (AppBarLayout) getActivity().findViewById(R.id.appBar);
progressBar.setVisibility(View.GONE);
//Updating parsed JSON data into ListView
mItemsAdapter = new SimpleAdapter(
getActivity(), mItemList,
R.layout.list_item, new String[]{"brand", "price",
"dist", "street", "houseNumber", "postcode", "place"}, new int[]{R.id.brand,
R.id.price, R.id.dist, R.id.street, R.id.houseNumber, R.id.postCode, R.id.place});
mItemList.addAll(resultList);
mItemsAdapter.notifyDataSetChanged();
}
}
}
In the following method from MainActivity, you try to pass the location data to an instance of FragmentB:
public void start() {
//Location data fetched here
FragmentB fb = new FragmentB();
fb.start(lat, lon);
}
The resulting crash is due to the fact that you only instantiate the Fragment, nothing else. Methods like onCreateView() or onAttach() will only be called if the Fragment is (about to be) added to the View hierarchy. So for this instance of FragmentB, methods like getContext() or getActivity() will return null. That's why you get NullPointerExceptions.
Make sure that you only call start() on a Fragment which has been added to the View hierarchy. Or modify the method so that it stores the location data in some appropriate structure which can be accessed from e.g. onViewCreated(), onStart() or onResume()
See the docs for more information on the Fragment lifecycle

Get information from current fragment in TableLayout

I'm using TabLayout and ViewPager.I successfully integrated it and used from fragments.This is my mainTabActivity java class
public class MainTabActivity extends AppCompatActivity {
private CustomTabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_tabs);
viewPager = (ViewPager) findViewById(R.id.viewpager);
setupViewPager(viewPager);
tabLayout = (CustomTabLayout)findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
findViewById(R.id.tab_ticket).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent(MainTabActivity.this, TicketsActivity.class);
startActivity(intent);
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}
});
findViewById(R.id.tab_main).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e("BottomClickAction","BottomClickAction");
}
});
}
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new OneWayFragment(), "ONE");
adapter.addFragment(new TwoFragment(), "ROUND");
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
Also i have custom bottom bar.Now i try to explain my problem.In my fragments contains some elements,fro example spinners,Textviews or etc.My question is:How i get information from current fragment when i click bottom bar? I mean,spinner'data information,Textview's gettext or etc.
How i can solve my problem? Is it a possible to don't use static variables ?
You can find the fragment OneWayFragment in viewpager like this:
public OneWayFragment getOneWayFragment() {
return (OneWayFragment) getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + R.id.viewPager + ":" + 0);
}
public TwoFragment getTwoFragment() {
return (TwoFragment) getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + R.id.viewPager + ":" + 1);
}
You can access public method from OneWayFragment or TwoFragment a get data you want.
For ex, create method getText from OneWayFragment:
public String getData() {
return tv.getText().toString();
}
And in your MainTabActivity. For ex you click button has id tab_main and you get data from OneWayFragment.
findViewById(R.id.tab_main).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.e("BottomClickAction","BottomClickAction");
OneWayFragment fragment = getOneWayFragment();
if(fragment != null) {
String data = fragment.getData();
}
}
});
Create own method like getFragmentData() in fragments. Access this method whenever you want. In your case:
1) take references of your fragment
_oneWayaFrgament= new OneWayFragment()
adapter.addFragment(_oneWayaFrgament, "ONE");
2) call _oneWayaFrgament.getFragmentData()
similarly apply your conditional logic on TwoFragment.
Please call getFragmentData() by identifying current fragment.
yes you can have public variables and methods in your fragments and then you can set and get your variables or call your methods from your activity.
for example in your fragments:
public String myString;
public Button someButton;
or
public void fillMyTextView(){//some codes};
and in your activity you can call those methods or access your views like this:
myFragment.fillMyTextView("hello");
myFragment.someButton.setText("my btn");
I would suggest you create singleton as state object(as you want as the state of the views, you can go with integer or short or byte for state marks memory wise) use as you want, and nullify once done usage. This way you can be access any data, in any fragment or activity, at any point of time. You can go with other implementations also like interface kinds as design and architectural way.But depends on the how important states are.

What is going on with my Android Navigation drawer activity?

I am building an OpenGL live wallpaper. I decided to have a Navigation Drawer in my main activity since there are a lot of features the user will have access to.
The problem/issue
If I press the "hardware" back button to normally close an app the initial fragment that is shown just refreshes and the app never closes. If I hit the home button and go back to the app everything is a black screen. I've searched all throughout Google thinking that maybe I wasn't destroying the MainActivity properly or for a way to terminate a fragment. I've tried calling finish() in the main activity's onDestroy method. I've tried utilizing the remove method from fragment manager in each fragments onDetach method per posts that I've found online. Nothing has worked. I'm stumped. I've set debug points in the main activity on the onDestroy method and on the fragments onDetach method with no error being produced or any information being given. At this point I am clueless. Here's my MainActivity class.
public class MainActivity extends AppCompatActivity implements OnNavigationItemSelectedListener, OnPostSelectedListener{
FragmentManager mFragmentManager;
FragmentTransaction mFragmentTransaction;
TextView usrTag, tagrEmail;
CircleImageView tagrPic;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
mFragmentManager = getSupportFragmentManager();
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.add(R.id.cLMain, new PreviewFragment()).addToBackStack("PreviewFragment").commit();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
View header = navigationView.getHeaderView(0);
usrTag = (TextView)header.findViewById(R.id.usrName);
tagrEmail = (TextView)header.findViewById(R.id.usrEmail);
tagrPic = (CircleImageView)header.findViewById(R.id.usrImg);
Log.i("MainActivity: ", "User Photo: " + getProfilePic(this));
usrTag.setText(getUserName(getBaseContext()));
tagrEmail.setText(getUserEmail(getBaseContext()));
GlideUtils.loadProfileIcon(getProfilePic(getBaseContext()), tagrPic);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
Fragment fragment = null;
Class fragmentClass = null;
int id = item.getItemId();
if (id == R.id.nav_home) {
fragmentClass = PreviewFragment.class;
} else if (id == R.id.nav_custom) {
startCustomLabelCreator();
} else if (id == R.id.nav_mylabels) {
} else if (id == R.id.nav_commLabels) {
fragmentClass = PostsFragment.class;
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.cLMain, fragment).commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
public void startCustomLabelCreator(){
Intent cLC = new Intent(getBaseContext(), CreateLabel.class);
startActivity(cLC);
}
#Override
public void onPostComment(String postKey) {
}
#Override
public void onPostLike(String postKey) {
}
#Override
public void onPhotoSelected(String photoUrl) {
}
#Override
protected void onDestroy() {
super.onDestroy();
finish();
}
}
My Fragments
public class PostsFragment extends Fragment implements ConfirmSelectedPhotoListener{
public static final String TAG = "PostsFragment";
private static final String KEY_LAYOUT_POSITION = "layoutPosition";
private int mRecyclerViewPosition = 0;
private OnPostSelectedListener mListener;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter<PostViewHolder> mAdapter;
public PostsFragment() {
// Required empty public constructor
}
public static PostsFragment newInstance() {
PostsFragment fragment = new PostsFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_posts, container, false);
rootView.setTag(TAG);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setReverseLayout(true);
linearLayoutManager.setStackFromEnd(true);
mRecyclerView.setLayoutManager(linearLayoutManager);
Log.d(TAG, "Restoring recycler view position (all): " + mRecyclerViewPosition);
Query allPostsQuery = FirebaseUtil.getPostsRef();
mAdapter = getFirebaseRecyclerAdapter(allPostsQuery);
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
// TODO: Refresh feed view.
}
});
mRecyclerView.setAdapter(mAdapter);
}
private FirebaseRecyclerAdapter<Post, PostViewHolder> getFirebaseRecyclerAdapter(Query query) {
return new FirebaseRecyclerAdapter<Post, PostViewHolder>(
Post.class, R.layout.post_item, PostViewHolder.class, query) {
#Override
public void populateViewHolder(final PostViewHolder postViewHolder,
final Post post, final int position) {
setupPost(postViewHolder, post, position, null);
}
#Override
public void onViewRecycled(PostViewHolder holder) {
super.onViewRecycled(holder);
// FirebaseUtil.getLikesRef().child(holder.mPostKey).removeEventListener(holder.mLikeListener);
}
};
}
private void setupPost(final PostViewHolder postViewHolder, final Post post, final int position, final String inPostKey) {
postViewHolder.setPhoto(post.getThumb_url());
Log.d(TAG, post.getThumb_url());
postViewHolder.setText(post.getText());
postViewHolder.setTimestamp(DateUtils.getRelativeTimeSpanString(
(long) post.getTimestamp()).toString());
final String postKey;
if (mAdapter instanceof FirebaseRecyclerAdapter) {
postKey = ((FirebaseRecyclerAdapter) mAdapter).getRef(position).getKey();
} else {
postKey = inPostKey;
}
Author author = post.getAuthor();
postViewHolder.setAuthor(author.getFull_name(), author.getUid());
postViewHolder.setIcon(author.getProfile_picture(), author.getUid());
ValueEventListener likeListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
postViewHolder.setNumLikes(dataSnapshot.getChildrenCount());
if (dataSnapshot.hasChild(FirebaseUtil.getCurrentUserId())) {
postViewHolder.setLikeStatus(PostViewHolder.LikeStatus.LIKED, getActivity());
} else {
postViewHolder.setLikeStatus(PostViewHolder.LikeStatus.NOT_LIKED, getActivity());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
FirebaseUtil.getLikesRef().child(postKey).addValueEventListener(likeListener);
postViewHolder.mLikeListener = likeListener;
postViewHolder.setPostClickListener(new PostViewHolder.PostClickListener() {
#Override
public void showComments() {
Log.d(TAG, "Comment position: " + position);
mListener.onPostComment(postKey);
}
#Override
public void toggleLike() {
Log.d(TAG, "Like position: " + position);
mListener.onPostLike(postKey);
}
#Override
public void savePhotoUrl() {
//mListener.onPhotoSelected(post.getFull_url());
showLabelConfirm(post.getFull_url());
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null && mAdapter instanceof FirebaseRecyclerAdapter) {
((FirebaseRecyclerAdapter) mAdapter).cleanup();
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save currently selected layout manager.
int recyclerViewScrollPosition = getRecyclerViewScrollPosition();
Log.d(TAG, "Recycler view scroll position: " + recyclerViewScrollPosition);
savedInstanceState.putSerializable(KEY_LAYOUT_POSITION, recyclerViewScrollPosition);
super.onSaveInstanceState(savedInstanceState);
}
private int getRecyclerViewScrollPosition() {
int scrollPosition = 0;
// TODO: Is null check necessary?
if (mRecyclerView != null && mRecyclerView.getLayoutManager() != null) {
scrollPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager())
.findFirstCompletelyVisibleItemPosition();
}
return scrollPosition;
}
#Override
public void onSelectedPhoto(String selectPhoto) {
mListener.onPhotoSelected(selectPhoto);
}
public interface OnPostSelectedListener {
void onPostComment(String postKey);
void onPostLike(String postKey);
void onPhotoSelected(String photoUrl);
}
private void showLabelConfirm(String uriBmp) {
FragmentManager fm = getFragmentManager();
PhotoDialogFragment editNameDialogFragment = PhotoDialogFragment.newInstance(uriBmp);
// SETS the target fragment for use later when sending results
editNameDialogFragment.setTargetFragment(PostsFragment.this, 300);
editNameDialogFragment.show(fm, "fragment_edit_name");
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnPostSelectedListener) {
mListener = (OnPostSelectedListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnPostSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
}
Second Fragment:
public class PreviewFragment extends RajBaseFragment {
#Override
public ISurfaceRenderer createRenderer() {
return new PreviewRenderer(getContext());
}
}
Which extends:
public abstract class RajBaseFragment extends Fragment implements IDisplay, View.OnClickListener {
protected FrameLayout mLayout;
protected ISurface mRajawaliSurface;
protected ISurfaceRenderer mRenderer;
public RajBaseFragment(){
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
// Inflate the view
mLayout = (FrameLayout) inflater.inflate(getLayoutID(), container, false);
mLayout.findViewById(R.id.relative_layout_loader_container).bringToFront();
// Find the TextureView
mRajawaliSurface = (ISurface) mLayout.findViewById(R.id.rajwali_surface);
// Create the loader
mRenderer = createRenderer();
onBeforeApplyRenderer();
applyRenderer();
return mLayout;
}
protected void onBeforeApplyRenderer() {
}
protected void applyRenderer() {
mRajawaliSurface.setSurfaceRenderer(mRenderer);
}
#Override
public void onClick(View v) {
}
#Override
public void onDestroyView() {
super.onDestroyView();
if (mLayout != null)
mLayout.removeView((View) mRajawaliSurface);
}
#Override
public int getLayoutID() {
return R.layout.rajawali_textureview_fragment;
}
}
I've tried all the recommendations below so far and the primary fragment that is set in the MainActivity's onCreate method still gets refreshed/reloaded when the back button is pressed rather than the app exiting/closing.
In your onNavigationItemSelected method, you are replacing the current fragment with fragment even in cases where fragment is null, which has undefined effects. You should not do that.
One fix is to replace this code block:
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
with this one:
if (fragmentClass != null) {
fragment = fragmentClass.newInstance();
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.cLMain, fragment).addToBackStack().commit();
}
(and then leave out the fragment transaction below this point).
Also, there is a call to finish in the onDestroy method, which probably is not causing the problem but should be taken out because it does not make any sense there.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
}
return true;
}
replace your onOptionsItemSelected() with mine.
Don't include your first fragment into backstack.
Try to change you fragment transaction line code without addToBackStack
as below:
mFragmentTransaction.add(R.id.cLMain, new PreviewFragment()).commit();
While adding fragment with addToBackStack, this allows back
navigation for added fragment.Because of fragment in backstack,
empty(black) activity layout will be displayed.
Change onBackPressed() as below which automatically close app after if no any Fragment found in FragmentManager:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
getSupportFragmentManager().popBackStack();
}
}
Also you can see some similar Q/A on below links which helps you get more idea to solve your problem:
Fragment pressing back button
In Fragment on back button pressed Activity is blank
Transaction of fragments in android results in blank screen
It's solved my blank screen problem. Hope its helps you.
Try this code, hope this helps you, take necessary stuffs which are required for you. Also, try running this project in Android studio, it works.
https://github.com/asifali22/Navigation_Health/blob/master/app/src/main/java/com/thenewboston/mynavigation/MainActivity.java
When user press to back button it'll check fragment manager's backstack and if backstack entity count is bigger than 0 (this means there's a fragment in backstack) it'll popBackStack else it'll finish activity.
If you add your initial fragment to backstack, when user press back button they'll see a blank screen.
Also when you init your activity if you need to put a fragment it's a best practice to check if saved instance state is null. Here i modified some part of your code.
if(savedInstanceState == null){
mFragmentManager = getSupportFragmentManager();
mFragmentTransaction = mFragmentManager.beginTransaction();
mFragmentTransaction.add(R.id.cLMain, new PreviewFragment()).commit();
}
I hope this'll help you. If you still have problem let me know.
Good luck.
create subclass for ISurface and override onKeyDown method like this
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.e("Custom View", "onKeyDown");
//return super.onKeyDown(keyCode, event);
return false;
}
Could be related with the lifecycle...
Try using GLSurfaceView. I believe is easier for what you want, is special for OpenGL rendering and there is plenty information about it. Examples, lifecycle among others. Let me know if helped. If not, please, provide more info.

how to communicate between two listfragments in a viewpager from a parent fragmentactivity

Basically I have a Fragment activity which holds two ListFragments and i use ViewPager to swipe between them.In one fragment when i long click on a listItem and select Add Phrase, it updates the database of the other listFragment but never immediately refreshes until i close the app and reopen it. I tried using the official android way of communicating between fragment, using interface in the listFragment and a callback method http://developer.android.com/training/basics/fragments/communicating.html. This is supposed to call the method that fills the data in the second ListFragment but i always get a nullPionterException. Please help me
This is the first ListFragment (BoardActivity.java, only the portion that adds the interface)
//container activity must implement this interface
public interface OnAddPhraseListener {
public void onAddPhrase(String text);
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
//make sure that the container activity has implemented the callback interface
try{
mAddPhraseCallback = (OnAddPhraseListener) activity;
}catch(ClassCastException e){
}
}
This is the second ListFragment (PhrasesActivity.java, portion that fills d ListView with data)
public void fillData(){
try {
mDbHelper = new PhrasesDbAdapter(this.getSherlockActivity()).open();
} catch (SQLException e) {
Log.e(tag, "Couldnt open mDbHelper to fill Data");
e.printStackTrace();
}
Cursor phraseCursor = mDbHelper.fetchAllPhrases();
String [] from = new String[]{PhrasesDbAdapter.KEY_PHRASE};
int [] to = new int []{R.id.phraseText};
SimpleCursorAdapter phrases = new SimpleCursorAdapter(getSherlockActivity(), R.layout.phrases_row, phraseCursor, from, to);
setListAdapter(phrases);
}
This is the MainLayoutActivity that holds the viewpager with BoardActivity and PhrasesActivity
public class MainLayoutActivity extends SherlockFragmentActivity implements OnAddPhraseListener {
public ViewPager mViewPager;
public ViewPagerAdapter mAdapter;
public com.actionbarsherlock.app.ActionBar mActionBar;
public Tab tab;
ComponentName service;
final String CLIP_CHANGED = "clipboard.clipchanged";
final String tag = "Clipboard";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
mActionBar = getSupportActionBar();
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
setUpView();
setTab();
service = startService(new Intent(this, ClipboardService.class));
}
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getSupportMenuInflater().inflate(R.menu.menu_layout, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item){
switch (item.getItemId()) {
case R.id.menu_settings:
Intent intent = new Intent(this, ClipboardPrefereneActivity.class);
startActivity(intent);
return true;
case R.id.menu_about:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void setUpView(){
mViewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new ViewPagerAdapter(getApplicationContext(), getSupportFragmentManager());
mViewPager.setAdapter(mAdapter);
mViewPager.setCurrentItem(0);
}
private void setTab(){
mViewPager.setOnPageChangeListener(new OnPageChangeListener(){
#Override
public void onPageScrollStateChanged(int arg0) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
});
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
};
tab = mActionBar.newTab().setText("Board").setTabListener(tabListener);
mActionBar.addTab(tab);
tab = mActionBar.newTab().setText("Phrases").setTabListener(tabListener);
mActionBar.addTab(tab);
}
#Override
public void onAddPhrase(String text) {
Log.d(tag, "On Add Phrase callback >>>>>>>>>>>>");
PhrasesActivity phrasesActivity = (PhrasesActivity) getSupportFragmentManager().findFragmentById(R.id.tab_phrases);
if(phrasesActivity != null){
Log.e(tag, "Got Phrases Activity to fill Data");
phrasesActivity.fillData();
}
else{
Log.e(tag, "Couldnt get Phrases Activity to fill Data");
}
}
}
The app always gets to the Log message
Log.e(tag, "Couldnt get Phrases Activity to fill Data");
Again i read about LocalBraodcastManager can i do the refresh with this? is it a better way? http://getpocket.com/a/read/156004495
Do not findFragmentByTag in ViewPager scenario as the tag is not obtainable for their own reason. Use LocalBroadcastManager instead for communicating between fragments.

Categories