Monday, December 13, 2010

Date Picker Frustrations

The date picker for the scheduler part of my app has somehow completely disappeared from existence. Did I dream that this was a working widget and never bothered to try it out in real life!? Anyhow, I'm trying to implement a date picker from an options menu click event inside a tabhost and the code is giving me a load of problems. Damn you, ambiguously written android dev tutorial!


The result -- I think trying to implement a date picker in tabhost is impossible. Something about the content view... had to work around the problem by adding a "select a date" button into the activity controlling that particular tab and removing the troublesome item from the options menu.



Friday, December 3, 2010

Saving State on Orientation Change

Problem:
Form loses state on orientation change. This is due to onCreate being called on orientation change. This affects pages with forms half-filled out becoming blank.

Solution:
In Manifest.xml, go to Application tab, select the Activity in question (yes, you have to do this for EVERY activity you want to protect). For Config Changes select “keyboardHidden” and “orientation”. Worked for me.

Repainting a ListView Adapter from a Separate Activity

Basically, I have a page with a search box. You search for something, get the results in the form of a list on a pop-up dialog (which has its own activity). When you select one of the results, the dialog closes, and the item is added to the original page with the search box. You can repeat this, ad nauseum. *NOTE* This method requires an API level of at least 1.6.

PageOne.java
Be sure to declare variables for the strings and adapter before onCreate. Static makes it available to use by other activities in the package:


static List<String> strings; ListView lv; static ListAdapter adapter;


Define these variables inside onCreate:


strings = new ArrayList<String>();   
lv = getListView();
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.label, strings);
lv.setAdapter(adapter);


PageTwo.java

In the onClick method, add code to transform selected item to a string value. Then, adds the item to the String Array in PageOne. Last, notifyDataSetChanged on the adapter used in pageone:


@Override  
public void onListItemClick(ListView parent, View v, int position, long id) {  
selected = ((TextView) v).getText().toString();  
PageOne.strings.add(selected);  
((ArrayAdapter<String>) PageOne.adapter).notifyDataSetChanged();  
this.finish();  
}

Thursday, December 2, 2010

"Conversion to Dalvik format failed with error 1"

Ugh. Don't you hate errors that aren't in the code, and don't go away no matter how many times you fix project setup or clean.

Heres what I got in the console:


[2010-12-02 10:38:10 - MDatHand] 
trouble processing "java/lang/Object.class":
[2010-12-02 10:38:10 - MDatHand] 
Attempt to include a core VM class in something other than a core library.
It is likely that you have attempted to include the core library from a desktop
virtual machine into an application, which will most assuredly not work. If
you really intend to build a core library -- which is only appropriate as
part of creating a full virtual machine binary, as opposed to compiling an
application -- then use the "--core-library" option to suppress this error
message. If you go ahead and use "--core-library" but are in fact building
an application, then please be aware that your build will still fail at some
point; you will simply be denied the pleasure of reading this helpful error
message.
[2010-12-02 10:38:10 - MDatHand] 1 error; aborting
[2010-12-02 10:38:10 - MDatHand] Conversion to Dalvik format failed with error 1

Oh yeah... this was certainly a real pleasure... jerk. The only thing I understand in all that garbage is "library" not that that give me any damn clue on how to fix it. How but just a nice error message that says "FIX YOUR LIBRARY SETTINGS"????? Anywho, I digress...

I did some soul searching on the interwebs, and a nice man by the name of Jim had posted a reasonable solution. I'm posting it herein the event the error pops up again again:

I received the following message and found several others who had seen
it but no solution. So I have included how I finally fixed it. (I'm
using Eclipse version 3.4.2 and Android 1.5.)

...
The fix for me was to go to my project's properties, select:

Java Build Path -> Libraries (tab)

Somehow, the android.jar had been added, and when I deleted it, all
was good. Note that the android.jar is included as part of the
Android 1.5 library, so this was a duplication.

