Search This Blog

Loading...

Saturday, January 15, 2011

Learn Android through some code...

I have been pretty busy lately and didn't really get a chance to post anything new here, which is a big shame by the way...however I have had quite a few requests asking for the source code of EbaySearch application and TicTacToe Game that I have used to demonstrate 2D features in Android. so finally I decided to create a couple of projects in GitHub and put all the source codes there for anybody who might be interested. there are 2 separate repositories which can be found at :

1- EbaySearch
2- TicTacToe

Please remember these codes have been written a long time ago(relatively) using Android SDK 5 (Android 1.6) and honestly I haven't tested them lately to make sure if they are still OK, consequently there is no guarantee that they work properly on newer versions, Although I doubt if there is any major problem getting them to work on newer versions unless something has been changed dramatically in newer versions and broken the code.
nonetheless I thought this would be helpful for anyone who prefers to learn Android through some real code rather than reading books and stuff or is just curious about the full source code of those applications which as it turn out lots of people are ;)
the last thing I'd like to add is although there is a lot to learn from these source codes, please don't forget that they have all been written for experimental purposes and they might not be the best possible way to go in some circumstances...

Wednesday, September 15, 2010

Sprint Challenges Developers to Create Innovative 4G Apps

I just received this E-mail, sounds like a great opportunity for anyone who is up for a little bit of challenge, I would definitely give it a go if I wasn't dead busy at the moment....

here it goes:

Developing mobile applications is very exciting. From developing the concept, building out wireframes, all the way to launch, seeing your creation come to life is very gratifying as a developer. Sprint recognizes this gratification, and wants to continue that feeling by inviting you and your blog audience to a unique app development contest.

Sprint is leading the way with 4G speed, and wants to place some Android app developers in the lime light to showcase what they can do when 4G is thrown into the mix. Sprint, along with partners Wired, Reddit and Ars Technica have created the Sprint 4G App Challenge, a contest to develop 4G mobile applications to demonstrate the benefits and features of a 4G application.

Below contains information regarding the contest

All app submissions must fall within one of the following categories:

Video, Multimedia & Augmented Reality

Gaming

Productivity, Business & Utilities

Social Networking

Entertainment


Submission phase: Today through November 5th


Category judging will take place in November by representatives from Wired, Reddit, ArsTechnica and Sprint, and the winners will be announced at the Wired Store on December 16th.



EACH CATEGORY WINNER RECEIVES:

$50,000

1 year membership to Sprint’s Professional Developers Program

250 hours for the Virtual Developer Lab

1 Evo device with 1 year service

Press announcements promoting winning apps



For more information on developing and submitting an application into the Sprint 4G App Challenge, please visit: http://www.sprint.com/appchallenge

Thursday, May 6, 2010

Ebay-Search Upgraded

Version 0.2 of Ebay-Search application has been published, this version will enable users to do more sophisticated searches using different Ebay search Filters such as Condition, Listing type, Available Country , etc...

Monday, March 15, 2010

Android Layout Managers

Sometimes There are some simple rules and facts which can easily improve the quality and performance of your applications but they are widely ignored either because of lack of knowledge or just because of our reluctance to change the way we're already doing stuff.
One of these basic principles in android is Layout management which is hugely being misused, I mean if you go through different android samples and blogs (including this Blog!) more than 70% of all samples and examples are using LinearLayout even for some very simple layout that could have been simply done by using a FrameLayout. I am no exception and actually I used to think if I am comfortable with LinearLayout and everybody else is using it, why should I use another layout? but the thing is LinearLayout is a pretty heavyweight LayoutManager compare to FrameLayout and a far less flexible layout compare to RelativeLayout (this inflexibility usually leads to one of those ugly layout files with 4 or 5 nested LinearLayout) and if you are developing an application with a GUI a bit more complicated than a basic TextField and Button (specially when we have a repeating object like what we have in a ListView),Switching from LinearLayout to FrameLayout or RelativeLayout can tangibly improve the responsiveness of your application.
Just to see that using FrameLayout or RelativeLayout is pretty much as easy and as straight-forward as LinearLayout is, I'm gonna show you Six simple examples which will hopefully give you the idea of how they work so that you are gonna be able to choose a more efficient layout when you are designing a page.
Here are those Six examples I was talking about, I have used Buttons for all subviews just for the sake of simplicity but it can obviously be any other type of View:





1

2

