Archives for category: Android

How do I put graphics on top of the map?

Thanks
Stephen


Make a nested Class which uses canvas graphics to draw a marker of the map. This class extends map.Overlay as shown. We’ve put in a few extra lines to onCreate to associate the overlay with our map.

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.main);
	MapView mapView = (MapView) findViewById(R.id.map);
	mapView.setBuiltInZoomControls(true);
	mapView.getController().animateTo(new GeoPoint(
		(int)((N_DEGREES+N_MINUTES/60+N_SECONDS/3600) * 1000000),
		(int)((E_DEGREES+E_MINUTES/60+E_SECONDS/3600) * 1000000))
	);
	mapView.getController().setZoom(10);

	MyLocationOverlay myLocationOverlay = new MyLocationOverlay();
	List list = mapView.getOverlays();
	list.add(myLocationOverlay);

	LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
	lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f, this);
}

@Override
protected boolean isRouteDisplayed() {
	return false;
}

public void onLocationChanged(Location location) {
	if (location != null) {
		double lat = location.getLatitude();
		double lng = location.getLongitude();
		p = new GeoPoint((int)(lat * 1000000), (int)(lng * 1000000));
	        mapView.animateTo(p);
	}
}

class MyLocationOverlay extends com.google.android.maps.Overlay {
@Override
	public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
	super.draw(canvas, mapView, shadow);
	// Converts lat/lng-Point to OUR coordinates on the screen.
	Point myScreenCoords = new Point();
	mapView.getProjection().toPixels(p, myScreenCoords);
	Paint paint = new Paint();
	paint.setStrokeWidth(1);
	paint.setColor(Color.BLACK);
	paint.setStyle(Paint.Style.STROKE);
	canvas.drawCircle(myScreenCoords.x, myScreenCoords.y, 16, paint);
	canvas.drawText("You are here", myScreenCoords.x, myScreenCoords.y, paint);
	return true;
}

You might notice we haven’t defined ‘p’. Nest this class inside your map code, with location updates, and p will be defined globally, of type GeoPoint.

Advertisements

Could you advice how to set a canvas array to store the notes that user key in? I am trying to change my coding to the SurfaceView, and use the surface holder.

ChooChin


I liked your prototype, but the displayed musical scores were too small to accurately drag notes onto.  I suppose it depends how nimble your fingers are, but I’ve noticed that the HTC Android touch screen doesn’t feel as accurate as my Apple device.  So I think the editable music score area should be bigger than the displayed music.  I imagined panning along the music score, and selecting a portion to edit, which is rendered larger at the bottom of the screen.

I like SurfaceView, but in this case I think a normal View/invalidate() would be better.  The screen isn’t constantly animated.  Only when you edit notes.

In my implementation, I store the notes numerically in the mNotes array.  0 (zero) corresponds to f, 1 to e, 2 to d, and so on.  -1 corresponds to g.  Integer.MAX_VALUE means there is no note at that position.

Rather than dragging notes onto the score.  Just touch the score, and a note will appear at that position.  Then drag vertically into the right position.  Any note can be edited after it has been placed.  To remove a note drag up or down beyond the editable region.

 

