How can I update ListView in the other Fragment?
public class ChooseCS extends FragmentActivity {
final private Context context = this;
private HashMap<String, List<String>> mCitiesStreets = null;
private View rootViewStreetChangeFragment = null;
private SimpleAdapter adapter;
...
private static final int NUM_PAGES = 3;
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
...
and two Fragments
public class CityChangeFragment extends Fragment {
and
public class StreetChangeFragment extends Fragment {
...
mMapDataAdapter.put("streets", fillcities);
adapter = new SimpleAdapter(
rootViewStreetChangeFragment.getContext(),
mMapDataAdapter.get("streets"), R.layout.grid_streets_4_7,
from, to);
mDataListViewStreets.setAdapter(adapter);
...
I need make update ListView in StreetChangeFragment from CityChangeFragment where I doing changing data
You can use LocalBroadcastManager to achieve this.
In your StreetChangeFragment write below code
#Override
public void onCreate(Bundle savedInstanceState) {
...
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-event-name".
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("custom-event-name"));
}
// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onDestroy() {
// Unregister since the activity is about to be closed.
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onDestroy();
}
And use below method to send broadcast message from CityChangeFragment to StreetChangeFragment
private void sendMessage() {
Log.d("sender", "Broadcasting message");
Intent intent = new Intent("custom-event-name");
// You can also include some extra data.
intent.putExtra("message", "This is my message!");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Note: You can pass data using intent (here you can position also on which you want to update data in listview)
You can check below link to learn more about LocalBroadcastManager
https://developer.android.com/reference/android/support/v4/content/LocalBroadcastManager.html
Interface is good idea,The idea is basically to define an interface and let the activity implement that interface.
Once it has implemented that interface, you could do anything you want in the method it overrides.
There is a good tutorial on Simple Developer Blog how to do exactly this kind of thing.
And you need t declare a method in fragment and it can be executed from the activity by getting the fragment instance from adapter like
Fragment fragment= mPagerAdapter.getItem(int positon);
((StreetChangeFragment )).updateList();
in StreetChangeFragment declare method and do what else you want, Thank you
Related
I have a ViewPager with two tabs which holds fragment. Inside the first fragment, I have a Gridview which is being populated with Sqlite Db.
I have an custom alertdialog in my Activity, which is the parent of the Fragments.
When the alertdialog closes, it either adds/removes/updates the Sqlite Db:
DataBaseHelper dbh = DataBaseHelper(this);
...
positiveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dbh.addVal(new TheData(editName.getText().toString(), editAge.getText().toString())); //adds a row to the Sqlite Db
dialog.dismiss();
//on dismiss, refresh the Fragment, which in turn will display the updated GridView.
}
});
...
How can I update complete the following:
//on dismiss, refresh the Fragment, which in turn will display the updated GridView.
You could use Intents and Intent Filters with a Broadcast Receiver
for this.
Create a BroadcastReceiver instance in the fragment where you want to update the data.
Create an IntentFilter and set an action string (maybe 'db.update') to it and register it with your application context (you could do this via your fragment by calling getActivity().getApplicationContext().registerReceiver(receiver, filter).
In your AlertDialog, after you update your database, create an Intent with the same action string you set above (in our case, 'db.update') and use context to send it out (getActivity().getApplicationContext().sendBroadcast(intent)). Your BroadcastReceiver's onReceive() method would be called in your fragment and you can call the method to refresh or reload your data there. See sample code below:
Say this is your fragment
public class YourFragment extends Fragment {
private GridView mGridView;
private BaseAdapter mAdapter;
private BroadcastReceiver mReceiver;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//inflate view as usual
View view = inflater.inflate(R.layout.yourlayour, container, false);
...
//create instance of broadcast receiver
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) { //when intent is receiver, this method is called
if(intent.getAction().contentEquals("db.update")){
//update intent received, call method to refresh your content loader
refreshFragment();
}
}
};
//create a new intent filter
IntentFilter mDataUpdateFilter = new IntentFilter("db.update");
//register our broadcast receiver and intent filter
getActivity().getApplicationContext().registerReceiver(mReceiver, mDataUpdateFilter);
return view;
}
#Override
public void onDestroy() {
super.onDestroy();
//never forget to unregister the receiver when you're done, it could cause your app to crash
//if it receives an intent and calls null pointing methods in your code
getActivity().getApplicationContext().unregisterReceiver(mReceiver);
} }
Then in your AlertDialog as you did above, send the intent to this receiver by:
DataBaseHelper dbh = DataBaseHelper(this);
...
positiveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dbh.addVal(new TheData(editName.getText().toString(), editAge.getText().toString())); //adds a row to the Sqlite Db
//Create an intent with our action
Intent updateIntent = new Intent("db.update");
//send the intent by
getContext().getApplicationContext().sendBroadcast(updateIntent);
dialog.dismiss();
}
});
...
Don't forget to unregister your broadcast receiver when your fragment is destroyed. Call getActivity().getApplicationContext().unregisterReceiver(receiver); in your onDestroy() method.
I should also point out that the onReceive() method of your broadcast receiver would always be called on the main thread, even if you send your intent from a background thread.
Here is a trick that i use to access Fragments inside a ViewPager
in my custom viewPagerAdapter, i add two methods
public class CustomViewPagerAdapter extends FragmentPagerAdapter {
.....
private String getFragmentTag(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
//mFragManager is a reference to FragmentManager
public Fragment getFragmentByTag(int containerId, int position) {
return mFragManager.findFragmentByTag(getFragmentTag(containerId, position));
}
}
then in your activity or wherever you can access the customViewPager
YourFragment frag = (YourFragment) customViewPager
.getFragmentByTag(YouViewPager.getId(), position);
after that, add a method in YourFragment refreshData (if you like the name!) and in it refresh the grid
Hope this help
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(frag).attach(frag).commit(); //frag is my Fragment instance...
Each time the dialog closed and it did the trick... simple and easy!
The application that I'm working on has an activity with three fragments. Each fragment needs to show some data that is received from an IntentService.
Fragment 1 - the icon, the name and the description
Fragment 2 - a list of articles
Fragment 3 - a list of items
public class Activity extends SherlockFragmentActivity implements Actionbar.Tablistener
{
public void onCreate(..) {
....
performSearch();
setupTabs(); // 3 tabs are setup, their clicks and swipes init'ed
...
}
#Override
public void onResume() {
IntentFilter intentFilter = new IntentFilter(SearchRequestReceiver.ACTION);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
searchRequestReceiver = new SearchRequestReceiver(this);
registerReceiver(searchRequestReceiver, intentFilter);
}
#Override
public void onPause() {
unregisterReceivers();
}
...
public void performSearch() {
Intent intent = new Intent(this, SearchRequest.class);
intent.putExtra("searchTerm", this.searchTerm); // declared and initialised earlier
startService(intent);
}
...
}
What is the best way for me to push this data from my receiver to my fragments or am I approaching this the wrong way? I didn't use AsyncTasks because I wanted to decouple my services from the context or was that the wrong decision?
An EventBus is one of the neatest solutions in this situation. EventBus and Otto are both very easy to use.
An example using Otto...
Your IntentService
new Handler(Looper.getMainLooper()).post(new Runnable() {
bus.post(new DataLoadCompleteEvent());
});
Note the necessity to post the event on Android's main thread with Otto. In this case, a DataLoadCompleteEvent could contain whatever you wanted.
Your Fragment
#Subscribe public void onLoad(DataLoadCompleteEvent event) {
//Do stuff with event
}
Just make sure your Fragments register on the bus in their onResume(), and unregister in their onPause().
I've managed to get it working by having the different receivers within my fragments but it seems like an awful lot of repetition.
public class FragmentName extends SherlockFragment
{
private SearchRequestReceiver searchRequestReceiver;
..
public class ServiceRequestReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
}
Is there a better way?
I searched all over the web, couldn't find a good reference on how to call fragment from another fragment.
Fragment A -> Fragment B (fragment A calls fragment B after 3 seconds)
Well, first of all you need to consider that it's a very bad idea to keep somehow a direct reference from FragmentA to FragmentB. Why:
FragmentB may be recreated and you may keep a reference to an older reference of FragmentB. So you have a memory leak.
FragmentB may be not created, added or visible. So you would have a null/unusable reference.
For this reason you need to consider methods that base on sending messages from FragmentA to FragmentB. I see several options:
Send a broadcast message using a custom action from FragmentA. FragmentB registers itself as a receiver for this kind of message (in onCreate/onResume/onAttach and de-register in onDestroy/onPause/onDetach) and when the message arrives it can handle it. This is very suitable if you have no data to send from FragmentA to FragmentB or if you do these are primitive types or easy-to-implement Parcelables. Here's an example:
Have this in FragmentA:
private void sendMessageToFragmentB(String someData) {
Intent messageIntent = new Intent("com.your_package.A_TO_B_ACTION");
messageIntent.putExtra("DATA_VALUE", someData);
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(messageIntent);
}
While in FragmentB you could have this:
public class FragmentB extends Fragment {
private BroadcastReceiver messagesFromAReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if ("com.your_package.A_TO_B_ACTION".equals(intent.getAction())) {
String dataFromA = intent.getStringExtra("DATA_VALUE");
dataFromAReceived(dataFromA);
}
}
};
protected void dataFromAReceived(String data) {
// here you have the data
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
IntentFilter messageFromAIntentFilter = new IntentFilter("com.your_package.A_TO_B_ACTION");
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(messagesFromAReceiver,
messageFromAIntentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(messagesFromAReceiver);
}
}
Use the hosting activity as a proxy: The host activity implements some kind of interface defined in FragmentA and when requested it can search if it can find FragmentB and if so call some method in there. The advantage is that you can send any data, no matter its weight. The base idea is descrived in Android dev articles. To exemplify, you could have FragmentA as:
public class FragmentA extends Fragment {
public static interface CallerProxy {
public void sendCustomMessage(Object... dataParams);
}
private CallerProxy proxyActivity;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof CallerProxy) {
this.proxyActivity = (CallerProxy) activity;
}
}
#Override
public void onDetach() {
super.onDetach();
this.proxyActivity = null;
}
private void sendMessageToFragmentB(String someData) {
if (proxyActivity != null) {
// send whatever data
proxyActivity.sendCustomMessage(new Integer(1), new Object());
// or don't send anything ...
proxyActivity.sendCustomMessage();
}
}
}
The proxy activity would have at least these methods and signature:
public class MyProxyActivity extends FragmentActivity implements CallerProxy {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// call setContentView and then make sure you've added FragmentA and
// FragmentB.
}
#Override
public void sendCustomMessage(Object... dataParams) {
// FragmentB must be identified somehow, either by tag,
// either by id. Suppose you'll identify by tag. This means you've added
// it previously with this tag
Fragment fragment = getSupportFragmentManager().findFragmentByTag("FragmentB-TAG");
if (fragment != null) {
FragmentB fragB = (FragmentB) fragment;
fragB.dataFromAReceived(dataParams);
}
}
}
While in FragmentB all you need is a method that can be called with above sent parameters:
public void dataFromAReceived(Object ... data) {
// here you have the data
}
Use or implement some sort of event bus. Some general details here. For Android I remember that Otto event bus was very handy and easy to use. Here's a link with this. This is very similar to first option as you need anyway to register and un-register.
In the end it depends on what you need to send as a message, when should it be received and how flexible does it need to be. ... your choice!
Enjoy programming!
Fragments are not supposed to connect to each other directly, that may be your problem in finding a decent guide to do this.
Your approach makes the assumption that a fragment B will always be reachable (and ready) for a fragment A to interact, and that is actually not true, will kill the flexibility of your Fragment and will cause you problems in the future.
A better approach to interaction of Fragments is to talk only through interfaces that talk directly to a activity that can handle who is alive when where and should receive what.
-> http://developer.android.com/training/basics/fragments/index.html
This Android guide above, specifically on the last topic, shows you how to do this.
i hope this code help you..
in your first fragment add this code
onCreateView
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getActivity());
IntentFilter intentFilter = new IntentFilter("update");
// Here you can add additional actions which then would be received by the BroadcastReceiver
broadcastManager.registerReceiver(receiver, intentFilter);
#Override
public void onDestroyView() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
super.onDestroyView();
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null && action.equals("update")) {
// perform your update
getOngoingOrderData();
}
}
};
in your second fragment add this code where you send broadcast..
Intent intent = new Intent("update");
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getActivity());
broadcastManager.sendBroadcast(intent);
I have an app that downloads data which must be displayed within the fragments of a viewpager. I dont know how to call the ListFragment adaptername.notifyDataSetChanged() in the AsyncTask that does the data download.
For example say i am downloading the temperature forecast for the next seven days:
my app has the following structure:
MainActivity: Starts an AsyncTask to download the data in onCreate() and gives the user choice (button) of which day to look at. Clicking the button launches SecondActivity and passes the day index to the ViewPager (to set the current view).
SecondActivity: Contains a ViewPager that contains 7 of the same ListFragments (The list display the temperature over a period of 5 hours, so the list has 5 entries).
MyListFragment: when this loads it sets the adapter to display each temperature (If the data is downloaded) otherwise it sets the temperature to "loading..."
Now my problem is, if the user waits on the MainActivity until the data downloads they can then proceed to the ViewPager to see the ListFragment temperatures without problem. But if they try click a day and load the ViewPager before the download completes the fragments will forever just say "loading..."
I need a way that I can reload the adapter within the ListFragment from the onPostExecute() of my AsyncTask in MainActivity. To do this though i need to be able to actually access the ListFragment that the ViewPager is displaying. How do update the adapter onPostExecute()?
MainActivity:
protected void onCreate(Bundle savedInstanceState) {
...
new LoadData().execute();
}
protected class LoadData extends AsyncTask<String, Void, String> {
protected String doInBackground(String... params) {
//Download happens here
}
protected void onPostExecute(String result) {
//I need to tell the viewpager in SecondActivity to reload the ListFragment it is currently showing here
}
}
SecondActivity
private ViewPager mPager;
private PagerAdapter mPagerAdapter;
private int[] temperatureArray;
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = getIntent();
int[] defaultTemps = {0, 0, 0, 0, 0};
temperatureArray = getIntArrayExtra("temps", defaultTemps);
mPager = (ViewPager) findViewById(R.id.pagerID);
mPager.setCurrentItem(intent.getIntExtra("page", 0));
mPagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
}
private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
...
public Fragment getItem(int position) {
MyListFragment lf = new MyListFragment();
lf.setTemperatures(temperatureArray);
return lf;
}
}
I need a way to be able to refresh the current displayed fragment when i finish downloading in the AsyncTask.
I can suggest doing one of two things, not sure if these are best practices.
You can Have the AsyncTask send a broadcast with a unique action when it has finished loading the information. That would of course have to be done from OnPostExecute:
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (result != null) {
//_Do whatever action you normally do, like storing result to database.
//fire up the broadcast
Intent intent = new Intent(Home.ACTION_FEED_LOADING_FINISHED);
mContext.sendBroadcast(intent);
}
}
And then intercept that via a BroadcastReceiver on your Fragment's code.
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_FEED_LOADING_FINISHED)) {
//The AsyncTask Finished loading data
}
}
};
Once the event is received, since the BroadcastReceiver is in the Fragment, where the views are loaded, you can refresh your UI accordingly.
Or,
You can pass the View you want to refresh as a paremeter on your AsyncTask.
Imagine your AsyncTask class like this:
private static class getInternetStuffTask extends AsyncTask<String, Void, Void> {
Then you can create a custom constructor to receive the view as paremeter:
public getInternetStuffTask (final Context context, final ListView list) {
this.mContext = context;
this.mListView= list;
}
Then, during onPostExecute, when data is loaded, you can simply set the adapter to the ListView directly form the AsyncTask.
You're touching on two different problems. First, use a Service for downloading. Services are there for long running operations (like a download) that live outside an Activity's lifecycle.
Second, to communicate between Activities and Fragments you'll want to use an callback interface. The link provided is to the docs which do an excellent job of explaining and providing samples.
I currently have a tabhost with 5 tabs. Over one of the tabs I have an ImageView that when the tabs are created it pulls data via POST to display a number. I am wondering how from one of the tab activities (say Rate.java) I could call that method to update that ImageView that is over one of the tabs.
I know it's not very specific but I think I wrote it so you know what I am talking about.
Let me know if you require anymore info.
talitore
Based on the information given, two options that immediately come to mind are:
Send a broadcast from the tab activity (e.g. Rate.java) and have the activity hosting the ImageView listen for it.
Create some sort of BaseActivity (extending Activity) that takes a custom Listener interface with an update method. Have your tab activities extend that BaseActivity and the activity with your ImageView implement it. You can then call the update method on the listener from your tab activities (instantiate them as a BaseActivity and pass along the listener) and make the activity with the ImageView act upon it.
//Edit per request:
A good starting point for information about broadcasts and receivers is the documentation for the BroadcastReceiver. In your case it's probably easiest to just create them in code.
A minimal example will contain something like the following:
BroadcastSendingActivity:
public class BroadcastSendingActivity extends Activity {
public static final String UPDATE_IMAGEVIEW = "UPDATE_IMAGEVIEW";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sender);
Intent i = new Intent();
i.setAction(UPDATE_IMAGEVIEW);
sendBroadcast(i);
}
}
BroadcastReceivingActivity:
public class BroadcastReceivingActivity extends Activity {
private BroadcastReceiver mReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.receiver);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver();
}
#Override
protected void onResume() {
super.onResume();
registerReceiver();
}
private void registerReceiver() {
if (mReceiver == null) {
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BroadcastSendingActivity.UPDATE_IMAGEVIEW)) {
// code to update imageview...
}
}
};
}
getApplicationContext().registerReceiver(mReceiver, new IntentFilter(BroadcastSendingActivity.UPDATE_IMAGEVIEW));
}
private void unregisterReceiver() {
if (mReceiver != null) {
getApplicationContext().unregisterReceiver(mReceiver);
}
}
}
Note that I did not test the code, but I'm sure you'll be able to figure out any mistakes I might've made. :)