Change tabhost tab title in a different activity - android

I have a main activity that hold the tabs and each tab start a new activity. May I know how can I change the tab title from the new activity? Thanks.

Although CommonsWare has pointed out that having Activities as Tab content is deprecated, if you still want to do it then one possibility is to use a nested BroadcastReceiver and have the content Activity send a broadcast Intent. I'm not sure if it will work but I would try something like the following...
public class MainActivity extends Activity {
bool tabMonitorIsRegistered = false;
TabMonitor tabMonitor = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Other code
tabMonitor = new TabMonitor();
}
#Override
protected void onResume() {
super.onResume();
if (!tabMonitorIsRegistered) {
registerReceiver(tabMonitor, new IntentFilter(Intent.com.mydomain.myapp.ACTION_TAB_CHANGE));
tabMonitorIsRegistered = true;
}
}
#Override
protected void onPause() {
super.onPause();
if (tabMonitorIsRegistered) {
unregisterReceiver(tabMonitor);
tabMonitorIsRegistered = false;
}
}
// Nested BroadcastReceiver
private class TabMonitor extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
// Process the Intent here to change the tab title
}
}
}
At this point it occurs to me that each 'content' Activity will need to tell the MainActivity (via the Intent it sends) 'who' it is. To do this, I would use an Intent extra when adding the tab content Activities identifying each as 'tab1', tab2' etc. When the 'content' Activities start, e.g., in onCreate(), they can store this string and use it in the Intent they send as the broadcast to the MainActivity.

Related

Why do I get a NullPointerException here?

I have my code defined the way below. There are two crucial activities. Activity (1) shows some images in a ViewFlipper. It uses methods to load desired image directly. The onOptionsItemSelected() method fetches data from a menu defined within linked XML layout R.layout.browse. The other method, displaySelectedFlag(), gets a tag parameter passed from a different activity, let's call it activity (2).
Activity (1):
public class BrowserActivity extends AppCompatActivity implements SimpleGestureListener, View.OnClickListener {
public ViewFlipper vFlipper;
(...)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.browse);
vFlipper = (ViewFlipper) findViewById(R.id.viewFlipperBrowser);
(...)
} // onCreate() ends here
// this method below works fine:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
vFlipper.setDisplayedChild(item.getOrder());
return true;
}
// and this one doesn't:
public void displaySelectedFlag(int orderTag) {
vFlipper.setDisplayedChild(orderTag); // crashes here
}
}
Activity (2):
public class ListActivity extends Activity implements View.OnClickListener {
private BrowserActivity browserActivity = new BrowserActivity();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
ImageButton imageA = (ImageButton) findViewById(R.id.img_a);
imageA.setOnClickListener(this);
ImageButton imageB = (ImageButton) findViewById(R.id.img_b);
imageB.setOnClickListener(this);
}
public void displayImageInfo(View view) {
String tagValue = (String) view.getTag();
int tagId = Integer.parseInt(tagValue);
Intent intent = new Intent(this, BrowserActivity.class);
startActivity(intent);
browserActivity.displaySelectedImage(imageId);
}
#Override
public void onClick(View view) {
displayImageInfo(view);
}
}
As I checked, the method onClick() called in activity (2) fetches an ID of an ImageButton and passes it to activity (1). Unfortunately, I get a NullPointerException when calling the ViewFlipper (the line is marked in the code above, activity (1)).
Any idea why it happens?
You cannot reference one Activity from another activity. You must let the Android OS create the Activity object via the call to "startActivity". Allocating a local variable as an instance of an Activity doesn't actually mean anything (like your instantiation of the BrowserActivity). Apoorv's comment links to a decent article on the subject.
If you want to pass data from one Activity to another, you need to pass extras within the Intent's bundle. This post goes into detail: https://stackoverflow.com/a/819427/504252

How can one know if an activity is started without a transition?

