I'm working in an app where I have just implemented the ViewPager. I was first working with tabs but when I made the change to ViewPager I started having an issue with the data transfer from Activity to fragments.
I finally found this post where this issue was explained and where recomends to use LocalBroadcastManager to send data from Activity to Frament when using ViewPager. I have implemented this code and works fine:
Fragment1.java
public class Fragment1 extends Fragment {
public static final String ACTION_INTENT = "fragment1.action.BOX_UPDATE";
/*Register the receiver*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION_INTENT);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(ActivityDataReceiver, filter);
}
/*Broadcast Receiver*/
protected BroadcastReceiver ActivityDataReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION_INTENT.equals(intent.getAction())) {
String text = intent.getStringExtra("TEXT");
witeOnBox(text);
}
}
};
/*Method which changes the text with the icoming value*/
public void witeOnBox(String text) {
tv_log.setText(text);
}
/*Unregister receiver*/
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(ActivityDataReceiver);
super.onDestroy();
}
Now, in MainActivity I send the data to the fragment this way:
protected void sendValueToFragment1(String text) {
Intent intent = new Intent("fragment1.action.BOX_UPDATE");
intent.putExtra("TEXT", text);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Now I need to send other data from MainActivity to the same Fragment1, and my question is, how do I manage in the fragment the incoming of another intent?
Do I have to create another BroadcastReceiver to manage a new Intent, or can I manage a new intent in the same BroadcastRecevier? I see that I can check using an if inside the onReceive() method of the BroadcastReceiver for the incoming intent filter, but If I declare two diferent intent filters in the same fragment, how do I asign them to the BroadcastReceiver?
I finally solved adding an Action to the previously defined IntentFilter:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION_INTENT);
filter.addAction(ACTION_INTENT2);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(ActivityDataReceiver, filter);
}
Then in the BroadcastReceiver I manage the incoming actions:
protected BroadcastReceiver ActivityDataReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION_INTENT.equals(intent.getAction())) {
//Do
}
if(ACTION_INTENT2.equals(intent.getAction())) {
//DO
}
}
};
Much better ways than using broadcast receiver,
Fragment frag = getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + mPager.getCurrentItem());
if(frag!=null && mPager.getCurrentItem()==1){
((Fragment1) frag).setText(text);
}
If you navigate to the Fragment after this has been called you can have it get the variables from the Activity using getActivity();
Related
I want to update an Activity which is not the MainActivity.
So I start a second Activity via a onClick method in MainActivity.
Now the Activty "SecondActivity" is at front.
When I started a Thread in the "MainActivity" how can I reference to the "SecondActivity" to update their TextViews and so on?
PseudoCode
public class activity_MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThreadSome threadSome= new ThreadSome();
threadSome.start()
}
onClick(View View){
Intent intent = new Intent(this, activity_Second.class);
startActivity(intent);
}
}
Inside Thread
public class ThreadSome extends Thread {
#Override
public void run() {
//This is what I don't know, so I just write what I want to do.
// I know the following Code is wrong and not working.
activity_Second.someTextView.setText("Hi");
}
}
Is a WeakReference the best way to do this, or better work with static TextView objects? How would you solve this problem?
Based on your description, I think you want to do something where there will be some ui change in activity stack based on some event performed in the forground activity. There is a good way to use onActivityResult() via startActivityForResult() but if this is not fullfilling your requirement directly then you can try something like below:
/**
UpdateActivity is the activity where some ui update or action will be taken based on event in EventActivity.
**/
public class UpdateActivity extends Activity {
private BroadcastReceiver mReceiver;
public static final String ACTION_UPDATE = "com.my.internal.activity.action";
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update);
......
//Prepared Intent for broadcast receiver
IntentFilter intentFilter = new IntentFilter(ACTION_UPDATE);
//registering our receiver
this.registerReceiver(mReceiver, intentFilter);
.....
}
//This is the receiver section where you need to do the ui update
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//extract our message from intent
String some_msg = intent.getStringExtra("msg_1"); //parameter received if passed in intent when broadcast called.
//log our message value
Log.i("Message", some_msg);
updateActivityUi();
}
};
private void updateActivityUi() {
// you need to write the code for the update which you want to do after an event done in other activity.
}
#Override
protected void onDestroy() {
super.onDestroy();
//unregister our receiver
this.unregisterReceiver(this.mReceiver);
}
}
public class EventActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
......
//Sending BroadcastReceiver against the action ACTION_UPDATE and it will be received by UpdateActivity.
if(condition_for_event) {
Intent i = new Intent(UpdateActivity.ACTION_UPDATE).putExtra("msg_1", "Hey! an event performed here.");
this.sendBroadcast(i);
}
.....
}
....
}
Let me know if it solved your issue.
Send data from Activity to Fragment in Android using BroadcastReceiver. I know there is varies way to communicate Activity to Fragment.
But i don't know how to send data and receive using BroadcastReceiver.
From your Activity
Intent intent = new Intent("KEY");
sendBroadcast(intent);
In your fragment
private BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUi();
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(mNotificationReceiver, new IntentFilter("KEY"));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mNotificationReceiver);
}
I have a serious issue about passing data from BroadcastReceiver to an Activity. Let see my issue carefully. I have a class PhoneStateReceiver extends BroadcastReceiver that used to received an incoming phone.
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
}
}
catch (Exception e){
e.printStackTrace();
}
}
}
The incoming phone will be sent to an Activity, called ReceiverActivity. The ReceiverActivity receives the incoming phone and sends it to a server via a socket connection. The socket connection is initialized in the onCreate function. I googled and found server way to pass the data from BroadcastReceiver to an Activity. The common way is that send data via putExtra function and call startActivity. However, the way will call the onCreate again and then connect the socket, draw the UI again. Thus, it is not helpful in my case.
In my goal, If the phone receives an incoming call, it will send the incoming call to the ReceiverActivity. The ReceiverActivity receives the message and calls the send function. Which is the best way to do it? Thank you
The common way to pass data from a BroadcastReceiver to a ReceiverActivity that I used as follows
In PhoneStateReceiver class :
Intent intent_phonenum = new Intent(context, ReceiverActivity.class);
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent_phonenum.putExtra("phone_num", incomingNumber);
context.startActivity(intent_phonenum);
In ReceiverActivity class :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connect_socket();
Intent intent = getIntent();
phone_num = intent.getStringExtra("phone_num");
send(phone_num);
}
Simple without any third party libs.
Make sure BroadcastReceiver must be registered and also unregistered on OnPause().
You have to do two thing
Register a receiver in you activity like below.
public class MainActivity extends Activity {
Context context;
BroadcastReceiver updateUIReciver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
IntentFilter filter = new IntentFilter();
filter.addAction("service.to.activity.transfer");
updateUIReciver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//UI update here
if (intent != null)
Toast.makeText(context, intent.getStringExtra("number").toString(), Toast.LENGTH_LONG).show();
}
};
registerReceiver(updateUIReciver, filter);
}
}
Now in you service
public class PhoneStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
System.out.println("Receiver start");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Intent local = new Intent();
local.setAction("service.to.activity.transfer");
local.putExtra("number", incomingNumber);
context.sendBroadcast(local);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
There is a very simple design pattern you can use here to ease communication between your classes and also decouple your code: publisher/subscriber. My favorite library for this is EventBus:
First, add to your build.gradle file:
compile 'org.greenrobot:eventbus:3.0.0'
Then, create a simple POJO - Plain Old Java Object like this:
public class OnReceiverEvent{
private String phoneNumber;
public OnReceiverEvent(String phone){
this.phoneNumber = phone;
}
public String getPhoneNumber(){
return phoneNumber;
}
}
Next, by making your Receiver class a publisher, and your Activity a subscriber, you should be able to easily pass the information to your activity like this:
//inside your PhoneStateReceiver class when you want to pass info
EventBus.getDefault().post(new OnReceiverEvent(phoneNumber));
Next, inside your activity, simply do this:
//onStart
#Override
public void onStart(){
super.onStart();
EventBus.getDefault().register(this);
}
//onStop
#Override
public void onStop(){
super.onStop();
EventBus.getDefault().unregister(this);
}
Finally, handle the posted data i.e phoneNumber value:
#Subscribe
public void onPhoneNumberReceived(OnReceiverEvent event){
//get the phone number value here and do something with it
String phoneNumber = event.getPhoneNumber();
//display or something?
}
UPDATE
If you have another Event that you want this activity to subscribe to, simply create a method like you did in the first one using the #Subscribe annotation.
#Subscribe
public void onSomeOtherEvent(EventClassName event){
//get the variables here as usual;
}
This is the easiest way to pass the data from your receiver to your activity without having to worry about starting the activity over and over!
I hope this helps and good luck!
So I understand you don't want to recreate your Activity everytime.
In your Intent changing this flag will help you :
intent_phonenum.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
In Intent class if you read method summary of FLAG_ACTIVITY_CLEAR_TOP:
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that activity,
all of the other activities on top of it will be closed and this Intent
will be delivered to the (now on top) old activity as a new Intent. (you can read more ...)
In this case: If your app is running and you have an Activity instance then Intent will not recreate your Activity. But assume that your app is in closed state and when BroadcastReceiver triggered, the Intent will create new Activity because you don't have instance of that Activity.
#Edit :
You can specify special Intent like that in your BroadcastReceiver:
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
Intent i = new Intent("mycustombroadcast");
i.putExtra("phone_num", incomingNumber);
context.sendBroadcast(i);
}
Then in your Activity inside onCreate() register receiver like that :
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
int incoming_number= bundle.getInt("phone_num");
Log.e("incoming number", "" + incoming_number);
}
};
//then register receiver like that :
registerReceiver(broadcastReceiver, new IntentFilter("mycustombroadcast"));
You can unregister Receiver in onDestroy() : unregisterReceiver(broadcastReceiver);
Also another way is overriding onNewIntent() in your Activity:
#Override
protected void onNewIntent(Intent intent) {
//your intent is here, you can do sth.
super.onNewIntent(intent);
}
I have a question about updating my ListView in ListFragment from my Map fragment. Each time I will call this method I will assign different values to String Array. And what should I put into that Update method to refresh the listview ?
In ListFragment create and register BroadcastReceiver :
static final String ACTION_CUSTOM = "action";
BroadcastReceiver mReceiver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new BroadcastReceiver(){
public void onReceive(android.content.Context context, Intent intent) {
//Check for action you need
if (intent.getAction() == ACTION_CUSTOM ){
//Do stuff with data from intent
intent.getExtras().getString("data");
}
}
};
}
#Override
public void onResume() {
super.onResume();
getActivity().registerReceiver(receiver, new IntentFilter(ACTION_CUSTOM ));
}
#Override
protected void onPause() {
super.onPause();
getActivity().unregisterReceiver(receiver);
}
In MapFragment send broadcast intent, when you need to change data:
Intent intent = new Intent();
//Set action you need to send
intent.setAction(ACTION_CUSTOM);
//Add data to send
intent.putExtra("data", "data_value");
//Send broadcast intent
getActivity().sendBroadcast(intent);
I'm having two activities which are displayed side by side on one screen through a fragment for each activity. I want to send a String when I click a button on one of the activity, and then the other activity should retrieve the String I sent.
I know that it's possible to do that with the classic way setString() and getString() methods. But I'm wondering, could it be accomplished with putExtra() and getExtra() without opening the targeted activity on a new screen?
You can have both activity's intent as global variable and try using putExtra() from one activity and then getExtra() by another activity.
For Example,
public class activityOne extends Activity
{
public static Intent intent = null;
#Override
protected synchronized final void onCreate(final Bundle savedInstanceState)
{
intent = getIntent();
}
}
public class activityTwo extends Activity
{
public static Intent intent = null;
#Override
protected synchronized final void onCreate(final Bundle savedInstanceState)
{
intent = getIntent();
}
}
Now wherever you want you can access their intent like activityOne.intent,activityTwo.intent followed by null check
You can send the intent as a broadcast and have the receiving fragment register to that broadcast on its start (and unregister on its destroy).
Sending fragment:
Intent intent= new Intent(PARAM_TRANSFER);
intent.putExtra(key, extra);
sendBroadcast(intent);
Receiving fragment:
register:
IntentFilter intentFilter = new IntentFilter(PARAM_TRANSFER);
registerReceiver(mReceiver, intentFilter);
unregister:
try {
unregisterReceiver(mReceiver);
} catch (Exception e) {}
getting the param:
private class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
intent.getExtra(key);
}
}