package com.danielfreeman.musicalscore;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class EditBar extends View implements OnTouchListener {

	protected static final int BACKGROUND_COLOUR = Color.WHITE;

	protected static final int LINE_COLOUR = Color.BLACK;
	protected static final int NOTE_COLOUR_OFF = Color.DKGRAY;
	protected static final int NOTE_COLOUR_ON = Color.BLACK;

	protected static final float LINE_SPACING = 20.0f;
	protected static final float TOP = 128.0f;
	protected static final float MARGIN = 16.0f;

	protected static final int NOTES_IN_BAR = 10;
	protected static final int NOTE_LOW = -4;
	protected static final int NOTE_HIGH = 12;

	protected static final float NOTE_X = 3;
	protected static final float NOTE_Y = 6;
	protected static final float STALK_UP = -64;
	protected static final float STALK_DOWN = 68;
	protected static final float SEG = 16;
	protected static final int MID = 4;

	protected Paint mScorePaint = new Paint();
	protected Paint mNotePaint = new Paint();
	protected int [] mNotes = new int[NOTES_IN_BAR];
	protected boolean mDragging = false;
	protected int mLastIndex = -1;

	public EditBar(Context context) {
        super(context);
        for (int i = 0; i<NOTES_IN_BAR; i++) mNotes[i] = Integer.MAX_VALUE;
        initialiseColours();
    }

    @Override
    protected void onDraw(Canvas canvas) {
    	canvas.drawColor(BACKGROUND_COLOUR);
    	drawScore(canvas);
    	drawNotes(canvas);
    }

    protected void initialiseColours() {
    	mScorePaint.setColor(LINE_COLOUR);
    	mScorePaint.setStyle(Style.FILL_AND_STROKE);
    	mNotePaint.setColor(NOTE_COLOUR_OFF);
    	mNotePaint.setStyle(Style.FILL_AND_STROKE);
    }

    protected void drawScore(Canvas canvas) {
    	for (int i=0; i<5; i++) {
    		float y = TOP + i * LINE_SPACING;
    		canvas.drawRect(MARGIN, y, getWidth()-MARGIN, y+1, mScorePaint);
    	}
    }

    protected void drawNotes(Canvas canvas) {
    	 for (int i = 0; i<NOTES_IN_BAR; i++) {
    		 int position = mNotes[i];
    		 if (position!=Integer.MAX_VALUE) {
    			 drawQuarterNote(canvas, i, position);
    		 }
    	 }
    }

    protected void drawQuarterNote(Canvas canvas, int index, int position) {
    	float x = indexToX(index);
    	float y = positionToY(position);
    	if (position<0 || position>9) {
    		float y0 = positionToY(2*(position/2));
    		canvas.drawRect(x - SEG, y0, x + SEG, y0+1, mNotePaint);
    	}
    	Path path = new Path();
    	path.moveTo(x + 3*NOTE_X, y - NOTE_Y);
    	path.cubicTo(x + 5*NOTE_X, y, x-NOTE_X, y+2*NOTE_Y, x-3*NOTE_X, y+NOTE_Y);
    	path.cubicTo(x - 5*NOTE_X, y, x+NOTE_X, y-2*NOTE_Y, x + 3*NOTE_X, y-NOTE_Y);
    	canvas.drawPath(path, mNotePaint);
    	canvas.drawRect(x + 3*NOTE_X - 1, y - NOTE_Y/2, x + 3*NOTE_X + 1 , y - NOTE_Y/2 + ((position > MID ) ? STALK_UP : STALK_DOWN), mNotePaint);
    }

    protected float indexToX(int index) {
    	return MARGIN + (index + 0.5f)*(getWidth()-2f*MARGIN)/NOTES_IN_BAR;
    }

    protected float positionToY(int position) {
    	return TOP + position * LINE_SPACING / 2f;
    }

    protected int xToIndex(float x) {
    	return (int)Math.floor((x-MARGIN)/((getWidth()-2f*MARGIN)/NOTES_IN_BAR));
    }

    protected int yToPosition(float y) {
    	return (int)Math.floor((y-TOP)/(LINE_SPACING/2));
    }

    protected void editNote(float x, float y) {
    	int index = xToIndex(x);
    	if (index>=0 && index<NOTES_IN_BAR) {
    		if (mLastIndex!=index) mDragging = false;
    		int position = yToPosition(y);
    		int note = mNotes[index];
    		if (note == Integer.MAX_VALUE || note == position) mDragging = true;
    		if (mDragging) {
    			if (position>=NOTE_LOW && position<=NOTE_HIGH) mNotes[index] = position;
    			else mNotes[index] = Integer.MAX_VALUE;
    			invalidate();
    		}
    		mLastIndex = index;
    	}

    }

    public boolean onTouch(View view, MotionEvent event) {
    	return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        editNote(event.getX(), event.getY());
        return true;
    }

}

The main program is as you’d expect.

package com.danielfreeman.musicalscore;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;

public class MusicalScore extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        EditBar editBar = new EditBar(this);
        setContentView(editBar);
    }
}

Note, there seems to be a problem with displaying the graphics properly in the 1.5 emulator. The 2.2 emulator works ok.

I’ve put the following attribute into the application tag of the manifest file to make the application full screen.

android:theme=”@android:style/Theme.NoTitleBar.Fullscreen”

Yesterday, in about two hours, I probably presented enough information about games to fill an entire course.  (Hey!, that would be cool).  I also ended up inspiring MYSELF to write a new game.  I hope that some of you were inspired to create a game too.