I have a use case where I mostly start an activity with a transition, but that's not the case when opening it from the navigation drawer.
To keep the transition smooth I have a Transition.TransitionListener in which I trigger some UI updating when the transition is done.
So I have something like this:
public class SomeActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
// ...
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
// ...
#Override
public void onTransitionEnd(Transition transition) {
doSomeUiUpdating();
}
});
} else { // Pre-Lollipop
doSomeUiUpdating();
}
}
}
This works well when starting the Activity with the animation, but how can I know if the Activity was started without a transition so that I can call doSomeUiUpdating()?
I'm sure there must be a simple method in Activity, Window, Transition or somewhere that I have overlooked. I don't want to relay on the calling Activity to set some bundle that telling if the animation is showing or not.
You can try onTransitionStart of TransitionListener to set some boolean isAnimationStarted.
public class SomeActivity extends Activity {
private boolean isAnimationStarted = false;
public void onCreate(Bundle savedInstanceState) {
// ...
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
Transition sharedElementEnterTransition = getWindow().getSharedElementEnterTransition();
sharedElementEnterTransition.addListener(new Transition.TransitionListener() {
// ...
#Override
public void onTransitionEnd(Transition transition) {
doSomeUiUpdating();
}
#Override
public void onTransitionStarted(Transition transition) {
isAnimationStarted = true;
}
});
}
}
public void onStart() {
if (!isAnimationStarted) {
doSomeUiUpdating();
}
}
}
Since you are starting an Activity, you'll be making use of an Intent to start it. You can add extras to Intents and check for them in the onCreate() of the called Activity.
Let's assume that we have 2 Activities – ActivityA, and ActivityB.
Now, let's assume that ActivityA is the calling Activity, and that ActivityB is the called Activity.
In ActivityA, let's say you've written some code to start ActivityB with a SharedElementTransition.
#Override
public void onClick(View v) {
Intent startActivityBIntent = new Intent(getContext(), ActivityB.class);
startActivityBIntent.putExtra("IS_SHARED_ELEMENT_TRANSITION_ENABLED", true);
ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), view, ViewCompat.getTransitionName(view));
startActivity(startActivityBIntent, activityOptionsCompat);
}
Now, if you notice above, I've passed an Intent extra with the putExtra() method. I've passed a Boolean value of true because I intend to start the Activity with a SharedElementTransition.
Now in ActivityB's onCreate() method, you can just check for the boolean value passed to the Intent. If you passed false, then you can add a conditional statement and perform your UI updating there. I've given you a small snippet below to help you get started:
private static final String isSharedElementTransitionEnabled = "IS_SHARED_ELEMENT_TRANSITION_ENABLED";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
// If you are postponing your SharedElementTransition, don't forget to call postponeEnterTransition() and override onPreDraw()
if (!getIntent().getExtras().getBoolean(isSharedElementTransitionEnabled)) {
//Do your UI updation here
}
}
The good thing about doing it this way is that you can then have full control over how your content transitions and your shared element transitions will play out.

Call fragment from another fragment after some delay

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);

Update tabhost imageView from another activity

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. :)

How to reference child activity from TabHost to call a public function?

