#面向自己写博客#
#面向新人互相鼓劲#
事情的起因是这样的:
人物:我,一个学习JAVA总共46天的小菜鸟。
事件:在编程做一款android五子棋游戏。
需求:需要在人或机某一方获得胜利后,动态加载一个带按钮和文本的Fragment,并调整画布大小。
背景:五子棋游戏中我在逻辑类Game中定义了一个静态的static int winner;并定义了一个方法,int winner();方便随时通过游戏的盘面,返回胜利者,当没有人胜利的时候返回0,当玩家胜利返回1,当AI胜利返回2;本文的问题在于,如果监听这个静态变量winner,使得一旦其变成了1或者2,马上跳出弹窗,并且停止游戏。
那么我究竟应该怎么做才能做到这一点呢?
首先:我想到的是类似OnClickListener的监听功能,查了一圈儿,问了一圈儿人,得到的答复是,木有类似的监听器,需要自己创建。
这条路走不通,我却意外找到了另外两种实现方法,一种非常简单,一种稍微复杂一点。
那么,我们就先来说这个简单的:
使用子线程,不停地来检测我们的静态变量winner
既然是要使用子线程,那么我们必然要先创造一个线程,要通过线程改变主UI,那必然要使用到andriod的异步机制,因为我对async Task 用法不熟悉,所以并没有选择使用这个封装好的方法,因为内容比较简单,所以直接用Handler和Message就能解决。
好,先new一个Handler。(特别提醒Android Studio的朋友,该软件过于智能,会给你自动导Handler的包,但并不是os.Handler的,所以需要注意一下,别问我为什么知道,你看我脸上的泪痕。。)
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
String str1=getResources().getString(R.string.winner_p1);
String str2=getResources().getString(R.string.winner_p2);
super.handleMessage(msg);
if (msg.what==1){
switch (msg.arg1){
case 1:change(str1);break;
case 2:change(str2);break;
}
}
}
};
好了,代码放上来了,在实例Handler的过程中,我们重写了handleMessage方法,这个方法意味着,我们可以接收一个子线程传来的信息,并且我们可以通过它来影响主线程,那就好办了,可以看到,在该方法中,我们先定义了两个String字符串,这是用于表达的,看官们可以无视。
从这里开始才是关键:
if (msg.what==1){
switch (msg.arg1){
case 1:change(str1);break;
case 2:change(str2);break;
}
}
首先,我们会对传来的message的TAG进行判定,也就是它的what变量,如果是1,说明是我希望的子线程发过来的,然后对其中的一个整形变量进行判定,我在后面会如果是1,说明胜利者是玩家,如果是2,说明胜利者是电脑。这里的change()方法是我项目中的一个方法,看官们无视就好。
有了Handler,接下来就要看我们的子线程是什么样子的了。
用最基础的new Thread(new Runnable)来实现就行。如下:
new Thread(new Runnable() {
@Override
public synchronized void run() {
Message message=Message.obtain();
message.what=1;
while (Game.winner==0){
try {
wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
notify();
switch (Game.winner){
case 1:message.arg1=1;break;
case 2:message.arg1=2;break;
}
handler.sendMessage(message);
}
}).start();
在主线程中,直接new一个匿名类,并在Runnable中重写方法run(),这个方法就是子线程要不停做的事。
通过Message.obtain()获取message方法和new差不多,我就不解释了,官方更推荐我们用这个方法。
它的成员变量what和Handler里需要的保持一致,暗号对上了。
接下来就是关键代码了,首先你一定主意到我把synchronized加到了run的前面,这是为了将其锁定,并使用wait()和notify()方法,如果你不想这么做,用sleep也是可以的。然后让线程在此处无限循环:
while (Game.winner==0){
try {
wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
每一秒,对我的静态变量判定一次,直到静态变量不等于0,则去执行后面的代码。
并且handler发送代码。
怎么样,不难吧。
这方法当然简单,可是它的响应速度受限于wait(1000),也就是说,相应速度最高可能达到1秒。
目前我了解到观察者模式可以很好的解决这个问题,我也正在学,那么下篇博客我们就来了解一下:
观察者模式的用法吧~大家一起学习一起进步,干吧爹!