[Android]从Helloworld开始,继续前进

从Helloworld开始,继续前进

 

 [第二届 Google 暑期大学生博客分享大赛 - 2011 Android 成长篇]

 

  配置好了开发环境,写出了第一个Helloworld程序,很高兴。但是高兴之余又发现对于接下来的学习有点不知所措。书上介绍了很多控件怎么使用,Layout怎么使用,看了一会就觉得好烦啊。

  我觉得学习在一个平台开发程序,还是应该先自己摸索着写一点东西出来,有了一定的兴趣和成就感后,继续学习深入的开发,效果可能会更好。

  写一个小程序先。

  通过Intent实现Activity间的切换:

  第一个Activity   第二个Activity 

  通过Button和返回键,在两个Activity之前切换,这样一个程序应该很好写,网上和书上都有教程。注意点就是要新建一个布局文件,并且要把新的Activity在清单文件中注册一下。

  

  试着把这样一个简单的程序改成一个小游戏。

 

  Intent的另外一个功能,就是在两个Activity之前传递数据。这个功能非常有用,假设第一个Activity是刚进入游戏时的界面,有开始游戏、选择难度、游戏帮助、退出游戏等选项,第二个Activity则是真正的游戏界面,那么当从第一个Activity进入到第二个Activity时,肯定是要传递一些数据的,比方说难度、玩家昵称。现在把这样一个传输的功能简单实现一下。

  1.把第一个Activity的UI改成这样,即添加一个EditText控件,用ADT编辑布局文件即可。

  

  2.修改代码,第一个Activity:

public class MoveActivity extends Activity {
private Button jump;
private EditText et;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
jump
=(Button)findViewById(R.id.jump);//得到控件对象的引用
et=(EditText)findViewById(R.id.nickname);
jump.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent i=new Intent();
i.setClass(MoveActivity.
this, Game.class);//设置Intent
String nickName=et.getText().toString();//得到EditText中的内容
i.putExtra("NickName", nickName);//加入附加信息 nickname
i.putExtra("Grade", 10);//Grade
startActivity(i);//启动第二个Activity
}
});
}
}

  记得import进相应的包,Ctrl+Shift+O即可

  3.在第二个Activity中再加入两个TextView,然后修改代码:

public class Game extends Activity {
private TextView tv1,tv2,tv3;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
tv1
=(TextView)findViewById(R.id.tv1);//得到控件对象的引用
tv2=(TextView)findViewById(R.id.tv2);//id已修改
tv3=(TextView)findViewById(R.id.tv3);
//得到Intent对象
Intent i=getIntent();
//从Intent对象中得到附加信息并在TextView中显示出来
String nickName=i.getStringExtra("NickName");
int iGrade=i.getIntExtra("Grade", 0);//默认是0
tv2.setText(nickName);//设置TextView
tv3.setText(""+iGrade);
}
}

  同样注意import。

  运行看结果后就可以看到数据传输是成功的。

  4.在第二个Activity中添加16个Button,4x4。因为xml里面默认布局是vertical的LinearLayout,所以只要先在UI中加一个LinearLayout(Horizontal),然后再加四个Button,如此重复四次即可。

  

  如果现在我说这已经是一个游戏了,你肯定不信。

  还记得小时候玩过的那种移拼图的玩具吗?

  

  应该有想法了吧。

  5.修改第二个Activity中的代码,让它变成一个Android上的移拼图小游戏。其实这已经和Android无关了,看的是Java和算法的基础。文章最后给出代码。

     

     

  说到写游戏,我想到的是游戏中的主循环。于是我试着在Android中模拟了一下,发现了一个问题。

  原先的想法是:在一个TextView中显示一个数字,然后在Activity中启动一个线程,该线程每隔一定的时间让TextView中显示的数字加1。

  看上去这十分简单,但是写了之后我才发现,单纯的这样做是不可行的,因为一个线程不能更改非该线程创建的控件的内容。网上看到的解决办法是使用Handler。具体请见这里。非常感谢原文作者的分享。

  使用这个方法,我让第二个Activity中的tv3里面的内容每隔一定时间加1。

  最终效果图:

    

  

  这离一个正式的游戏当然还距离很远,但是,如果看过这篇文章后,一些原本不善于思考的人能变得善于思考,例如,你会不会开始思考Menu和返回键在这个程序中的作用,会不会思考NumberAdder线程到底应该在OnCreate、OnStart、OnRestart等的哪个生命周期函数中被创建,会不会试着加一个Service进去,会不会试着让Button间的间距减小然后把数字替换成图片,会不会增加代码以判断游戏是否结束,等等,只要能够增加一点想法,那看过这篇文章就算值得了吧。

   

  不足之处,请不吝赐教,谢谢!

  

  最后是第二个Activity的代码,供参考,项目源代码下载

package Yuleo.Android;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Game extends Activity {
private TextView tv1,tv2,tv3;//三个TextView的引用
private Button[][] allButtons;//所有Button对象的引用的二维数组
private int[][] allValues;//Button对象对应的数值,另外一种办法是用Button的继承类

//Handler
static final int UPDATE_TV2=1;//消息的定义
Handler h=new Handler()
{
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch(msg.what)
{
case UPDATE_TV2://处理tv3中数字的增加
{
String sNum
=(String) tv3.getText();//得到String并转为int
Integer i=new Integer(sNum);
int iNum=i.intValue();
iNum
++;
tv3.setText(
""+iNum);//更新
break;
}
}
}

};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
tv1
=(TextView)findViewById(R.id.tv1);//得到控件对象的引用
tv2=(TextView)findViewById(R.id.tv2);//id已修改
tv3=(TextView)findViewById(R.id.tv3);
Intent i
=getIntent();
String nickName
=i.getStringExtra("NickName");
int iGrade=i.getIntExtra("Grade", 0);//默认是0
tv2.setText(nickName);//设置TextView
tv3.setText(""+iGrade);