I have a TabHost with two child activities in it (in two tabs). I also implemented a public function in one of these activities that i would like to call from my parent (TabHost), to trigger some action within the tab.
Is it possible to reference the activity itself from the TabHost to call a public function?
Thanks
here is my tabhost setup:
res = getResources();
tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
intent = new Intent().setClass(this, home.class);
spec = tabHost.newTabSpec("home").setIndicator("Groups", res.getDrawable(R.drawable.groups)).setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, messages.class);
spec = tabHost.newTabSpec("messages").setIndicator("Messages", res.getDrawable(R.drawable.messages)).setContent(intent);
tabHost.addTab(spec);
My approach would be to define a nested 'listener' class in the child activity which extends BroadcastReceiver.
I would then simply broadcast an Intent from my TabActivity which would then trigger the BroadcastReceiver to perform the action.
EDIT: To give example code...
The steps are...
Define the intent filter in the manifest
Add the nested 'listener' to the child activity
Set onResume()/onPause() in child activity to register/unregister the listener
Create intent in TabActivity and broadcast it when you want child to do something
In AndroidManifest.xml
<activity
android:name=".MyActivity"
android:label="#string/app_name"
<intent-filter>
<action android:name="com.mycompany.myApp.DO_SOMETHING" />
</intent-filter>
</activity>
In MyActivity.java
public class MyActivity extends Activity {
private MyListener listener = null;
private Boolean MyListenerIsRegistered = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreated(savedInstanceState);
listener = new MyListener();
}
#Override
protected void onResume() {
super.onResume();
if (!MyListenerIsRegistered) {
registerReceiver(listener, new IntentFilter("com.mycompany.myApp.DO_SOMETHING"));
MyListenerIsRegisterd = true;
}
}
#Override
protected void onPause() {
super.onPause();
if (MyListenerIsRegistered) {
unregisterReceiver(listener);
MyListenerIsRegistered = false;
}
}
// Nested 'listener'
protected class MyListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// No need to check for the action unless the listener will
// will handle more than one - let's do it anyway
if (intent.getAction().equals("com.mycompany.myApp.DO_SOMETHING")) {
// Do something
}
}
}
}
In the main TabActivity
private void MakeChildDoSomething() {
Intent i = new Intent();
i.setAction("com.mycompany.myApp.DO_SOMETHING");
sendBroadcast(i);
}
I've found another, probably simpler solution. I'm sure OP doesn't need this any more, but maybe someone from the future will be glad to find it.
So, basically, to run a public method in your child activity, you just need this little piece of code in your parent (tabHost, home and message are taken from OP's TabHost configuration):
tabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
#Override
public void onTabChanged(String tabId) {
Activity currentActivity = getCurrentActivity();
if (currentActivity instanceof home) {
((home) currentActivity).aPublicMethodFromClassHome();
}
if (currentActivity instanceof messages) {
((messages) currentActivity).aPublicMethodFromClassMessages();
}
}
});
I use it in my application. Works as a charm;)
I'm currently debugging an Android application and came across the same need. I found a much straightforward answer to this with this code snippet :
String currentActivityId = getLocalActivityManager().getCurrentId();
Activity currentActivity = getLocalActivityManager().getActivity(currentActivityId);
The identifier here is the identifier given when creating the TabSpec :
tabHost.newTabSpec("id").setIndicator(indicator).setContent(intent);
Thank you, this helped me to solve a simular problem!
Activity currentActivity = getLocalActivityManager().getActivity(_TabHost.getCurrentTabTag());
if(currentActivity != null && currentActivity instanceof iMyActivity)
{
// pass to children
((iMyActivity)currentActivity).onLaunchDelegate();
}
From this link, I found this simple solution (http://androidactivity.wordpress.com/2012/08/17/two-way-communication-between-tabactivity-and-its-child-tabs/):
Well, the trick is to store the TAG associated with each tab, and use it to call the respective activity.
When you create the tab, you associate it with a tag like following:
yourTabHost.newTabSpec("Tab1");
Lets say we want to invoke a method “refreshContent()” that is inside the Tab1 Activity.
It’s simple as calling these lines from the MainActivity:
ActivityTab1 activity = (ActivityTab1) getLocalActivityManager().getActivity("Tab1");
activity.refreshContent();
And that’s it!
Now for the opposite direction, we want to call some method “updateMain()” inside MainActivity, from the child tab TabActivity1.
At the TabActivity1 you will only need to call
((MainActivity)getParent()).updateMain();
find it simple, use it in app ActivityTab class:
if(getCurrentActivity() instanceof YourSearchActivity){
log("onClick: instance found");
((YourSearchActivity)getCurrentActivity()).activityPublicFuntion();
}

Categories

Resources