I’d encourage you to have a go.  While I don’t pretend to be a guru in absolutely all areas of Android development (anyone who makes this claim is lying), I know quite a bit about games – and I can give you all the expert help you need.  Well, I can help with the easy bit – programming.  Design is another matter.  I’m just in awe of anyone who can come up with great-looking game characters and worlds.

There seemed to be some confusion when I talked about depth-ordering (z-ordering) in an isometric projection world.  After the presentation, I was troubled as to whether people had understood what I was talking about.  I wasn’t sure what was at the root of the misunderstanding either.  So that’s probably why my answers didn’t seem to resolve stuff for you.

I was talking about how to decide what was in front of what in an orthographic world.

The brute-force approach would be to calculate the distance from the observer, and sort the objects based on that.  But sorting can be computationally intensive.  Especially in an MMO (Massive Multiplayer Online) game where there may be many avatars in the scene, all moving around.

I presented a standard simplification strategy to z-ordering.  The one used by the OpenSpace Flash engine that I’ve used.

In this strategy we effectively number each cell in the way shown above.  Then we apply a rule something within a cell with a larger number is placed in front of something in a cell with a smaller number.

Note that cell 10 is actually further away from the observer than cell 9.  But this doesn’t matter because there wouldn’t be any overlap between the contents of these cells.

So, we spoke about this strategy working for graphical things in the same locality.  This is what seemed to confuse people.  Some of you thought of this as a limitation of the scheme, and seemed to be searching for a fix to overcome this limitation.  When in fact, the “limitation” never manifests itself in a way that the observer would notice.  There’s nothing to fix.

Maybe the misunderstanding lies with an understanding of what depth or z-ordering actually does.  Consider two shapes.  A blue square, and yellow circle.  If the shapes overlap, then we notice which shape is in front of the other.  We NOTICE the z-ordering.

        

In the first example above, the yellow circle is in front of the blue square.  In the second example, it is behind.  If these shapes were associated with cells in our orthographic grid, the shape in the cell with the highest number would be placed in front.  This works well for cells in the same locality.

But when the cells AREN’T in the same locality, the likelihood is that the images associated with these cells WON’T OVERLAP.

  

In the first example above, the yellow circle is in front of the blue square.  In the second example, it is behind.  Spot the difference?  There ISN’T ANY.  Not to the observer anyway.  If the image associated with cell 10 of the orthographic world gets placed in front of the image associated with the image associated with cell 9 (Event though cell 9 is closer to the observer).  No one will notice.  As far as the observer is concerned, everything looks right.  There’s nothing to fix.  The scheme works.

But when images associated with a cell occupy a larger area of a world, then it is possible for images that are not in the same locality to overlap.  Yesterday, I gave the example of a house, and how we carefully choose which cells to associate (register) the images to – so that our scheme still works.

Yesterday, someone asked about the case where the house had a low roof.  So an avatar seen at cell position 10 or 20 could be seen over the top of the building.

It was at this point that I realised I had REALLY confused you all.  I and couldn’t comprehend the root of this confusion to fix things.

Suppose we have an avatar behind the house, at cell position 10.  Suppose there is no overlap between the house and the avatar, so the avatar can be clearly seen.  It is not obscured in any way.  So it doesn’t matter whether the avatar is ordered in front or behind the house.

The blue square represents the avatar.  The yellow circle represents the house.  They don’t overlap.  In the first example above, the yellow circle is in front of the blue square.  In the second example, it is behind.  Spot the difference?

  

But actually, in the house example, an avatar at cell position 10 IS BEHIND the house.  Whether the avatar is obscured by the house or not.  It is further away from the observer, and our depth-ordering (z-ordering) scheme concurs with this – and places it behind.  There’s no conflict.  No problem.

I think some people thought I was describing some kind of hidden surface removal?  Or maybe object clipping?  I don’t know?

I wasn’t describing this at all.  I was just talking about what was behind, or in-front-of what.

If something is ordered behind something else, but it doesn’t overlap, and it can be seen clearly – there’s no problem.  Just because we’ve decided that it’s behind, we’re not removing it or making it invisible, or clipping it or anything.  It’s still there.  It can be seen.

Maybe just saying it was “behind” something, when there was no overlap was enough to confuse people yesterday?  I don’t know.

I still can’t understand root of the misunderstanding yesterday.  Hopefully, I’ve explained myself better in this blog.  If you still have a problem, please leave a comment.  I really want to resolve the misunderstanding – whatever it is.