3


4



5



6




and here is the XML source that generates each one of these layouts:

1

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingTop="30dip"
android:background="@color/black">

<Button
android:layout_width="fill_parent"
android:layout_height="90dip"
android:layout_alignParentTop="true"
android:text="View 1"
android:id="@+id/view1" />

<Button
android:layout_width="fill_parent"
android:layout_height="90dip"
android:layout_below="@id/view1"
android:text="View 2"
android:id="@+id/view2" />

<Button
android:layout_width="fill_parent"
android:layout_height="90dip"
android:layout_below="@id/view2"
android:text="View 3"
android:id="@+id/view3" />

<Button
android:layout_width="fill_parent"
android:layout_height="90dip"
android:layout_below="@id/view3"
android:text="View 4"
android:id="@+id/view4" />

<Button
android:layout_width="fill_parent"
android:layout_height="90dip"
android:layout_below="@id/view4"
android:text="View 5"
android:id="@+id/view5" />


</RelativeLayout>

2

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="5dip"
android:background="@color/black">

<Button
android:layout_width="100dip"
android:layout_height="fill_parent"
android:layout_gravity="left"
android:text="View 1"
android:id="@+id/view1" />

<Button
android:layout_width="100dip"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:text="View 2"
android:id="@+id/view2" />

<Button
android:layout_width="100dip"
android:layout_height="fill_parent"
android:layout_gravity="right"
android:text="View 3"
android:id="@+id/view3" />


</FrameLayout>

3

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/black">

<Button
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_gravity="left|top"
android:layout_margin="15dip"
android:text="View 1"
android:id="@+id/view1" />

<Button
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_gravity="right|top"
android:layout_margin="15dip"
android:text="View 2"
android:id="@+id/view2" />

<Button
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_gravity="left|center_vertical"
android:layout_marginLeft="15dip"
android:text="View 3"
android:id="@+id/view3" />

<Button
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="15dip"
android:text="View 4"
android:id="@+id/view4" />

<Button
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_gravity="left|bottom"
android:layout_margin="15dip"
android:text="View 5"
android:id="@+id/view5" />

<Button
android:layout_width="120dip"
android:layout_height="120dip"
android:layout_gravity="right|bottom"
android:layout_margin="15dip"
android:text="View 6"
android:id="@+id/view6" />


</FrameLayout>

4

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dip"
android:background="@color/black">

<Button
android:layout_width="150dip"
android:layout_height="120dip"
android:layout_gravity="left|top"
android:text="View 1"
android:id="@+id/view1" />

<Button
android:layout_width="150dip"
android:layout_height="120dip"
android:layout_gravity="right|top"
android:text="View 2"
android:id="@+id/view2" />


<Button
android:layout_width="fill_parent"
android:layout_height="200dip"
android:layout_gravity="center"
android:text="View 3"
android:id="@+id/view3" />


<Button
android:layout_width="150dip"
android:layout_height="120dip"
android:layout_gravity="left|bottom"
android:text="View 4"
android:id="@+id/view4" />

<Button
android:layout_width="150dip"
android:layout_height="120dip"
android:layout_gravity="right|bottom"
android:text="View 5"
android:id="@+id/view5" />


</FrameLayout>

5

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dip"
android:background="@color/black">

<Button
android:layout_width="120dip"
android:layout_height="200dip"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:text="View 1"
android:id="@+id/view1" />

<Button
android:layout_width="180dip"
android:layout_height="120dip"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:text="View 2"
android:id="@+id/view2" />


<Button
android:layout_width="120dip"
android:layout_height="100dip"
android:layout_alignParentLeft="true"
android:layout_below="@id/view1"
android:text="View 3"
android:id="@+id/view3" />


<Button
android:layout_width="180dip"
android:layout_height="180dip"
android:layout_alignParentRight="true"
android:layout_below="@id/view2"
android:text="View 4"
android:id="@+id/view4" />

<Button
android:layout_width="fill_parent"
android:layout_height="120dip"
android:layout_alignParentBottom="true"
android:layout_below="@id/view4"
android:text="View 5"
android:id="@+id/view5" />


</RelativeLayout>

6

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dip"
android:background="@color/black">

<Button
android:layout_width="180dip"
android:layout_height="180dip"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:text="View 1"
android:id="@+id/view1" />

