I have a tabbed activity with one of the tab has favorite movie recyclerView List. In another tab, all the movies will be shown and onclick of one movie will open the movie details Activity, where he can favorite that movie. I am only saving favorite movie's id in shared preferences. After he goes back to the favorite tab, I can fetch all the movies and display it, but for every new movie addition, fetching all the favorite items is not a good idea and maintaining the static variables for newly favorite movies and refreshing the list also not looking like a good idea.
I am thinking of using Interfaces,broadcast receiver or RxJava approach for this. But for interfaces, I can't hold the favorite tab instance in movie details activity all the time. Rxjava's Publish subject also good, but I need to maintain static reference to send event from movie details activity.
I am thinking the broadcast receivers or Rxjava approaches are the best way here. Please help me to pick the right implementation.
You can Broadcast Intent from the previous fragment after you get the response in the next fragment make sure only the next fragment/tab is loaded you can also set data in the Activity also so if any change made in the data Fragment can incorporate it and do not override destroyItem this will
help recreate fagment object again and you will get fresh data...problem will arise when
you have to make changes from you next fragment to previous fragment!
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Intent intent = new Intent("key_to_identify_the_broadcast");
Bundle bundle = new Bundle();
bundle.putString("edttext", json.toString());
intent.putExtra("bundle_key_for_intent", bundle);
context.sendBroadcast(intent);
}
and then you can receive the bundle in your fragment by using the BroadcastReceiver class
private final BroadcastReceiver mHandleMessageReceiver = new
BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle =
intent.getExtras().getBundle("bundle_key_for_intent");
if(bundle!=null){
String edttext = bundle.getString("edttext");
}
//you can call any of your methods for using this bundle for your use case
}
};
in onCreateView() of your fragment you need to register the broadcast receiver first otherwise this broadcast receiver will not be triggered
IntentFilter filter = new IntentFilter("key_to_identify_the_broadcast");
getActivity().getApplicationContext().
registerReceiver(mHandleMessageReceiver, filter);
Finally you can unregister the receiver to avoid any exceptions
#Override
public void onDestroy() {
try {
getActivity().getApplicationContext().
unregisterReceiver(mHandleMessageReceiver);
} catch (Exception e) {
Log.e("UnRegister Error", "> " + e.getMessage());
}
super.onDestroy();
}
You can create separate broadcast receivers in all of your fragments and use the same broadcast to broadcast the data to all of your fragments. You can also use different keys for different fragments and then broadcast using particular key for particular fragment.
In your case, you need to specify setOffscreenPageLimit 0, so that when you are on the second page, the first one is destroyed, and vice-versa.
So, every time you tab your listView or recylerView load again.
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(0);
Related
I have 4 Fragments and I am trying to click a button on FragmentA and call a method that changes the visibility of some views on FragmentB and populate it.
I tried an interface, but I can't seem to get it to work between 2 fragments. I can call the interface method from a fragment if I implement it in the activity, but I can't implement it in a fragment and call it in a fragment.
Is there a different way to do this? I don't think I can use the static keyword.
I am suggesting you can use broadcast receiver its, good to perform action anywhere and easy to use.
In your first fragment you can define receiver and from another fragment, you can send broadcast or action.
Example are following.
Write following code in your first fragment in which you want to update view,
private void registerReciver() {
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.getAction().equals("UPDATE_FRAG_A")) {
// here you can fire your action which you want also get data from intent
}
}
};
IntentFilter intentFilter = new IntentFilter("UPDATE_FRAG_A");
getActivity().registerReceiver(broadcastReceiver, intentFilter);
}
And In your second fragment write following code for fire action,
Intent intent=new Intent();
// Here you can also put data on intent
intent.setAction("UPDATE_FRAG_A");
getActivity().sendBroadcast(intent);
Assume that all the fragments are in the same activity.
Define a interface in FragmentA, which is a Listener
Expose what you want to do in FragmentB via a public method
Implement FragmentA's interface in the parent activity by calling the public method of FragmentB
For more inforamtion,see Communicating with Other Fragments
I have implemented application which downloads data from web and then shows it in two ActionBar.Tabs. I have one issue with it. If I switch from one tab to other one, application starts another download and while download is not finished, the app freezes. If internet connection is slow it becomes very annoying. I've decide to add ProgressDialog to app to show user that application is downloading data from web. I've added a piece of code which implements ProgressDialog to AsyncTask which performs the download, but that didn't help. I understand why that happens but can't find the way how to fix it :(
Data which will be fitted into tab is represented as instance of Fragment class. This instance after creation will be added to transaction, and only after adding mFragment object to transaction, app switches to another tab.
This is the part of tabListener code:
// ...
#Override
public void onTabSelected(Tab tab, FragmentTransaction transaction) {
if (mFragment == null) {
/*
* Creation of ParkFragment is the reason why app locks!! Because in
* ParkFragment data is being downloaded from web
*/
mFragment = new ParkFragment(mUrl, mActivity);
/*
* mFragment can't be added to transaction until downloading is
* finished, that's why app doesn't switch fast
*/
transaction.add(android.R.id.content, mFragment, mTag);
} else {
transaction.attach(mFragment);
}
}
Please, if anybody has any ideas how to implement ProgressDialog to avoid the delay in switching between tabs, share with it.
Thank you for reading.
Updated: I've read the answer to this question but didn't understand how that implementation will help me managing delays: Changing Tabs is Slow/Laggy - Using Fragments.
UPD:
public class ParkFragment extends ListFragment {
private ArrayList<Cinemas> cinema;
private CinemasAdapter cinemaAdapter;
private String url;
private Activity activity;
public ParkFragment (String cinema,Activity activ){
url = cinema;
activity = activ;
}
public void onCreate(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
cinema = new Handler().handle(url,activity);
cinemaAdapter = new CinemasAdapter(activity, R.layout.movie_data_row, cinema);
setListAdapter(cinemaAdapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Cinemas movie = cinemaAdapter.getItem(position);
Intent intent = new Intent (activity, More.class);
intent.putExtra("Cinemas", movie);
intent.putExtra("data", movie.getBitmap());
Bundle translateBundle =
ActivityOptions.makeCustomAnimation(activity,
R.anim.slide_in_left, R.anim.slide_out_left).toBundle();
startActivity (intent, translateBundle);
}
}
In your ParkFragment you can use content providers combining with loaders. Downloading data should be handled in a service, when done the service inserts data into DB via content providers. And in your fragment, the loader will load the data.
There is one app named API Demos in any Android emulators, which has several examples related to content providers/ loaders/ services… The source code of its is available in Android SDK, at: [Android SDK]/samples/android-x/ApiDemos, in which x is API level.
I just think so, but if you could share your code of ParkFragment, perhaps there would be another problem?
Edited
In your ParkFragment, you can create a ResultReceiver (available in API 3+), put it into an Intent and start a service to download/ handle the url. The service keeps the instance of the ResultReceiver, when done it sends back the downloaded data to your fragment via send(int, Bundle). A Bundle can hold primitive data types such as String, int, byte[]… For more complex data, you create a class to hold it which implements Parcelable or Serializable.
Or with Bound Services, you can call the service's methods directly from within the fragment. Note that services run on main UI thread, so to avoid of NetworkOnMainThreadException, you need something like Thread in your service.
I have 2 Tabs - Tab1 and Tab2, Tab1Activity and Tab2Activity.
I want to pass values from Tab1Actvity to Tab2Activity but dont want to start Tab2Activity.
When i try below code it gives null value:
In Tab1Activity
getParent().getIntent().putExtra("key", "value");
In Tab2Activity
String valueString=getParent().getIntent().getStringExtra("key");
System.out.println("Testing.....: "+valueString);
I really discourage you from using global variables by extending the Application class. If your application goes to the background, (e.g. due a phone call) the android system might decide to kill your application. When the call is finished your application and the activity stack will be restored, but your activity state will be lost.
I'd rather suggest you to use broadcasts to send data to another activity.
In your Tab1Activity:
Intent dataIntent = new Intent();
dataIntent.setAction("com.your.app.DATA_BROADCAST");
dataIntent.putExtra("tag", "your data");
sendBroadcast(dataIntent);
Tab2Activity:
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String yourData = intent.getStringExtra("tag");
}
};
IntentFilter filter = new IntentFilter();
filter.addAction("com.your.app.DATA_BROADCAST");
registerReceiver(receiver, filter);
You definitely want to reconsider using Activities as the content of your tabs. The more standard approach is to use one Activity that uses Tabs to only show part of the layout when a particular tab is selected.
The Android documentation has an excellent worked example, check out Hello, TabWidget.
Alternative
If for some reason you do need to use Activities, you can pass information between them by either adding values to the extras bundle within the Intent your using to open each Activity, or by extending the Application class.
By extending the Application class (and implementing it as a Singleton) you get an object that will exist whenever any of your application components exist, providing a centralized place to store and transfer complex object data between application components.
Also you can use static classes or SharedPreferences for data transfer between tabs.
the correct way is setting a static field into the activity that creates the tabs
public class greformanews extends TabActivity {
public static String JorgesysTitle;
...
...
...
so in your Activity defined in tab 1
#Override
protected void onPause() {
greformanews.JorgesysTitle = "JORGESYS =)";
super.onPause();
}
in your Activity defined in tab 2
//get value defined in Activity 1 !:)
String Title = greformanews.JorgesysTitle
I want to send data from one tab to another. The one which will receive the data contains a spinner. When that data is passed on, I want to the spinner to change its selection to the one given within the data (it'll be the same as one of the spinner items).
Any ideas how I can use Bundle to do this?
is this in same activity or in a new activity ?
Same activity:
make an onClickListener and change the items in the spinner.
New Activity:
use
Inten intent = new Intent(yourclassname.this, targetClassname.class);
intent.putExtra("ID",DATA);
this.startActivity(intent);
it would help if you provide some code, but for now I hope this helps
As option make array holding data for a spinner static and then create a static method in you destination activity something like this:
public static void setSpinnerData (String[] data) {
spinnerData = data;
}
Then call something like this YourActivity.setSpinnerData (myArray);
Alternativerly you can consider saving data to the application object which is the same for all activities.
You may send the data (something small like a string or an ID) using a broadcast.
In the tab where the data is generated
final Intent i = new Intent(IConstants.UPDATE_SPINNER);
i.putExtra(IConstants.DATA_UPDATE, data);
this.sendBroadcast(i)
IConstants.UPDATE_SPINNER and DATA_UPDATE are just Strings used to identify your message by the receiver. You may also put them in your main activity instead of the interface I used.
In the tab with your spinner, declare an inner class for a broadcast receiver, it can access the spinner of the outer class.
private final class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if( IConstants.UPDATE_SPINNER.equals(intent.getAction()) ) {
final String data = intent.getIntExtra(IConstants.DATA_UPDATE, "");
// update your spinner
return;
}
// process other messages ...
}
}
Register the broadcast receiver like this, e.g. in onCreate() or onResume()
this.broadcastReceiver = new MyBroadcastReceiver();
final IntentFilter f = new IntentFilter(IConstants.UPDATE_SPINNER);
// for more actions you can add them like this:
// f.addAction(IConstants.UPDATE_ONOTHER_WIDGET);
this.registerReceiver(this.broadcastReceiver, f);
Remember to unregister in onDestroy() or onPause().
Another option would be to use a handler and send messages to the handler. However, you would need the handler, which is located in the receiver, to be accessible in the sender. This way your fragments or activities (the tabs) would be stronger coupled.
I got list of checked contacts.However, i need to pass these selected contacts to another activity and display in edit Text.Please help.Thanks
You have a few solutions...
You can use static fields in your Java classes
You can pack the data into Intents via Intent.putExtra
Option (1) is probably going to be the easiest and quickest if you are trying to send data between your own activities. Option (2) is what you must do if you wish to send data to Activities of another applications.
I suggest you read these Q&A first though as some cover this question in more depth...
Passing data of a non-primitive type between activities in android
Passing data between activities in Android
Switching activities/passing data between activities
You have to use an Intent to do so.
Example, to pass the data to an activity already running:
public void sendToActivity(Object data){
Intent i = new Intent("SEND_DATA");
i.putExtra("data", this.catchReports.get(data));
sendBroadcast(i);
}
Then, you have to setup a listener in your receiving activity to catch the Broadcasted signal:
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Sets the View of the Activity
setContentView(R.layout.activity_layout);
registerReceiver(new CustomReceiver(this), new IntentFilter("SEND_DATA"));
}
With the following customreceiver:
public class CustomReceiver extends BroadcastReceiver {
private MyActivity activity;
public ReceiverEvent(MyActivity activity) {
this.activity = activity;
}
public void onReceive(Context context, Intent i) {
this.activity.doWhateverWithYourData(i.getParcelableExtra("newEvent"));
}
}
Note that if you want to transport Objects other than integers, floats and strings, you have to make them Parcelable.