How did this happen? I certainly didn't do it. But my app has blown
up a lot in the emulator, so who knows.

Later . . . Jim


THANKS JIM :]

Tuesday, November 30, 2010

Marquee Attributes

This has absolutely nothing to do with Android or Java.

I had a text marquee announcement news thingy on my company website, and I didn't want to lose the code because it took me a full day to figure out how to use marquee attributes.

<marquee behavior="scroll" direction="left" scollamount="1" onmouseover="this.stop();" onmouseout="this.start();"></marquee>

Friday, November 26, 2010

Setting up Android Development Environment with Eclipse

I've done set up a fifth computer with the Android Dev environment and every time it's a gorram struggle. I hate setting up workstations! So here I am, finally conceding to the idea that there will never be a last and final time for the most tedious, time consuming, and confusing chores.

1) Download Eclipse IDE for Java Developers 3.5 (Galileo). The newer version 3.6 Helios is not supported by android. Galileo comes as a zip file, no install necessary. Unzip somewhere you will remember, and make shortcuts to your desktop/task bar/whatever.
http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/galileor

2) Download JDK/JRE v.6 (or the new v.7). Follow the install. You will need a login username and password for Sun Microsystems. (*Optional: After install, find the jdk folder, and copy the "jre" file into your eclipse folder. I don't know if this is the correct way to do this, but it works for me. Particularly useful if you downloaded the Android SDK as a zip rather than the installer.)
http://www.oracle.com/technetwork/java/javase/downloads/index.html

3) Download Android SDK. This can also come as a zip file but also includes an installer which I will recommend, because the installer will "link" the Android SDK to the JDK. Whatever that means. But because of this linking thing, the JDK has to be fully installed first in order to run.
http://developer.android.com/sdk/index.html

4) Add SDK Platform. After the installer from step 3 finishes, start the SDK program. Start checking off stuff to add. You need at least ONE platform to begin developing in android. You will need to download all the versions you plan on testing on. Be sure to add packages in small groups, if you try to do it all at once it crashes or never finishes.

5) "Download"/Install/Configure ADT plugin. Finish downloading the SDK in step 4 before attempting this. Adding the ADT to Eclipse requires use of the "Adding new software" option from the Help menu. Its awful and feels wrong. Instructions at the link below. Be sure to follow the steps for downloading AND configuring the ADT plugin!



6) Create an AVD (Android Virtual Device.)  This is the emulator. I set the target to Android 2.2 - API Level 8, and the skin to WVGA854
http://developer.android.com/guide/developing/tools/avd.html#creating

Resources:
http://developer.android.com/sdk/requirements.html
http://developer.android.com/sdk/installing.html

Thursday, November 18, 2010

Adding xml Layout to an Existing xml Layout Dynamically

So some background information is needed for this tutorial. My project requires many many many screens. It's incredibly difficult to keep track of all these for development purposes, and on top of that it makes load time on the phone mind-bogglingly slow. So I am trying to create generic "blank" screens to use and reuse for my applications. In this particular example, I have created a generic list screen with a TextView "title" and a blank ListView. I already know that I can programically change the row styling, data entries, the text in the title, etc etc. But I needed to add a row of buttons to the bottom. So I created a simple xml layout with some buttons inside a horizontal linear layout. This is where I hit the snag. I assumed it would be simple to just say mainlayout.addView(extrabuttonslayout); 


I was wrong.