<Button
android:layout_width="120dip"
android:layout_height="90dip"
android:layout_toLeftOf="@id/view1"
android:layout_alignParentLeft="true"
android:text="View 2"
android:id="@+id/view2" />


<Button
android:layout_width="120dip"
android:layout_height="90dip"
android:layout_toLeftOf="@id/view1"
android:layout_below="@id/view2"
android:layout_alignParentLeft="true"
android:text="View 3"
android:id="@+id/view3" />


<Button
android:layout_width="fill_parent"
android:layout_height="120dip"
android:layout_below="@id/view1"
android:text="View 4"
android:id="@+id/view4" />

<Button
android:layout_width="180dip"
android:layout_height="180dip"
android:layout_alignParentLeft="true"
android:layout_below="@id/view4"
android:text="View 5"
android:id="@+id/view5" />


<Button
android:layout_width="120dip"
android:layout_height="90dip"
android:layout_toRightOf="@id/view5"
android:layout_below="@id/view4"
android:layout_alignParentRight="true"
android:text="View 6"
android:id="@+id/view6" />


<Button
android:layout_width="120dip"
android:layout_height="90dip"
android:layout_toRightOf="@id/view5"
android:layout_below="@id/view6"
android:layout_alignParentRight="true"
android:text="View 7"
android:id="@+id/view7" />


</RelativeLayout>

Friday, March 12, 2010

My First Android Application ;)

I was struggling with myself for a long time whether to do this or not, and finally I did it.
I uploaded my first Android application in Market yesterday and actually I feel excited about it...
It is not a full-feature application, just a simple Ebay-Search client which will let you search through Items in Ebay...no buying or bidding yet!!
since unfortunately I don't have any Android-enabled phone at the moment so I would really appreciate it if you could download this application, give it a go and let me know how it works on a real device.
Here's some screen-shots of my application :










Monday, February 15, 2010

Android 2D ( A Simple Example )

It has been a long time I wanted to go through Android 2D capabilities and see how that works. and after a little bit of reading and researching about the topic, I developed a simple TicTacToe game which I'm gonna share it with you in this article.
The primary purpose of this example is to dig up some basic Android 2D features and get familiar with some game programming principles. Although TicTacToe is not really an interactive game, I think its simplicity will help us to be focused on what matters most which is actually how to do things in Android rather than how to design and develop an efficient game algorithm for a particular game. (I'm gonna use the same technique that has been used in LunarLandar application, which by the way is a pretty good example in this area).
first of all let's have a look at how our application will be looking like:








Despite the fact that TicTacToe is a pretty easy game to develop, Graphic wise I mean, and can be simply done by extending View Class, I have actually used 'SurfaceView', since apparently it's a better option for developing interactive games in Android. the most important point about SurfaceView class is that it uses two buffers, a drawing buffer and a displaying buffer, you are not allowed to draw directly on displaying buffer and if you need to draw something you will have to get the drawing buffer , fill it and post it as display buffer. as API documentation has mentioned there is no guarantee that anything gets preserved in drawing buffer and as a result we always need to draw anything we want to be shown without taking any presumption that something is already there from last drawing operation.
OK... now that we learned some basic facts about how SurfaceView works, let's have a look at my code and see what we have got there :



public class TicTacToeView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener {

.
.
.

public TicTacToeView(Context context) {
super(context);
getHolder().addCallback(this);
}

public TicTacToeView(Context context,TicTacToe internalState) {
this(context);
this.tictactoe = internalState;
}

.
.
.

class MainThread extends Thread {

private SurfaceHolder surfaceHolder;
private boolean runFlag = false;
boolean firstTime = true;

public MainThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
}

public void setRunning(boolean run) {
this.runFlag = run;
}

@Override
public void run() {
Canvas c;

while (this.runFlag) {

if(firstTime){
drawLines();
firstTime = false;
continue;
}

c = null;
try {

c = this.surfaceHolder.lockCanvas(null);
synchronized (this.surfaceHolder) {
doDraw(c);
updateScores(c);
}
} finally {

if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c);

}
}
}
}

.
.
.

}

.
.
.
}

The first thing we're gonna need in any game is a Game Thread, The idea here is to constantly call a series of methods which are responsible to update some states and draw something based on those states. as I said before when you are dealing with SurfaceView you need to draw into the draw buffer and then post it on the surface, It can be done by calling lockCanvas() and unlockCanvasAndPost() methods of SurfaceHolder class, you can get the associated SurfaceHolder instance of your SurfaceView by calling getHolder() method. as you can see in the above code I have implemented the SurfaceHolder.Callback interface; this interface provides 3 callback methods for monitoring the life-cycle of the SurfaceView, here is my implementation of these methods:



