I am having trouble grasping a certain concept in Android UI design. The book I am referring to first uses the usual technique that Java programmers use to create UIs and that is to to create containers and add UI components to them and nest them as necessary.
Now, the book introduces a new concept where the entire UI was created using an XML file. The code is pasted below:
package com.oreilly.android.intro;
import android.app.Activity;
import android.os.Bundle;
/**
* Android UI demo program
*/
public class AndroidDemo extends Activity {
private LinearLayout root;
#Override public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
root = (LinearLayout) findViewById(R.id.root);
}
}
so basically, I can use any of them ?
Simple answer,yes, you can use either approach. However, there are some limitations to each such as there are layout properties that must be set in xml if you want to use them. I can't think of what any are off-hand but I can look them up.
For the most part, creating the layouts is much simpler to do in xml but you do have the option of setting Views and layouts in Java if you need to such as creating an unknown number of Buttons depending on some user-defined variable.
When you create your UI in xml then you inflate it in your Java code. This is normally done in onCreate() using
setContentView(R.layout.main);
as you see in your example. But it can also be done with an inflater.
The thing to remember here is to inflate your layout, using either method, before trying to initialize any views in the layout or you will get a NPE when trying to call a method on a View defined before inflating the layout it is contained in.
A correct way
**Examples of inflating views/layouts correctly**
Button mBtn;
public class AndroidDemo extends Activity {
private LinearLayout root;
#Override public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.main);
root = (LinearLayout) findViewById(R.id.root);
btn = (Button) findViewById(R.id.buttonId); // Button is initialized after inflating the layout
}
}
Incorrect way
public class AndroidDemo extends Activity {
private LinearLayout root;
#Override public void onCreate(Bundle state) {
super.onCreate(state);
Button mBtn = (Button) findViewById(R.id.buttonId); // Button is initialized before inflating layout which will return null
setContentView(R.layout.main);
root = (LinearLayout) findViewById(R.id.root);
}
}
I added the above example because I have seen a lot of people make that mistake. So don't do it...you've been warned! :)
Not entirely sure what you're asking, but the two are interchangeable.
Most of the time your UI will be done via xml. In some cases though, the ui is heavily dependent of the data, so you may need to dynamically generate it.
It basically comes down to whichever is easiest for you at the time.
Yes.
But is preferable to use xml, it is more powerful, easier and will separate layout from your code.
Take a look at the docs:
http://developer.android.com/guide/topics/ui/declaring-layout.html
Related
I'm writing a calculator application in which I would like to be able to switch between 4 modes of calculation: Decimal, Binary, Octal, and Hex. In order to manage the different UIs for the different modes, I have 4 Fragment subclasses in my Activity. Each Fragment has its own XML layout file, in addition to the main XML file for the Activity. I found a guide on the Android Developer site for inflating layouts for Fragments, and I've followed that guide. However, I would like to add listeners and so on to the various components of the layouts, preferably within the onCreateLayout method of the Fragment, or somewhere else where I could do it easily and minimize code duplication.
It appears, however, that when I try to call findViewByID to access one of the inflated Views (after I've called LayoutInflater.inflate, obviously), I get a null return value. This issue occurs whether I call findViewByID from within onCreateLayout or from elsewhere in the Activity (after the Views have, theoretically, been created). What's going wrong here?
One issue I think might be a problem is that I've overloaded the names of the Views between the various Fragment layouts. For example, the "1" button in the Binary layout has the same ID as the "1" button in the Hex layout. Is this allowed, assuming the Binary and Hex layouts are never both part of the Activity at the same time?
Thanks.
I think same id in different layout is not problem in Fragement. First you have to catch the inflated view then find whatever inside this. For example --
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.frg1, container, false);
android.util.Log.v("", "!!!!!!!!!! Frg1 !!!!!!!!!");
Button b = (Button) view.findViewById(R.id.b1);
b.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
Toast.makeText(getActivity(), "here", Toast.LENGTH_SHORT).show();
}
});
return view;
}
I want to upgrade a couple of my Android apps to use Fragments. Here is a basic situation:
I have an Activity and a ListActivity. I want to convert these using fragments using the compatibility packaging. Below is what I have in the onCreate method in the Activity. (The ListActivity has similar items so I am only using the Activity as the example ere in the conversion).
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
setContentView(R.layout.rate);
Item = getIntent().getExtras().getString("name");
Category = getIntent().getExtras().getString("category");
title = (TextView) findViewById(R.id.tvRateItem);
ratingsBar = (RatingBar) findViewById(R.id.theRatingBar);
title.setText(Item);
// Display list of reviews
new starTotalTask().execute();
new starRatingTask().execute();
final EditText etTweetReview = (EditText) findViewById(R.id.etTweetReview);
Button button = (Button) findViewById(R.id.theRatingBarButton);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// do stuff
}
}
});
Button BReviews = (Button) findViewById(R.id.bReviews);
BReviews.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// do stuff
}
});
}
So you see, I have a couple of Buttons, a couple of AsyncTasks, some getIntents that are grabbing data from other Activities, some "widget" declarations referencing to the XML.
I have the basic framework already setup with a FragmentActivity (from compatibility v4 package) with a couple of fragments it points to. In fact, I have a ViewPager, and tabs set up. The correct layouts are already setup as it should be to the new Fragment view. I just don't get how to move the data as seen above. I also understand the onCreateView is where you set the layout. Outside of that, where does everything else go? Not looking for code example as much as direction -- IF POSSIBLE.
Edit: My layout is based on this: http://thepseudocoder.wordpress.com/2011/10/13/android-tabs-viewpager-swipe-able-tabs-ftw/
especially interest in:
- Where do the RatingsBar and TextView (and other xml references) go?
- what about AsyncTask?
- and how do you handle passing around data in intents?
Almost everything will be identical. The key differences are:
You need to extend FragmentActivity in place of Activity.
You need to call getSupportFragmentManager() instead of getFragmentManager().
You need to call getSupportLoaderManager() instead of getLoaderManager().
The compatibility library does not support a ListFragmentActivity (or whatever). You'll need to use a FragmentActivity instead and set up the ListView in your code.
I'm having issues with understanding how I should organize my user interface in Android. My original plan was to create TextViews and ListViews programatically and change them when buttons are clicked, etc.
Here's my first simple attempt. viewFriends is a method within my Activity class. It's called when a menu button is pressed.
private void viewFriends()
{
mText = new TextView(this);
mText.setText("Gathering information...");
setContentView(mText);
...irrelevant code follows
Why doesn't this seemingly simple example work? How should I logically organize and manage my user interface objects (TextViews, ListViews, Buttons, etc).
Thanks.
The best work would be having those listviews and textviews in your XML files and give them a suitable ID like following:
<ListView
android:id="#+id/myList"
android:layout_width="wrap_content"
android:layout_weight="1"
/>
Just like above have your text view too in XML file an add the android:id attribute.
Once you define this way in your java file have references to them:
ListView myListObj = (ListView)findViewById(R.id.myList);
Now you have an object called myListObj in your java file and now you can do whatever you want to do with it.
:)
Let me if you find any issue in this so that I can update the answer to meet your specific need.
Don`t use setContentView in your method. Usually it should only be called once in the onCreate method of your activity.
Best predefine your bottons/TextViews in xml, get a handle for them (findViewbyId...)
and modify them that way.
If you create them programaticly, just add them to a view containter from your xml.
Like :
setContentView(R.layout.main);
Lets say in main.xml there is a LinearLayout with the id: root.
// get accces to that layout:
LinearLayout rootLayout = (LinearLayout) findViewById (R.id.root);
// create a new TextView
TextView tv1 = new TextView (this);
tv.setText("Hello!");
// add it to your base layout
rootLayout.addView(tv1);
// done! :)
Make a double check on what you are getting in "this".
change it to your java file name.this
You have to reload/refresh your activity once you change it.
Try this
#Override
protected void onResume() {
if(param.equalsIgnoreCase("gr"))
{
finish();
Intent myIntent = new Intent(yourActivity.this, yourActivity.class);
startActivity(myIntent);
}
In the app, I'm struggling with I have a custom view.
I cannot declare it in layout XML file, because I'm going to use in from the activity that holds my custom view instance and I need to have access to it (cannot override findViewById...).
Thereof I decided to declare all of the GUI elements into the Activity.
But I simply cannot make a single step forward, since I even cannot instantiate viewGroup...
This is what I'm trying:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup vg = new ViewGroup(this.getApplicationContext());
setContentView(vg);
}
and I get 'Cannot instantiate ViewGroup'...
Can someone give a straight-forward example, of how to declare a viewGroup, that holds views?
The documentation of the class is also not very beginner-friendly... all the examples are focused on describing the layout in a layout XML file...?
Appreciate your efford, giving an example!
[ViewGroup][1] is an abstract class, you cannot instantiate it. It defines a type of classes that will be container to put other views in them. In other words, layouts like LinearLayout of RelativeLayout are ViewGroup. Thus, you could do something like that :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout vg = new LinearLayout(this);
// set the LayoutParams the way you want.
// and add textviews, imageviews, ... here for instance.
setContentView(vg);
}
For the LayoutParams, I think you should start with LayoutParams.Fill_parent
Is there anywhere that I can find documentation on the scope of the XML files? I have an app I am currently working on and have been struggling with getting a feature to work and it seems that the problem I am having is that I am trying to access an element in an XML file that must be out of scope. To simplify the layout, my project has main.xml, sub.xml, main.java, and sub.java files in it. As you can probably guess, main.java works with main.xml and sub.java is working with the elements in sub.xml. Here's where the issue comes in, I have a TextView element that is created in main.xml that I would like to modify the text in, but the action that would trigger it will occur in sub.java. I can't figure out how to change it from sub.java, and I can't figure out how to move the element into sub.xml. The code I am using is pretty simple:
TextView titleText = (TextView) findViewById(R.id.myTitle);
titleText.setText(filePath);
I get a FC every time I run the app, but if I move the code into main.java, it runs flawlessly. If anyone can offer any ideas, or point me in the direction of some documentation that would explain what java files can access what elements in which xml files, that would be awesome! Sorry for the novel, but I'm just struggling to get the point across. Thanks.
try like this Bryan in Main.xml file it works with no issue...........Declare first & then Initialize it...
public class Main extends Activity {
static TextView tv;
static Button submit;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
tv = (TextView) findViewById(R.id.header_text1);
}
}
Activity.findViewById(int) only works if that view is in the activity's layout. So no, you can't refer to a view in main.xml because that layout doesn't apply to sub.
Do you have any TextViews in sub.xml called myTitle?
You can access the the textview of main.java(main.xml) in submain.java as follows
In main.java write the following code
static TextView titleText = (TextView) findViewById(R.id.myTitle);
titleText.setText(filePath);
and u can access this submain.java as
Main.titleText.setText(filePath);