allButtons
=new Button[5][5];//Button控件
allButtons[1][1]=(Button)findViewById(R.id.button11);
allButtons[
1][2]=(Button)findViewById(R.id.button12);
allButtons[
1][3]=(Button)findViewById(R.id.button13);
allButtons[
1][4]=(Button)findViewById(R.id.button14);
allButtons[
2][1]=(Button)findViewById(R.id.button21);
allButtons[
2][2]=(Button)findViewById(R.id.button22);
allButtons[
2][3]=(Button)findViewById(R.id.button23);
allButtons[
2][4]=(Button)findViewById(R.id.button24);
allButtons[
3][1]=(Button)findViewById(R.id.button31);
allButtons[
3][2]=(Button)findViewById(R.id.button32);
allButtons[
3][3]=(Button)findViewById(R.id.button33);
allButtons[
3][4]=(Button)findViewById(R.id.button34);
allButtons[
4][1]=(Button)findViewById(R.id.button41);
allButtons[
4][2]=(Button)findViewById(R.id.button42);
allButtons[
4][3]=(Button)findViewById(R.id.button43);
allButtons[
4][4]=(Button)findViewById(R.id.button44);
//这个真没办法偷懒


allValues
=new int[5][5];//数组对象

for(int r=1;r<=4;r++)//row column
{
for(int c=1;c<=4;c++)
{
allValues[r][c]
=(r-1)*4+c;
if(allValues[r][c]<10)
{
allButtons[r][c].setText(
" "+allValues[r][c]+" ");
//加空格固定Button的宽度,也可以通过布局文件来固定
}
else
{
allButtons[r][c].setText(
" "+allValues[r][c]+" ");
}
}
}

//修改右下角那个Button
allValues[4][4]=111;
allButtons[
4][4].setText(" ");

//设置监听器
for(int r=1;r<=4;r++)
{
for(int c=1;c<=4;c++)
{
GameListener gl
=new GameListener(r,c);
allButtons[r][c].setOnClickListener(gl);

}
}
}


//Button监听器类,内部类可以方便地访问外部类中的成员变量
class GameListener implements OnClickListener
{
private int iRow,iColumn;
GameListener(
int r, int c)
{
iRow
=r;
iColumn
=c;
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub

if(iRow>1)//上面有按钮的话
{
if(allValues[iRow-1][iColumn]==111)//如果上面那个按钮为空
{
//交换数据
int iTemp=allValues[iRow][iColumn];
allValues[iRow][iColumn]
=111;
allValues[iRow
-1][iColumn]=iTemp;

//交换显示的内容
String sTemp=(String) (allButtons[iRow][iColumn]).getText();
allButtons[iRow][iColumn].setText(allButtons[iRow
-1][iColumn].getText());
allButtons[iRow
-1][iColumn].setText(sTemp);
return ;
}
}

if(iRow<4)//下面有按钮的话
{
if(allValues[iRow+1][iColumn]==111)
{
int iTemp=allValues[iRow][iColumn];
allValues[iRow][iColumn]
=111;
allValues[iRow
+1][iColumn]=iTemp;

String sTemp
=(String) (allButtons[iRow][iColumn]).getText();
allButtons[iRow][iColumn].setText(allButtons[iRow
+1][iColumn].getText());
allButtons[iRow
+1][iColumn].setText(sTemp);
return ;
}
}

if(iColumn>1)//左边有按钮的话
{
if(allValues[iRow][iColumn-1]==111)
{
int iTemp=allValues[iRow][iColumn];
allValues[iRow][iColumn]
=111;
allValues[iRow][iColumn
-1]=iTemp;

String sTemp
=(String) (allButtons[iRow][iColumn]).getText();
allButtons[iRow][iColumn].setText(allButtons[iRow][iColumn
-1].getText());
allButtons[iRow][iColumn
-1].setText(sTemp);
return ;
}
}

if(iColumn<4)//右边有按钮的话
{
if(allValues[iRow][iColumn+1]==111)
{
int iTemp=allValues[iRow][iColumn];
allValues[iRow][iColumn]
=111;
allValues[iRow][iColumn
+1]=iTemp;

String sTemp
=(String) (allButtons[iRow][iColumn]).getText();
allButtons[iRow][iColumn].setText(allButtons[iRow][iColumn
+1].getText());
allButtons[iRow][iColumn
+1].setText(sTemp);
return ;
}
}
}
}

//线程类,用于让tv3中的数字增加
class NumberAdder implements Runnable
{
@Override
public void run() {
// TODO Auto-generated method stub
for(int j=1;j<20;j++)
{
try
{
Thread.sleep(
1000);
Message msg
= new Message();
msg.what
= UPDATE_TV2;//给Handler发消息,让Handler去处理
h.sendMessage(msg);
}
catch (Exception e)
{

}
}
}
}

@Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
//建立线程
NumberAdder na=new NumberAdder();
new Thread(na).start();
}
}


  

  

posted on 2011-08-13 20:11  Yuleo  阅读(923)  评论(0)    收藏  举报