So after three or four days of searching, attempting, failing... (Yeah I know I'm slow) I magically discovered four magical lines of text that allow me to make all my wildest dreams come true. At least for now.

So here's how I did it:

main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_height="fill_parent"
android:layout_width="fill_parent" android:id="@+id/LinearLayout_listview">
<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent" android:text="title" android:id="@+id/TextView_Title"
android:padding="5px" android:textSize="20px" />
<ListView android:layout_height="wrap_content" android:id="@android:id/list"
android:layout_width="fill_parent" android:layout_weight="1" />
<FrameLayout android:layout_height="wrap_content"
android:id="@+id/FrameLayout_listview" android:layout_width="fill_parent" />
</LinearLayout>


extrabuttonlayout.xml

<LinearLayout android:layout_height="wrap_content" android:layout_width="fill_parent"
android:gravity="center" android:id="@+id/LinearLayout_er">
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Search"
android:minWidth="100px" android:id="@+id/btnEmergencyResponse_Search"></Button>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="Exit"
android:minWidth="100px" android:id="@+id/btnEmergencyResponse_Exit"></Button>
</LinearLayout>

and finally the oh so dynamic MainActivity.java (I only included the part where I dynamically add a view, for info on how to dynamically populate a listview, or handle click evens, see my other entries.) Basically here we are setting our layout to be a "view" and then adding the view to the main layout. Silly me, I already thought it was a view...

public class MainActivity extends ListActivity {

LayoutInflater linflater;
LinearLayout llList;
LinearLayout llER;


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

//trying to add view to listview.xml
llList = (LinearLayout) findViewById(R.id.LinearLayout_listview);
                linflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View myView = linflater.inflate(R.layout.extrabuttonlayout, null);
                llList.addView(myView);


}
}

Wednesday, October 13, 2010

Using Intent and Bundle to pass String values to a new Activity.

So it took me three days to figure out how to pass on a string value from an old activity to a new one. This version uses bundle and intent.

I have only used this when starting a new activity with a button , list item , and menu item clicks events, although I'm sure it can be applied to many more types. 

You will need two activities. My example uses a list item click to set up a regular intent. A bundle is created with a string value, and its variables are ("unique.key.name", "The string you want to pass on"). (items[position]) is code that displays the text value of the list item that was selected. Then the bundle is added to the intent.

Page1.java
public void onListItemClick(ListView parent, View view, int position, long id) {
     Intent i = new Intent(Page1.this, Page2.class);
Bundle extras = new Bundle();
extras.putString("my.unique.extras.key", (items[position]) + " Details");
i.putExtras(extras);                
startActivity(i);
    }

Page2 activity needs to have a textview item ready to receive the bundle (this would look like uniquetextview.setText(extras.getString("("my.unique.extras.key")). An alternative is to set the bundle to be the activities title, as in my example below.

Page2.java

  // Adds selected listview item to title
        Bundle extras = this.getIntent().getExtras();
if ( extras != null ) {
 if ( extras.containsKey("my.unique.extras.key") ) {
 this.setTitle(extras.getString("my.unique.extras.key"));
 }
}

Thursday, October 7, 2010

Easy ListView with Anchored Header/Footer and "Custom" Row Layout.

This is the basic listview that has been working great for me.

Disclaimer: While the list item view for this is "custom" it does not allow you to provide more than one view per list item. You can customize that one item (background, font, size, color, etc.) To add more views to a list item please see my entry on custom list adapters.

First is the page layout. I only included a simple textview header, but it could easily be replaced with buttons or checkboxes or anything. The surrounding linear layout but be set to "fill_parent" height and width and also have a vertical orientation. The listview width should be set to "fill_parent" so that the whole list row is clickable and not just the text. layout_weight should be set to 1 which will cause the listview to expand to the height of available space in the window, pushing the header or footer to be docked at the top or bottom.



pageone.xml

xmlns:android="http://schemas.android.com/apk/res/android"

  android:layout_height="fill_parent"
  android:layout_width="fill_parent"
  android:orientation="vertical" >

<TextView android:layout_height="wrap_content"
  android:layout_width="fill_parent"
  android:text="This is the Header"
  android:id="@+id/Header" >
</TextView>

<ListView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_weight="1"
  android:textFilterEnabled="true"
  android:id="@android:id/list" >
</ListView>
</LinearLayout>


The row layout is important if you want to customize the look of your list (like text size, color, etc). Otherwise, android has some built in layouts that can be used. In my example, I am just using a single textview (easily populated by string values using simpleadapter) with a small font. Add more textviews in a horizontal linear layout for columns, or vertical for two rows of text. Use relative layout to add photos and for even more customization. Remember the id of the textviews that will be populated by simple adapter later on. (EDIT: If you want to use additional text views, image views check boxes or whatever, you need to use a custom adapter!)

list_item.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:padding="10dp"
  android:textSize="16sp"
  android:id="@+id/label">
</TextView>


In the java file, include a String of the items you want to display before the onCreate. Set the list Adapter in onCreate. Set up list item click event handler after onCreate. Right now, it is set up to display a toast message of the list item selected.

PageOne.java

public class StepTherapy extends ListActivity {

String[] items={"lorem", "ipsum", "dolor", "sit", "amet",
"consectetuer", "adipiscing", "elit", "morbi", "vel",
"ligula", "vitae", "arcu", "aliquet", "mollis",
"etiam", "vel", "erat", "placerat", "ante",
"porttitor", "sodales", "pellentesque", "augue",
"purus"};
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.steptherapy);

ListView lv = (ListView)getListView();
        lv.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, R.id.label, items));
    public void onListItemClick(ListView parent, View v, int position, long id) {
            Toast.makeText(getApplicationContext(), ((TextView) v).getText(), Toast.LENGTH_SHORT).show();
}
}




