I am very new to Android development and I'm trying to figure out the best way to achieve the following goal:
I want to have a main menu that holds several buttons. Each of those buttons should load a second Activity and pass some data to this Activity.
The Secondary Activity should display a tabbar that switches between three different views or activities:
1. A static view created for each element (button on main menu)
2. An image gallery with a set of images associated with that element
3. Another page with dynamic content like a map and images.
My thought: Create a json file for each element and pass the name of that file to the Secondary Activity with could then create the views using that data.
Problem: Can you store the name of a layout.xml file as a string and then load it?
So what would be the best Practice to approach this?
Pass the information of which layout/which views you want to display in the second activity as an extra on the intent used to start the activity:
Intent i = new Intent(FirstActivity.this, SecondActivity.class);
i.putExtra("layout_identifier", 5);
startActivity(i);
Then extract this information in the receiving activity onCreate():
Bundle b = getIntent().getExtras();
int layout = b.getInt("layout_identifier", 0);
switch (layout) {
case 5:
setContentView(R.layout.activity_second_layout5);
break;
Note that the datatype passed does not necessarily have to be int, you can pass all primitives, strings and a third option called Parcelable (https://developer.android.com/reference/android/os/Parcelable.html) which can be thought of as a container for objects.
Related
I have a gallery app, with some categories: animals, flowers... each gallery I created one activity, this activity in all galleries has the same content:
onCreate:
tSpeak = new TextToSpeech(this, new TextToSpeech.OnInitListener() { ...
AdView adView = new AdView(MainActivity.this); ...
//some checks to change images:
if(fase == 1) { imageView1.setImageResource(R.drawable.flower1); ...
if(fase == 100) ...
some setOnClickListener
after that some onRewardedVideo functions, a next() function that will intent to the same activity to show next image on this gallery (`fase` + 1)
What I'd like to know is, can I instead of repeating all this things (TextToSpeech, listeners, rewardedvideos functions, adview functions) just change the if checks in each activity gallery? this is the only thing that will change in each activity gallery, and I don't want to use just one activity for all categories because in this case I may have more than 2000 ifs and it is not good to work.
I'd like to just inject in each category the ifs to set imageresources there, without need to copy all activity again and again in each category. Any ideas?
You can create your common functionalities in a BaseActivity and extend your activities from this BaseActivity.
For the ifs conditional checking you can have a boolean field in your BaseActivity which you can override in your each subclass (In this case, your actual activities).
A better option could be having one activity only where your category is passed in the Bundle. Now based on your category, you can switch over the value and keeps your variations.
I suggest you use a single activity and pass a gallery ID as a parameter to your activity via an Intent extra.
You could get the image resource ids of the current gallery from a static map in your activity.
You could also use a ViewPager with one gallery per fragment, to enable your user to navigate quickly accross galleries.
Look at this for more info:
https://developer.android.com/training/animation/screen-slide
I'm trying to build an application that will have list/detail panes built with fragments. List is created from the ContentProvider. When clicked on the list the details is populated or activity created. In action similar to gmail application. How the data should be shared/passed between fragments/activities?
Population of the list wasn't that hard, but how can I pass the selection to the details fragment (either in the same activity or another activity)? Should I query again and returned result used in details?
It needs to be like gmail app, so swipe left/right should then change the details accordingly to the same order as the list is either in the single pane layout or dual pane layout.
I think for this I need to share the Cursor returned by the CursorLoader to keep the same order. Then swipes would increase/decrease the index and would display correct item.
Also as I already loaded data, I wanted to reuse it without new queries.
Could someone point me to the right direction, what you would you do to achieve that (no code but algorithm/steps)?
At the moment I have 2 activities list and detail, the list has dual and single panel layout and list fragment with details fragment are used, detail has just single pane with details fragment. I think I could reduce it to be a single activity and juggle the fragments but don't know if it will be good.
Here is a way to pass data from one activity to another :
intent = new Intent(this, ProductListActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(PRODUCT_LIST, productList);
bundle.putString(KEY_WORD, keyWord);
intent.putExtras(bundle);
startActivity(intent);
If you're in an activity and want to pass data to a fragment in that activity, just use setters from that fragment
EDIT : Since last comment, implement a class to handle your object with the Serializable interface :
public class MyDBObject implements Serializable {
//Stuff
}
Then when you fetch from your DB, return or a MyDBObject, or a List<MyDBObject>
Finally, when you need to pass the data, just use
Intent intent = new Intent(SourceActivity.this, TargetActivity.class);
intent.putExtra("DB_OBJECTS", ArrayList<MyDBObject>mDBObject); // For a list
intent.putExtra("DB_OBJECT", mDBOject); //For a single object
What I did then was:
activity holding the fragment(s) will do:
implement LoaderManager.LoaderCallbacks<Cursor>
call the getSupportLoaderManager().initLoader(ALL_DATA_LOADER_ID, null, this);
pass arguments of the LoaderCallbacks to the fragments that also implements LoaderCallbacks
call the getSupportLoaderManager().restartLoader(ALL_DATA_LOADER_ID, null,
this); whenever data was changed outside of the ContentProvider means
This way I'm sharing the same cursor between fragments. Between activities I'm exchanging (via Intent) the data needed to request the same dataset and selection id if needed.
I have 2 list views :
- The first one is instantiated in a fragment
- The second one in a activity.
They display the same information
On click on a list item, I open another activity to display item detail.
Depending on the calling activity/fragment, I want to render a different layout, so I need to know in the activity that render the detail of a item, which activity created the intent ?
getCallingActivity and getParentActivityIntent seems to be declarative and fixe, isn"t it ? in my case there are both null.
How can I do that ?
You can pass an argument with your intent as:
intent.putExtra("ParentActivity", "ActivityA");
or
intent.putExtra("ParentActivity", "ActivityB");
In your next activity, use this:
String parentActivity = getIntent().getStringExtra("ParentActivity");
And render the layout according to result.
Hope it helps.
I want to make an application that can support portrait and landscape. The layout has two panes, on the left is the options and the right shows the result. When an option is selected the right pane shows it. But for portrait there is not enough room, so a separate activity is needed. Each option produces a different type of fragment, so I don't want to make an activity for each option when all that changes between activities is what fragment is being added there. I want to pass a fragment from the main activity to the new one, how would I do this?
EDIT: Moved what asker actually wants to top.
If you want to pass data to an Activity when creating it, call a version of Intent.putExtra() on the intent that is used in startActivity(). You can then use getIntent().getStringExtra() to (for example) get a string extra in the activity.
Say you have a piece of string data in your first activity called myString.
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra(EXTRA_NAME_CONSTANT, myString);
startActivity(intent);
Now in your new activity in onCreate you would do:
String myString = this.getIntent()
.getStringExtra(EXTRA_NAME_CONSTANT, "default return value here");
A few notes:
For that EXTRA_NAME_CONSTANT, I do mean to make a string constant of the form "your.package.name.SomeString" for example "com.example.MyString". Personally I'd even use a resource (accessed in the form getString(R.string.extra_my_string)) for the extra's name. They recommend you prefix it with your package name.
You can put and get many types of data from strings to arrays to even serializable data.
Instead of making a separete activity for different layout orientations consider using resource qualifiers to provide alternative layouts.
To summarize, make two layouts in a structure like so:
/res/layout/yourlayout.xml
/res/layout-land/yourlayout.xml
Where both XML files are named the same. Then make your default portrait layout in one and a landscape version in the other.
When you inflate the layout in onCreate (and when it does so automatically on a layout change during runtime) it will select the correct layout for you.
I want to pass a fragment from the main activity to the new one, how would I do this?
You wouldn't. At most, you would follow #Ribose's answer -- pass a flag into the activity via an extra to indicate what set of fragments to create.
I would need to know how to handle the intent between tabs. For example, I have a tab activity with two tabs. First on content is a text view. another one is a map view. When i click that text view it redirects to the tab2. it can be easily achieved by setCurrentTab(1) or setCurrentTabByTag("tab2") methods. But i want to pass lat and long values to that Map Activity to drop pin. What is the better way to use intents or getter/setter in java? What do you prefer? if your answer is "Intents". How?
A interesting problem. I understand it that you want to change to the second tab on a click in the first tabview but also pass special data to the second tab that is dependent on the action in the first tab.
I would generally start your views inside the tabs with an activity. However this is done at the moment the tab host is configured. That means both intents the one for the activity that lets the user choose lat long and the one that shows lat long are openend at the same time.
Therefore you can't add the information to the intent used to intialize the tab host.
I don't like the solution but the only thing that comes to my mind (using different activities for the tabs) is using a custom application that stores a reference to an object containing the data that you need to update the view in the second tab. You have to extend application with an own class and add this class in you manifest, now you can call getApplication in the first tab cast it to your application class set lat and long just before you call setCurrentTab. In the second tab you can call getApplication() again and you will then get the application object that is the same for every activity at every moment of your app running. You then have cast it again to your application object and retrieve lat and long value. See this page in the google refs on how to use a custom application class.
To use a custom application class add the following to your application tag in your manifest:
<application
...
android:name=".somepackage.CustomAppClass"
This will tell Android to instantiate the CustomAppClass as your Application class at the moment your app starts. You need to extend Application to avoid errors on start up.
Another solution but not the one I would prefer is to initialize the views yourself and initialize the tabhost with views and not activities. With a map view in one of the tabs this could be very memory heavy.
If you want to pass values between activities, I suggest looking at
http://developer.android.com/reference/android/content/SharedPreferences.html
the best way to get values from one itent to another.
With sharedPrefrences, there is only one instance of the class for the whole application, which means that you can store values in the files, switch intents or activities, and then recall those sharedPrefrence files that have the data in them.
The only downside is that you have to pass primitive types (int, string, boolean) but I'm sure you'll figure ways around this :).
I dont see the Problem here:
Maybe its a little bit of hackish but following Code works for me:
public boolean onClick(View v) {
//get your data you wanna send.
//If it is an Object it would be good if it is Parcelable
Object o = getYourData();
// or Parcelable p = getYourData
Activity activity = getParent();
//I'm assuming were inside an Activity which is started by TabActivity
if (activity instanceof TabActivity){
TabActivity ta = (TabActivity)activity;
//now determine the Tab you wanna start
ta.getTabHost().setCurrentTabByTag("yourTag");
//or ta.getTabHost().setCurrentTab(yourID);
Activity current = ta.getCurrentActivity();
//check if the Activity is the one you wanna start
if (current instanceof YOUR_ACTIVITY_YOU_WANNA_START){
//Cast to your Activity
YOUR_ACTIVITY_YOU_WANNA_START yourActivity =
(YOUR_ACTIVITY_YOU_WANNA_START)current;
// you only need to put Data inside your Intent
Intent intent = new Intent();
intent.putExtra("EXTRA_DATA_TAG", o);
//your Activity must Override onNewIntent and make it public,
//or simply add another method
//with whatever You like as parameter
yourActivity.onNewIntent(intent);
return true;
}
}
return false;
}
this way you don't have to mess with Application, SharedPrefs or other unnessesary stuff mentioned here
If you make the intent you are using to start the second tab activity a global intent.
You can then add extra's to this intent in the onPause() of the first tab. Note: you have to define all your tabs in separate activitys than your tabhost TabActivity as this activity's onPause() is never called.
This also help's with the answer above, if you are using a global variable saved in your activity that extends application, you can set this in the onPause() as it is fired before the activity is switched, which you might find an issue if setting this elsewhere