I develop an app for video surveillance.
I use preferences to keep cameras settings.
In preferences I create main screen with list of cameras, when user click on current item, it opens subscreen with camera name, ip, port etc.
When user entered camera settings and clicked back button to return to main screen, I need to check that user entered all necessary data - name, ip, port, usr, pwd and if one of parameters missed, the app will show toast with warning.
The question is, how can I determine that user clicked on back button?
In PreferenceFragment, onBackPressed() and onKeyDown() not work, moreover I think it's not correct use this methods in my case...
http://4pda.ru/forum/dl/post/5659206/Screen-Main.gif - Main screen
http://4pda.ru/forum/dl/post/5659204/Screen-Sub.gif - Subscreen
My code:
public class MyFragments extends PreferenceFragment {
....
#Override
public void onCreate(Bundle savedInstanceState) {
root = getPreferenceManager().createPreferenceScreen(getActivity());
setPreferenceScreen(createMyPrefenceScreen());
}
private PreferenceScreen createMyPrefenceScreen() {
for (int i=1; i<=8; i++) {
PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getActivity());
screen.setKey("screen_name_" + i);
screen.setTitle("Number " + i);
ip = new EditTextPreference(getActivity());
ip.setKey("ip_" + i);
ip.setTitle("IP ");
screen.addPreference(ip);
ip.setSummary(ip.getText());
....
root.addPreference(screen);
}
return root;
}
...
}
You have to implement onBackPressed in your Activity, not in the PreferenceFragment.
Following 2nd answer given to this question:
private final static String TAG_FRAGMENT = "TAG_FRAGMENT";
private void showFragment() {
final Myfragment fragment = new MyFragment();
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
public void onBackPressed() {
final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);
if (fragment.insertedDataIsCorrect()) { // HERE you can check for correct data and allow back pressed or not
super.onBackPressed();
}
}
Related
I have a simple problem.
My problem is that I have two activities:
Activity A
Activity B
In Activity A I display 4-5 fragments. That is the main activity (Navigation Drawer) so I display 4-5 fragments in it.
From all fragments it redirects to Activity B.
But I want to display the last opened fragment when I come back from Activity B.
Now it directly opens the first fragment, which is the default. I want to open the last opened fragment when the user returns to the first activity.
Please help me...
You can use onSaveInstanceState in Activity A to save information about last opened fragment and onRestoreInstanceState/onCreate to restore this information. For example:
private static final String LAST_OPENED_FRAGMENT_REF = "LAST_OPENED_FRAGMENT_REF";
private static final int HOME_FRAGMENT = 0;
private static final int OTHER_FRAGMENT = 1;
private int currentOpenedFragment = HOME_FRAGMENT;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
if (savedInstanceState != null) {
currentOpenedFragment = savedInstanceState.getInt(LAST_OPENED_FRAGMENT_REF);
}
if (navigationView != null) {
Fragment fragment = initFragmentByType(currentOpenedFragment);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
setupDrawerContent(navigationView);
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(LAST_OPENED_FRAGMENT_REF, currentOpenedFragment);
}
private Fragment initFragmentByType(int type) {
switch(type) {
case HOME_FRAGMENT: return new Home();
case OTHER_FRAGMENT: return new Other();
default: throw new IllegalArgumentException("There is no type: " + type);
}
}
And don't forget to update currentOpenedFragment field in onNavigationItemSelected callback.
If your first activity changes with the second one, then fragments of the former activity will destroy themself because of the activity lifecycle.
You should just open first activity using startActivity and store the last active fragment before it goes the letter activity.
You don't use finish while call second activity. For exp: `
Intent i = new Intent(getApplicationContext(), ActivityB.class);
startActivity(i);
//finish(); `
I have an activity that opens PreferenceScreen. When I click 'back' - I expect that the preference screen will be closed and I'll go back to the activity, but instead - the current activity is closed and I go back to the previous activity. How can I fix that?
public class MyActivity extends Activity {
//....
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return (new Helper()).onOptionsItemSelected_menu(item,this,mFragmentManager);
}
}
public class Helper {
// ....
public boolean onOptionsItemSelected_menu(MenuItem item, Activity activity, FragmentManager mFragmentManager)
{
switch (item.getItemId()) {
case R.id.action_settings:
MenuHelper.settings(activity, mFragmentManager);
return true;
default:
return onOptionsItemSelected_menu(item, activity, mFragmentManager);
}
}
public static void settings(Activity activity, FragmentManager mFragmentManager) {
FragmentTransaction mFragmentTransaction = mFragmentManager
.beginTransaction();
PrefsFragment mPrefsFragment = new PrefsFragment(activity);
mFragmentTransaction.replace(android.R.id.content, mPrefsFragment);
mFragmentTransaction.commit();
}
public static class PrefsFragment extends PreferenceFragment {
Activity m_activity;
public PrefsFragment(Activity activity)
{
m_activity = activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
}
Daniel's answer is totally correct, though you can achieve same thing just by adding mFragmentTransaction.addToBackStack(null) right before transaction commit.
It looks like your issue is that you're replacing the fragment in the current activity with your Preferences screen.
You will have to re-factor your code a bit, but the key is to open a new Activity for your Preferences screen instead of replacing the fragment in the current Activity. This will add a new Activity to the Back Stack for the Preferences screen, and when you click back, it will pop the Preferences Activity from the Back Stack and return you to the previous Activity as you desire.
Edit: Don't re-factor your code, just do what #GnoX suggests.
For more info, see this guide: http://developer.android.com/guide/components/tasks-and-back-stack.html
I've had a look around and found a couple of questions with a similar topic, but nothing that helped in my case.
I'm trying to access an existing active fragment using getSupportFragmentManager().findFragmentByTag(TAG), but it always returns null. Replies on similar questions suggested that it takes a while for the commit to be executed, so calling findFragmentByTag would return null if called too early. I've tried two things:
add getSupportFragmentManager().executePendingTransactions()
immediately after the commit, but still get null.
added a button... pressing this after the activity has been created,
the fragment registered and the view displayed should leave the
system enough time to commit. But i still get null.
Here's my activity:
public class MainActivity extends ActionBarActivity {
private static final String F_SETTINGS = "f_settings";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
debug();
}
});
if (savedInstanceState == null) {
FSettings newFragment = new FSettings();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, newFragment);
ft.addToBackStack(F_SETTINGS);
ft.commit();
// getSupportFragmentManager().executePendingTransactions();
//// Activating this did not make any difference...
}
debug();
}
private void debug() {
String txt = "null";
Fragment frag = getSupportFragmentManager().findFragmentByTag(F_SETTINGS);
if (frag != null) {
txt = frag.toString();
}
Log.i("Testing", txt);
}
}
What am I doing wrong here?
Cheers,
Max
In your code you haven't mentioned tag in replace method So,
Use this structure of replace method of fragment
ft.replace(R.id.container, newFragment,"fragment_tag_String");
Refer this link for more information. fragment replace with tag name
I have implemented Google Maps Android API v2 in my applcation.
Currently I have an Activity which consists of different fragments:
public class MyTravelogueActivity extends SherlockFragmentActivity {
int travelogueID;
String placeID;
boolean isTravelogue;
Bundle b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String checkStatus = "";
b = getIntent().getExtras();
if (savedInstanceState != null) {
getSupportFragmentManager().popBackStack(null, getSupportFragmentManager().POP_BACK_STACK_INCLUSIVE);
checkStatus = savedInstanceState.getString("statusCheck");
b = savedInstanceState.getBundle("bundle");
}
else {
checkStatus = (String) b.get("status");
}
setContentView(R.layout.activity_frag);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
/*
codes to add Fragment to ft
*/
ft.commit();
}
}
So this calls for my MapFragment Class...
public class TravelogueSEOPageFragment extends SherlockFragment {
//............. codes
public void Map(View view){
if(hasConnection() == true){
Bundle b = new Bundle();
b.putInt("id", travelogueID);
b.putString("currentlayoutview", currentview);
FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction();
TOnlineMapViewFragment mapfrag = TOnlineMapViewFragment.newInstance(b, place_list);
ft.replace(R.id.container, mapfrag).addToBackStack(null).commit();
}
}
}
My question is why is it that on loading the Google Maps, there is a display of black screen for awhile? When finished viewing the maps, on clicking the back button, the black screen is displayed even longer.
I'm not sure what other codes I should paste to illustrate this problem, so please let me know if I'm lacking any codes to better allow me to ask for a solution to this phenomenon.
This is described by Google as a "known limitation". See here: Issue 4639. There is an officially proposed workaround but this does not work in all situations.
I am attempting to expand my application by adding a TabHost and some tabs to navigate extra features. The current app basically searches a database. The current application workflow:
App loads to a login screen
User logs in
User gets a search form and inputs data, presses "search"
Search loads a list activity of results...
With the new tabs, there is a separate tab for searching. I want all the seach activities to remain inside that tab group. So I've created an activity group to handle all of these:
public class searchGroup extends ActivityGroup {
public static searchGroup group;
private ArrayList<View> history;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.history = new ArrayList<View>();
group = this;
View view = getLocalActivityManager().startActivity("search", new Intent(this,search.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
replaceView(view);
}
public void replaceView(View v) {
history.add(v);
setContentView(v);
}
public void back() {
if(history.size() > 0) {
history.remove(history.size()-1);
setContentView(history.get(history.size()-1));
}else {
finish();
}
}
#Override
public void onBackPressed() {
searchGroup.group.back();
return;
}
}
In my search activity's Search button onClickListener:
view = searchGroup.group.getLocalActivityManager().startActivity("search_results",new Intent(search.this, search_results.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
searchGroup.group.replaceView(view);
This is where I get the crash:
02-11 13:43:49.481: E/AndroidRuntime(1165): java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.myApp/com.myApp.search_results}:
android.view.WindowManager$BadTokenException: Unable to add window --
token android.app.LocalActivityManager$LocalActivityRecord#40543360 is
not valid; is your activity running?
However, if I uncomment a line from the search_result activity's onCreate:
new LoadSearches().execute();
no crash, but I get nothing obviously. LoadSearches() is an AsyncTask that does the heavy lifting of going out to the server and running the search string and then populating the returned data into the ListActivity in onPostExecute().
I don't quite understand why its crashing here and not normally when I switch activities. How should I tackle this? Is there a better way? I've read a little bit about Fragments but haven't done anything with it yet.
I have decided, after much pulling my hair out, to go with fragments. Some resources I found useful for converting my existing app to use Fragments and tabs:
Fragments in Android 2.2.1, 2.3, 2.0. Is this possible?
http://www.e-nature.ch/tech/?p=55
http://thepseudocoder.wordpress.com/2011/10/04/android-tabs-the-fragment-way/
I also had an issue with pass data between my activities. The way to pass data between activities using an intent/bundle doesn't really work the same but can modified slightly and still work.
The old way (passing data from Activity1 to Activity2):
Activity1
Intent myIntent = new Intent(search.this, search_results.class);
Bundle b = new Bundle();
b.putString("SEARCHSTRING", strSearch);
myIntent.putExtras(b);
startActivityForResult(myIntent, 0);
Activity2
Bundle b = getIntent().getExtras();
strSearch = b.getString("SEARCHSTRING");
Using fragments I had to create an initializer for Activity2:
public search_results newInstance(String strSearch){
search_results f = new search_results();
Bundle b = new Bundle();
b.putString("SEARCHSTRING", strSearch);
f.setArguments(b);
return f;
}
using this, the new method using Fragments:
Avtivity1
Fragment newFragment = new search_results().newInstance(strSearch);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.realtabcontent, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
Activity2 (onCreateView)
Bundle b = getArguments();
strSearch = b.getString("SEARCHSTRING");
I hope this helps someone as it was difficult for me to find all this information in one spot.