Monday, October 4, 2010

Easy Tab Layout using separate Activities to fill Tab Content.

This is the working tab layout that I have designed thus far. This project requires three xml layouts, two xml drawables and a three java classes (and two png drawables for tab logos).


The main.xml file should have the following. Elements like buttons or TextViews that are needed to be displayed outside of the tabs or tab window should be placed above or below TabHost. Use the include method to add tab content layout files.


main.xml
<TabHost
   xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/tabhost" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:isScrollContainer="true">

<LinearLayout android:orientation="vertical" 
    android:layout_width="fill_parent" 
     android:layout_height="fill_parent">
<TabWidget android:id="@android:id/tabs" 
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content">
</TabWidget>
<FrameLayout android:id="@android:id/tabcontent" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"><
/FrameLayout>
</LinearLayout>
</TabHost>
I'm only going to include two tabs. You need to have a separate layout.xml file for each tab's content. 


tab1.xml and tab2.xml (they are the same for the sake of this tutorial)




<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/scheduler_dayview" 
  android:layout_height="fill_parent" 
  android:layout_width="fill_parent" 
  android:orientation="vertical">

<TextView android:layout_width="fill_parent" 
  android:text="Tab 1" 
  android:padding="5px" 
  android:id="@+id/TextView01" 
  android:layout_height="wrap_content"
</TextView>

</LinearLayout>
Again, for the sake of this tutorial, the tabs respective activities are the same. 

Tab1.java and Tab2.java




public class Tab1 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tab1);
        



   }

}

Now for the java class.

TabLayoutExample.Java

public class TabLayoutExample extends TabActivity {

    // Called when the activity is first created. 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        // Tab Stuff
        
Resources res = getResources(); 
        TabHost tabHost = getTabHost();  
        Intent intent;  

        // Create an Intent to launch an Activity for the tab 
        intent = new Intent().setClass(this, Tab1.class);
        // Initialize a TabSpec for each tab and add it to the TabHost
        tabHost.addTab(tabHost.newTabSpec("t1").setIndicator("Tab1",
                          res.getDrawable(R.drawable.tab1))
                      .setContent(intent));

        // Do the same for the other tabs
        intent = new Intent().setClass(this, Tab2.class);
        tabHost.addTab(tabHost.newTabSpec("t2").setIndicator("Tab2",
                          res.getDrawable(R.drawable.tab2))
                      .setContent(intent));

        tabHost.setCurrentTab(0);
    }
}