It’s not possible to cover ALL of Android development in a week. While my course is action-packed, there are some subjects that I don’t have time to do justice to. But I often give my students a web link to a tutorial or online resource to follow up in their own time. I’ve just updated the entire list for the new courses we’re running around Malaysia. So I thought I’d put the list up here for everyone:-

Sound

http://www.droidnova.com/creating-sound-effects-in-android-part-1,570.html

Camera

http://marakana.com/forums/android/examples/39.html

XML Parsing

http://www.ibm.com/developerworks/opensource/library/x-android/index.html?ca=dgr-lnxw82Android-XML

Widgets

http://www.helloandroid.com/files/xmaswidget/android_howto-hellowidget.pdf

Upload/Download image files

http://www.helloandroid.com/tutorials/how-download-fileimage-url-your-device

http://getablogger.blogspot.com/2008/01/android-how-to-post-file-to-php-server.html

Parcels

http://techdroid.kbeanie.com/2010/06/parcelable-how-to-do-that-in-android.html

3D games

http://www.droidnova.com/android-3d-game-tutorial-part-i,312.html

Games engines

http://rokonandroid.com/

http://rokonandroid.com/tutorials/41-beginner

http://www.emanueleferonato.com/2009/01/27/box2d-tutorial-for-the-absolute-beginners/

http://www.andengine.org/forums/tutorials/mimminito-s-tutorial-list-t417.html

http://unity3d.com/support/documentation/Manual/Tutorials.html

http://www.jpct.net/wiki/index.php/Main_Page

video tutorials and training

http://xtensivearts.blip.tv/posts?view=archive&nsfw=dc

VideoView

http://www.androidpeople.com/android-videoview-example/

http://www.helloandroid.com/tutorials/how-play-video-and-audio-android

http://www.youtube.com/watch?v=yqCj83leYRE&feature=player_embedded

PhoneGap in Android

http://www.androidcompetencycenter.com/2010/07/phonegap-in-androideclipse/

Files

http://www.anddev.org/novice-tutorials-f8/working-with-files-t115.html

Activities

http://www.anddev.org/novice-tutorials-f8/passing-data-to-sub-activities-t305.html

Animation

http://stuffthathappens.com/blog/2008/11/13/android-animation-101/

Augmented reality

http://www.devx.com/wireless/Article/42482/1954

Android app Inventor

http://www.androidcentral.com/google-unveils-android-app-inventor-no-coding-skill-required

Help forums

http://www.anddev.org

http://stackoverflow.com/questions/tagged/android

http://androidforums.com/application-development/

http://groups.google.com/group/android-platform?pli=1

A couple of students need to take pictures, and store their pictures in the database.  This allowed them to easily associate (tag) other data to the each picture, and manage their pictures, access and remove them easily.  We store binary data in a database record using a BLOB.

The database helper class looks like this:-

package com.danielfreeman.android.classes;

import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;

public class MyDBHelper extends SQLiteOpenHelper {

	final protected static String DATABASE_NAME="pictures";

	public MyDBHelper(Context context) {
		super(context, DATABASE_NAME, null, 4);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("DROP TABLE storedImages;");
		db.execSQL("CREATE TABLE storedImages (_id INTEGER PRIMARY KEY, image BLOB, tag TEXT);");
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		if (oldVersion >= newVersion)
			return;

	    onCreate(db);
	}
}

I put the application inside a TabActivity. Although the camera preview gets a bit squashed up this way.  So the UI needs a bit of thought.  Nevertheless, here is the main Activity code, based on Marakana’s camera tutorial:-

package com.danielfreeman.android;

import com.danielfreeman.android.classes.Preview;
import com.danielfreeman.android.classes.MyDBHelper;

import android.app.TabActivity;
import android.content.ContentValues;
import android.content.pm.ActivityInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TextView;
import android.widget.TabHost.TabSpec;

public class HelloCamera extends TabActivity {

  protected Preview preview;
  protected Button buttonClick;
  protected MyDBHelper myDBHelper;
  protected TabHost tabHost;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

    tabHost = getTabHost();
    newTab("gallery", null, R.id.tab0);
    newTab("camera", null, R.id.tab1);

    preview = new Preview(this);
    ((FrameLayout) findViewById(R.id.preview)).addView(preview);