.
.
.

@Override
public void surfaceCreated(SurfaceHolder holder) {

_thread = new MainThread(getHolder());

if(tictactoe == null)
this.tictactoe = new TicTacToe(new TicTacToeHandler(),false);
else
_thread.firstTime = false;

Resources resources = getContext().getResources();

this.background = BitmapFactory.decodeResource(resources, R.drawable.background);
this.X_Player = BitmapFactory.decodeResource(resources, R.drawable.x_pic);
this.O_Player = BitmapFactory.decodeResource(resources, R.drawable.o_pic);


Rect rect = holder.getSurfaceFrame();
this.gameTable_height = rect.height()-56;
this.gameTable_sY = 0;
this.gameTable_width = rect.width();
this.scoreBox_Height = 50;
this.scoreBox_Width = rect.width();
this.scoreBox_sY = rect.height()-this.scoreBox_Height;
this.squares = new Rect[9];

final int square_Width = (int)(gameTable_width-(TABLE_BORDER*4))/3;
final int square_Height = (int)(gameTable_height-(TABLE_BORDER*4))/3;

for(int i=0;i<9;i++){
int row = i%3;
int column = i/3;
int left = ((row+1)*TABLE_BORDER)+(square_Width*row);
int top = ((column+1)*TABLE_BORDER)+(square_Height*column);
this.squares[i] = new Rect(left,top,left+square_Width,top+square_Height);

}

this.tablePaint.setStyle(Style.STROKE);

this.tablePaint.setShader(new LinearGradient(0, 0, this.gameTable_height,
this.gameTable_width,
0xFF000000,
0xFF343434,
TileMode.MIRROR));
this.tablePaint.setStrokeWidth(TABLE_BORDER);
this.tablePaint.setAlpha(0xCC);

this.boxPaint.setStyle(Style.STROKE);
this.boxPaint.setStrokeWidth(BOX_BORDER);
this.boxPaint.setColor(0xFFA90000);

this.textPaint.setColor(0xFF000000);
this.textPaint.setTextAlign(Align.CENTER);
this.textPaint.setTextSize(14);
this.textPaint.setTypeface(Typeface.createFromAsset(getContext().getResources().getAssets(),"HARLOWSI.TTF"));

this.contentPaint.setAlpha(0xDF);

_thread.setRunning(true);
_thread.start();
setOnTouchListener(this);

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {

}
}
}


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
}
.
.
.

