I need to refresh my activity. I have bunch of question regrading the same which advice me to finish current activity and restart the current activity. OR again provide value to each widget. To avoid transition I used this code
Intent intent = getIntent();
overridePendingTransition(0, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
this.finish();
overridePendingTransition(0, 0);
startActivity(intent);
But in my case In my activity I have four tabs, and I need to refresh all four tabs.
There are few more problems regarding the same
1) With above code, if I am on other screen, I come back to this screen when above piece of code runs.
2) Activity sequence gets disturb.
3) Maintaining selected tab will also be a part of problem
Even if I try to refresh each tab seperatley, One of my tab have webview. how to refresh that as webview.loadData() can't be called unless there is view and since I am not on that tab there will no view.
What can be the ideal way to tackle this problem. Any help will be appreciated.
It depends a bit on your use case. You may setContentView() again to inflate the layout every time. If you are just displaying a list, then you may just call the adapter to display the list. You have to do this for every fragment in your TabActivity.
To reload a WebView I would just call loadUrl() again.
As to remembering the selected tab, you have to store it and then set the current tab in the TabHost.
Question was not much complicated but solution what I wanted got to be optimised. Finally I took the second way, ie refreshing each component. This approach overcomes the problem of disturbing the sequence of activity. For web view I am still using webView.loadData(...).
In total I have handeled each tab separately. If I include my entire code then it would become clumsy, but still trying to incorporate as many important feature.
In my activity class when I need to refresh my activity, I called this method.
private void onRefrash()
{
refreshCurrentActivity();
int selectedTab = getActionBar().getSelectedNavigationIndex();
switch (selectedTab)
{
case TAB1:
fragment1.update();
break;
case TAB2:
fragment2.update();
break;
case TAB3:
fragment3.update();
break;
}
Toast.makeText(this, getString(R.string.msg_case_updates_received), Toast.LENGTH_LONG).show();
}
}
Each fragment is earlier initialised, and update method is called for each tab in which I am updating the corresponding web view.
Related
I'm a beginner in Android, so I apologize for the mistakes and I'd appreciate any constructive criticism.
I'm writing a basic application with a ListView of images, and when the user clicks on an item in the list, I want to display that image in a ViewPager, where the user can swipe back and forth to browse the whole list of images. Afterwards when the user presses the back button, I want to switch back to the ListView.
I manage the business logic in the MainActivity, which uses MainActivityFragment for the ListView and ImageHolderFragment for ViewPager.
The simplified code so far is as follows:
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListItems = new ArrayList<>();
mListItemAdapter = new ListItemAdapter(this, R.layout.list_item, R.id.list_item_name, mListItems);
mListView = (ListView) findViewById(R.id.list_view_content);
mListView.setAdapter(mListItemAdapter);
mDeletedListItems = new ArrayList<>();
mViewPager = (ViewPager) getLayoutInflater().inflate(R.layout.image_display, null, true);
mImageAdapter = new ImageAdapter(getSupportFragmentManager(), mListItems);
mViewPager.setAdapter(mImageAdapter);
mViewPager.setOffscreenPageLimit(3);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mViewPager.setCurrentItem(position);
setContentView(mViewPager); // TODO: this is very wrong!
}
});
loadImages();
noContentText = (TextView) findViewById(R.id.no_content_text);
if (mListItems.isEmpty()) {
noContentText.setText(R.string.no_images);
} else {
mImageAdapter.notifyDataSetChanged();
}
}
Although this does work to some extent, meaning that it manages to display the ViewPager when an item in the list is clicked, there are two things about it ringing the alarm bells:
I've read that calling setContentView() for the second time in the same class is pretty much a sin. Nobody explained me why.
The back button doesn't work in this case. When it's pressed, the application is terminated instead of going back to the list view. I believe this is connected to the first point.
I would appreciate any help, explanations if my idea is completely wrong, and if my case is hopeless, I'd like to see a successful combination of ListView and ViewPager with transitions between each other.
Your activity already has R.layout.activity_main set as content view, which rightly displays the list view - that's what the responsibility of this activity is as you defined it. If we want to change what's shown on the screen, we should use a different instance of a building block (activity or fragment) to display the view pager images.
To say the least, imagine if you wanted to change the view to a third piece of functionality or UI, or a fourth... it would be a nightmare to maintain, extend and test as you're not separating functionality into manageable units. Fields that are needed in one view are mixed with those needed in another, your class file would grow larger and larger as each view brings its click listeners, callbacks, etc., you'd also have to override the back button so it does what you want - it's just not how the Android framework was designed to help you. And what if you wanted to re-use UI components in different contexts whilst tapping in to the framework's activity lifecycle callbacks? That's why fragments were introduced.
In your case, the list view could continue to run in your MainActivity and in your click listener, onItemClick you could start a new activity that will hold a viewPager:
Intent i = new Intent(MainActivity.this, MyLargePhotoActivityPager.class);
i.putExtra(KEY_POSITION, position);
// pass the data too
startActivityForResult(i, REQUEST_CODE);
Notice how you could pass the position to this activity as an int extra, in order for that second activity to nicely set the viewPager to the position that the user clicked on. I'll let you discover how to build the second activity and put the ViewPager there. You also get back button functionality assuming your launch modes are set accordingly, if needed. One thing to note is that when you do come back to the list View, you'd probably want to scroll to the position from the view pager, which is why you could supply that back as a result via a request code. The returned position can be supplied back to the list view.
Alternatively, you could use the same activity but have two fragments (see the link further above) and have an equivalent outcome. In fact, one of your fragments could store the list view, and the second fragment could be a fullscreen DialogFragment that stores a viewPager, like a photo gallery (some details here).
Hope this helps.
I've read that calling setContentView() for the second time in the
same class is pretty much a sin. Nobody explained me why.
Well, you kind of get an idea as to why.
When you use setContentView() to display another 'screen' you do no have a proper back stack.
You also keep references to Views (like mListView) that are not visible anymore and are therefore kind of 'useless' after you setContentView() for the second time.
Also keep in mind orientation changes or your app going to the background - you'll have to keep track of the state that your Activity was in which is way more complicated than it has to be if you have one Activity that does two different things.
You won't be arrested for doing things like you do right now, but it's just harder to debug and keep bug free.
I'd suggest using two different Activities for the two different things that you want to do, or use one Activity and two Fragments, swapping them back and forth.
If you insist on having it all in one Activity you need to override onBackPressed() (called when the user presses the back button) and restore the first state of your Activity (setContentView() again, pretty much starting all over).
I'm not so good at Android but I'm working on my project. So please forgive my ignorance.
I'm making a set of similar items with need prefenrences setting, so I made them preference fragments for each, and put those preference fragments in a viewpager, for easier use. I want to go to fragment No.1 if I clicked item No.1, then maybe fragment No.3 if I clicked on item No.3. Simply put, I want the items can link to its own preference fragment in the viewpager. The items are in MainActivity, the viewpager is in its own activity and this viewpager activity would not start as the app starts unless an item was clicked.
I learnt that viewPager.setCurrentItem(position); should be used when I want to get to a specific page of a viewpager. But my items are in MainActivity, not inside the viewpager activity. I set the viewpager as static, and put viewPager.setCurrentItem(position); inside onClick method in MainActivity, but when I click a item, the app crashes. It shows error: java.lang.NullPointerException. The app had worked fine before I dicided to link those items to their own settings, and now I really have no idea...
Could you please tell me whether it is possible to get to a specific page of a viewpager from other activity? If it is possible, how to do? Thank you so much!
Renew:
I tried to mess with the code, I changed the adapter of the viewpager into protected static MyAdapter adapter;. There was no crash then, but I always went to the first page of the viewpager, whichever item I clicked...
I think you need to pass the data to the activity.
When you call the ViewPager in the MainActivity, set a parameter.
Intent intent = new Intent(getBaseContext(), ViewPagerActivity.class);
intent.putExtra("EXTRA_PAGE", (String) position);
startActivity(intent);
Then in the start of the View Pager Activity, get the object and change the currentItem.
Bundle extras = getIntent().getExtras();
if (extras != null) {
String value = extras.getString("EXTRA_PAGE");
int position= Integer.parseInt(value );
viewPager.setCurrentItem(position);
}
Android can only have 1 visible activity at the same time, so i think it's impossible in your way.
Another approach will be the use of Fragment, but it depends on your app design and structure.
You can check more about Fragments here (Android documentation).
Hope it helps ;)
Best Regards
I have the default Android project layout in Eclipse. The current one, that comes with a "dummyText" and a switcher on top. (I selected that one during the wizard.)
I want to use the top select bar to switch screens. Between Main, and Settings, and Result.
How do I detect the current activity?
Because.. if I have a switch, like:
switch (getArguments().getInt(ARG_SECTION_NUMBER)) { ... }
It will get into an infinite loop if the current screen is the selected one on the top.
(E.g.: Value 1 = Main screen. And you open the application, and it's value 1. And it's on main screen. It will indefinitely open up the main screen again and again. If you select an other value, like 2, it will go to the proper screen, and it won't loop.)
How am I supposed to fix this?
(I'm opening the other Activity with a new Intent, and then I call startActivityForResult(...).
Update #1:
The switch went into the "DummySectionFragment", which gets created at the onNavigationItemSelected.
Which looks like this:
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment).commit();
So basically that looks right... to me. The switch is activated, the corresponding value gets sent to Dummy, and a switch could just work to launch the proper Activity. I just need to write an if statement, that IF the current Activity matches the "to-be-invoked" one, the app should do nothing.
How am I supposed to implement this?
(I know the code is a little messy, blame Google for it's sample.)
In case you are not familiar with the Google example/code I used, here it is:
https://gist.github.com/anonymous/4edaefa42dd1be96e6e4
It's the "Blank Activity" -> "Dropdown" one.
I think you'r not using the sample as intended. One way would be to put the switch in the onNavigationItemSelected and within it launch the correct fragment (instead of DummySectionFragment) according to the selected item.
So this sample is built on Fragments, you should use them for the different sections, instead of launching a new activity.
The other way would be to have the DummySectionFragment use the ARG_SECTION_NUMBER to decide which layout to inflate, and inflate different layouts for different sections. In any case launching a new activity per section is not the way this sample is supposed to work.
Edit: Here are good guides for working with fragments:
http://developer.android.com/training/basics/fragments/index.html
http://developer.android.com/guide/components/fragments.html
There are two activities.
Activity A has a button that can switch to Activity B.
Activity B also has a button that can switch to Activity A.
here is my code,
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Log.e("current", context.getClass().toString());
Log.e("changeto", tab.getTag().toString());
if(context.getClass()==tab.getTag())
return;
Intent intent = new Intent(new Intent(context,(Class<?>) tab.getTag()));
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
context.startActivity(intent);
}
I want to remove the animation when i switch the activities, but it doesn't work.
However if I remove
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
it works perfectly. Why?
Sorry for my bad English.
In the Activity that you're switching to, try using overridePendingTransition(0,0); either in onResume or in onCreate.
If you're calling startActivity in a tab switch, you're doing it wrong. Tabs are for switching views within the current activity, and switching tabs should never create navigation history. Consider switching a fragment or replacing your view hierarchy with the newly selected tab's content instead.
The more you pursue a path of switching activities for tab selection, the more you will find yourself playing whack-a-mole with subtle user experience bugs that make your app simply feel "wrong."
With your proposed implementation above, the Back button will return to the previously selected tab, breaking the, "never creates navigation history" rule. You may think that finish()ing the current Activity as you start the next can solve this, but you'll still have a host of other issues. Users expect subtle elements of state such as scroll position to persist across tabs. As of Android 4.0 there is an expectation that users should be able to swipe horizontally between tabs (http://developer.android.com/design/building-blocks/tabs.html) which you will not be able to accomplish if you are using separate activities for each tab's content.
This is only a small sample, the list just goes on. Tabs should not be used to switch between different Activities.
I have a tabhost with three tabs. Each is an activity. I would like to have a button which is in the action bar, the bar along the top with common buttons, call functions of the tab which is active.
For example, an add function which could add something different to each tab depending on what tab was present when you clicked the button.
So, I am aksing how to call a function in Activity A from the tabHost.
And if that wont work, perhaps I can update the database from the tabhost and then refresh the tab content. Would that be easier?
Thank you all for you time and support.
I used the following code within my TabActivity class to switch tab then call a public method defined in the activity of the tab:
getTabHost().setCurrentTab(0);
Activity MyActivity = this.getCurrentActivity();
MyActivity.myMethod();
Hopefully helpful to someone looking for the answer to this question.
Hi Just stumbled across this, not sure if you already found a solution?
I solved this myself recently. I was previously getting around the problem by raising a intent broadcast from the tabhost activity and receiving the broadcast within the sub tab activity. This worked for me but i was sure there is a "better" way.
A cleaner way is to achieve it with something like this:
might have something like this:
parentActivity - my "container"
activity which holds the TabHost
childActivity - my tab activity
which holds tab content and the
public method i want to call from
parentActivity
within parentActivity:
// a method used for onclick callback or whatever you need. within parentActivity (tabhost)
// this will get call huzzah() in the first tab - getChildAt(0)
onClick () {
childActivity childAct = (childActivity) getTabHost().getChildAt(0).getContext();
childAct.huzzah();
}
within childActivity:
// a public method for the parent activity to access
public void huzzah() {
Log.d("stuff", "huzzah() called");
}
Note: Another alternative i believe is to redesign to use views instead of activities in your tabs. This is a better overall alternative because IIRC memory wise you are only storing 1 activity on the stack rather than (n * tabs) number of activities
Hope that helps
Edited as per Peter O request:
I am on API 10, and this problem gave me a huge headache. I have 3 tabs, I want all of them to be aware of changes on the other. The problem I had was that once the activity for a tab is started, there seemed to be no call back so the activity understood the user switched to a different tab, and thus needed to do work to be sure its state was correct.
I found lots of answers to this problem, but none seemed to work.
The one that I finally got to work was the solution offered as #3 for this thread --but it too is confusing. I found that the getTabHost().setCurrentTab(0); does nothing; I implemented OnTabChangeListener() to call a function that used getTabHost().setCurrentTab(0); however, I found the getTabHost().setCurrentTab(0); caused the app to crash for any tab other than 0--e.g, If I chose tab B (index=1) then called getTabHost().setCurrentTab(1); the app crashed.
Using the Debugger, I found the call this.getCurrentActivity(); always returns the activity associated with the tab which the user clicked on--calling getTabHost().setCurrentTab(); did not change that fact, and caused the app to crash.
So I got rid of it and I can now call this.getCurrentActivity(), then call a method in the Actvitity class returned by that call --this lets the activity know it has to update it's state--in my case it does this using the application object.
The above way of calling the method will not work,
Here is the quick answer for the above problem:
getTabHost().setCurrentTab(0);
Activity myActivity=getCurrentActivity();
String name=((Tab1) myActivity).et1.getText().toString();
Here the above code is given in the onclick() method of the activity which has TahHost
where Tab1 is the secondactivity and et1 is the identity of the edittext in the Tab1 activity so you can get all the value of the different fields like this individually.