    buttonClick = (Button) findViewById(R.id.buttonClick);
    buttonClick.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
      }
    });

    myDBHelper = new MyDBHelper(this);
    readDatabase();
  }

  protected void newTab(String label, Drawable icon, int page) {
  	TabSpec tabSpec = tabHost.newTabSpec(label);
  	tabSpec.setIndicator(label,icon);
  	tabSpec.setContent(page);
  	tabHost.addTab(tabSpec);
  }

  // Called when shutter is opened
  ShutterCallback shutterCallback = new ShutterCallback() {
    public void onShutter() {
    }
  };

  // Handles data for raw picture
  PictureCallback rawCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
    }
  };

  // Handles data for jpeg picture
  PictureCallback jpegCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {

    SQLiteDatabase db = myDBHelper.getReadableDatabase();
    ContentValues values = new ContentValues();
    values.put("image", data);
    db.insert("storedImages", "tag", values);
    preview.camera.startPreview();
    }
  };

  protected void readDatabase() {
	  TextView info = (TextView) findViewById(R.id.info);
	  info.setText("Integer.toString(cursor.getCount())");
	  SQLiteDatabase db = myDBHelper.getReadableDatabase();
	  Cursor cursor = db.rawQuery("SELECT * FROM storedImages ;", null);

	  info.setText(Integer.toString(cursor.getCount()));

	  if (cursor.getCount()>0) {
		  cursor.moveToNext();
		  ImageView image = (ImageView) findViewById(R.id.image);
		  byte[] data = cursor.getBlob(cursor.getColumnIndex("image"));
		  image.setImageBitmap(BitmapFactory.decodeByteArray(data, 0, data.length));
	  }
  }

}

I use a db.insert() method to put the jpeg data into the database.  Note that the readDatabase() class is very simple.  Although it retrieves the entire database, it only displays one image.

Finally, here is the Preview class:-

package com.danielfreeman.android.classes;

import java.io.IOException;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Preview extends SurfaceView implements SurfaceHolder.Callback {

  SurfaceHolder mHolder;
  public Camera camera;

public Preview(Context context) {
    super(context);

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
  }

  // Called once the holder is ready
  public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, acquire the camera and tell it where
    // to draw.
    camera = Camera.open();
    try {
      camera.setPreviewDisplay(holder);

      camera.setPreviewCallback(new PreviewCallback() {
        // Called for each frame previewed
        public void onPreviewFrame(byte[] data, Camera camera) {
          Preview.this.invalidate();
        }
      });
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  // Called when the holder is destroyed
  public void surfaceDestroyed(SurfaceHolder holder) {
    camera.stopPreview();
    camera = null;
  }

  // Called when holder has changed
  public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    camera.startPreview();
  }

}

I haven’t included the layout file, as it probably needs rethinking, so you can probably come up with a better UI.  At the moment it’s wrapped up in a TabHost, a preview area (FrameLayout), and includes a Button called ‘buttonClick’.

Dear Android people, (Cyborgs?),

I have four items of news that you’ll probably be interested in:-

1. Android Clinic

The next Android Clinic will be on Saturday October 2nd. By popular demand, we’re running this one at a weekend, as many people have said they have work commitments on week days. If we get a good turn-out, then we’ll run further Clinics on weekends.

The theme for this clinic is “Writing Games”. A few people have expressed an interest in games, and those of you who’ve finished their MDEC prototype might be looking for a new project to undertake.

As usual, the timetable for the days is:-

10:00am to 12:00pm : Presentation (Writing Games)
12:00pm to 1:00pm : Lunch
1:00pm onwards : Individual support for your projects

Please be on time if you want to attend the presentation. Let us know if you’re coming.

See: https://sagemobile.wordpress.com/2010/09/10/android_clinic/

…for address, directions, and parking information.

These clinics are supported by Maxis, the Maxis 1Store, and the Maxis developer programme.

http://mdp.maxis.com.my
https://developer.1store.com.my/wps/portal/1store

2. Our Top Applications

Maxis have asked us to identify applications being developed that will be given special support. These applications are to be sold on the Maxis 1Store. We will be providing help in the form of technical support, pre-submission constructive reviews, discussions about design decisions, etc.

If you are thinking of selling an Application on the Maxis 1Store, and you would like YOUR application to be considered – CONTACT US NOW!