in surfaceCreated() method I have initialized some variables and objects such as an instance of TicTacToe class (which will actually take care of game's logic and rules), background Image , cross and circle images and Paint objects that all will be used later to draw the game, here is also a good place to create and start our main thread. then we will kill the main thread in surfaceDestroyed() method to make sure no one's gonna make an attempt to draw anything on the surface after it has been destroyed.
now that we have got anything initialized and the main thread running let's see what is happening in each loop of our thread, as you saw in the first chunk of code above we are actually calling 2 methods each time, doDraw() and updateScores() :



.
.
.

public void doDraw(Canvas canvas) {

canvas.drawBitmap(this.background, 0, 0, null);
drawTable(canvas);

if(this.draw && Xs[0] == Xs[1] && Ys[0] == Ys[1]){
CheckContent();
}
drawContent(canvas);

}

/////////
private void updateScores(Canvas canvas){

final int halfBorder = (int)BOX_BORDER/2;
final Paint paint = textPaint;

Rect rect = new Rect(halfBorder,
this.scoreBox_sY-halfBorder,
this.scoreBox_Width-halfBorder,
(this.scoreBox_sY-halfBorder)+this.scoreBox_Height);
RectF rectf = new RectF(rect);


canvas.drawRoundRect(rectf, 15, 15, this.boxPaint);

canvas.drawText("Your Score : "+this.tictactoe.getYourScore(), 65,this.scoreBox_sY+25,paint);
canvas.drawText("Computer's Score : "+this.tictactoe.getOpponentScore(), 15+(this.scoreBox_Width/3)*2,this.scoreBox_sY+25,paint);

}


private void drawTable(Canvas canvas){

final Paint paint = this.tablePaint;
final float border = TABLE_BORDER;

final int cellHeight = (int)(this.gameTable_height-(2*border))/3;
final int cellWidth = (int)(this.gameTable_width-(2*border))/3;

final float table_eX = this.gameTable_width-border;
final float table_eY = this.gameTable_height-border;

canvas.drawLine(this.gameTable_sY+border, cellHeight+border, table_eX, cellHeight+border, paint);
canvas.drawLine(this.gameTable_sY+border, (cellHeight*2)+border, table_eX, (cellHeight*2)+border, paint);

canvas.drawLine(cellWidth+border, border, cellWidth+border, table_eY, paint);
canvas.drawLine((cellWidth*2)+border, border, (cellWidth*2)+border, table_eY, paint);


paint.setPathEffect(new CornerPathEffect(20));
canvas.drawRect(border/2, border/2, this.gameTable_width-(border/2),
this.gameTable_height-(border/2),
paint);

paint.setPathEffect(null);
}


private void CheckContent(){

for(int i=0;i<9;i++){
if(this.squares[i].contains(Xs[1], Ys[1])){
this.tictactoe.move_Request(i);

this.draw = false;
return;
}
}
}


private void drawContent(Canvas canvas){


for(int i=0;i<9;i++){
int squareContent = this.tictactoe.getContent(i);
if(squareContent == TicTacToe.X_PLAYER)
canvas.drawBitmap(this.X_Player,null,this.squares[i], this.contentPaint);
else if(squareContent == TicTacToe.O_PLAYER)
canvas.drawBitmap(this.O_Player,null,this.squares[i], this.contentPaint);

}
}

@Override
public boolean onTouch(View v, MotionEvent event) {

if(event.getAction() == MotionEvent.ACTION_DOWN){
this.Xs[0] = (int)event.getX();
this.Ys[0] = (int)event.getY();
}
else if(event.getAction() == MotionEvent.ACTION_UP){
this.Xs[1] = (int)event.getX();
this.Ys[1] = (int)event.getY();

this.draw = true;
}

return true;
}
.
.
.

The Last thing I would like to handle is the ability to keep the state of the game when user flips the phone and goes to landscape mode or vice versa, so we are gonna have to save current state of the game just before application get killed and then retrieve that state later when the activity get started again which mean our activity class will be something like this:



public class TicTacToeActivity extends Activity{

private TicTacToeView view;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);

TicTacToe oldTTT = (TicTacToe)getLastNonConfigurationInstance();
if(oldTTT != null)
this.view = new TicTacToeView(this, oldTTT);
else
this.view = new TicTacToeView(this);

setContentView(this.view);
}

@Override
public Object onRetainNonConfigurationInstance(){
return this.view.getInternalState();
}

}

getInternalState() method returns the associated TicTacToe object of the TicTacToeView, as I said before TicTacToe class is just a simple class that holds the game matrix and players' scores and actually that's all we need to save and retrieve each time the configuration gets changed in this example.
I also though it would be interesting to start the game with some sort of animation so I wrote a piece of code to have the game table being drawn when you start the application, something like this I mean :








and here is the code that generates this animation:



.
.
.

public void run(){
final int length = lines.length;
for(int i=0;i<length;i++)
drawLine(i);
}

private void drawLine(int index){

final Line line = this.lines[index];

final float addingPortion_X = ((line.eX - line.sX) / DRAW_PER_LINE);
final float addingPortion_Y = ((line.eY - line.sY) / DRAW_PER_LINE);

for(int i=0;i<DRAW_PER_LINE;i++){

Canvas canvas = this.holder.lockCanvas(null);
canvas.drawBitmap(background, 0, 0, null);
for(int j=0;j<index;j++)
canvas.drawLine(this.lines[j].sX,
this.lines[j].sY,
this.lines[j].eX,
this.lines[j].eY,
this.paint);

canvas.drawLine(line.sX,
line.sY,
line.sX+(addingPortion_X*(i+1)),
line.sY+(addingPortion_Y*(i+1)),
this.paint);

this.holder.unlockCanvasAndPost(canvas);

}

.
.
.

I'm not sure if it's the best way to do this but it works just like i want it to work ;). (since just calling lockCanvas() and unlockCanvasAndPost() alone takes something around 200ms on my emulator - which is of course ridiculous but i have no idea why! - I didn't need to add any delay but on real device it will probably be needed to have some delay).