If you’ve already submitted your application to the Maxis store, or you’re about to do so – let us know.

3. New Android Training Courses

Sage will be running new Android training courses in Kota Baru and Kuching. Dates are still to be confirmed, but these will start on or after the 18th of October. Do you know anyone who’d like to attend? Please, spread the word, tell people about this, we’re recruiting participants NOW.

4. mYprize competition

http://www.myprize.my/what-is-myprize
Official website : http://www.ytlcomms.my/EN/Index.aspx

What is mYprize?

YTL Communications Sdn Bhd is launching the world’s first nationwide 4G network in Malaysia. YTL Communications’ 4G network is a wireless, high-speed, mobile Internet service.

They are challenging innovators and creative entrepreneurs around the world to submit original ideas, create unique applications or devices for the YTL 4G network today. They’ve created a competition, called mYprize, that offers a total of USD 1,000,000 in prize money for the best innovations for 4G.

Following on from WCs questions, I appreciate that the Android course didn’t go into any detail storing data on the server.  It was a Android course after all, not a server technology course.  Having said that, I always thought an overview of PHP and mySQL would be beneficial to a lot of students, who had no prior experience in server-side code.  So here it is, in a nutshell:-

I need to update the data on weekly basis.
May i know where the data can be stored? Does google provide a server to host the data?
My apps is about the daily consumer good pricing.
WC

It’s up to you to host your data.  Personally, I use a free hosting service provided by http://www.byethost.net.  Free hosts like this come with the ability to run PHP, and set up mySQL databases.

Let’s start with a simple PHP program:

<html>
<body>
<?php echo "Hello World!"; ?>
</body>
</html>

You can mix up PHP with HTML, as above. The parts of the program that do PHP things are enclosed by <?   ?> tags.  For example, the above program prints (echoes) “Hello World”.

PHP can execute commands to query an SQL database.  You will have already learnt some SQL language on the Android course.  This was related to Android’s SQLlite.  Here is a program to set up a database table, and populate it with some records:-

<?php
mysql_connect("localhost","root","password");
mysql_select_db("");
mysql_query("DROP DATABASE DEMO;");
mysql_query("CREATE DATABASE DEMO;");
mysql_select_db("DEMO");
mysql_query("CREATE TABLE PEOPLE(ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,NAME TEXT,AGE INT);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Albert Smith',32);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Justin Archer',28);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Sarah Tully',35);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Janet Brown',30);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Robert Jones',26);");
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('Alice Wendell',38);");
?>

As you can see, this program CREATEs a new TABLE, and INSERTs some records.

The strings that you pass to mysql_connect will relate to the details of the database you set up. You’ll need to set up a database first from the web host control panel. This is quite straight forward usually – but your web host probably has a user discussion forum, and there’s much more help and information on the internet about PHP and mySQL than there is for Android – so you should be able to sort this out yourself.

The following PHP program reads the database, and spits out the data as XML.

<?php
mysql_connect("localhost","root","password");
mysql_select_db("DEMO");
$query="SELECT * FROM PEOPLE;";
$result=mysql_query($query) or die("error:".$query);
header('Content-type: application/xml; charset="utf-8"',true);
echo "<table>\n";
while ($row=mysql_fetch_array($result)) {
	echo "<record>\n";
	echo "<id>".$row['ID']."</id>\n";
	echo "<name>".$row['NAME']."</name>\n";
	echo "<age>".$row['AGE']."</age>\n";
	echo "</record>\n";
	}
echo "</table>\n";
?>

There are other ways to manipulate XML in PHP, but strings, and echo are easy to understand.
Finally, sometimes, you’ll need to pass data from the Android phone to the server. Like this:-

public void postData() {

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.yoursite.com/insert.php");

try {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs.add(new BasicNameValuePair("name", "Fred Bloggs"));
        nameValuePairs.add(new BasicNameValuePair("age", "45"));
        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        HttpResponse response = httpclient.execute(httppost);

       } catch (ClientProtocolException e) {

       } catch (IOException e) {
   }
}

And insert.php looks like this:-

<?php
mysql_connect("localhost","root","password");
mysql_select_db("DEMO");
$name = $_POST['name'];
$age = $_POST['age'];
mysql_query("INSERT INTO PEOPLE (NAME,AGE) VALUES ('$name',$age);");
?>

$_POST[label] is used to retrieve the values sent by the Android device.