最近在做手机APP向PCServer端发送数据的小项目,Android 程序中为方便线程间通信(主要是高版本API不允许主线程内执行耗时服务,包括网络通信等),使用Message,Handler。
起初想法:
UI线程:利用Message封装并发送,同时接收子线程传来的数据;
子线程:利用handler进行处理消息handleMessage,同时得到Server端传回数据,并发送到主线程。
1、Server端已运行;
2、Android程序含有Internet权限,输入ServerIP地址正确,端口和Server端设置端口一致
3、添加了输入为空的异常捕捉
运行程序后,总是在message和handler的handler.sendMessage(msg)报Java.lang.NullPointerException。
探索:
1、找到了之前写得message和handler成功代码
发现自己在发送信息时只有一句话
//param 0x01---int
//param string-object 这里使用的字符串
handler.obtainMessage(0x01,string).sendToTarget();
然后就修改为上述句子,运行还是出错;
2、难道是封装的信息为空?
Message msg=new Message();
msg.what=0x02;
msg.obj="hello world!";
System.out.println(msg.obj.toString());
handler.sendMessage(msg);
结果可以输出封装信息(msg.obj),还是在handler.sendMessage(msg)报NullPointerException
3、是不是msg为空?
分析上述2中代码,新建Message对象没有报错,按理说不是空指针,但我还是不确定,判断一下。
Message msg=new Message();
msg.what=0x03;
msg.obj="Hello world!";
if(msg!=null){
System.out.println("msg is not null!");
handler.sendMessage(msg);
}
输出“msg is not null!",handler.sendMessage(msg)报空指针异常,这样确定了是handler为空。
4、子线程中处理UI线程信息的handler是传递过来的,Handler的发起和处理都因该对应起来。
子线程:
public class TestThread implements Runnable{
Handler mhandler;
//Constructor
public TestThread(Handler handler){
//将UI的handler传递过来,并用于sendMessage
this.mhandler=handler;
}
@Override
public void run(){
Message msg=new Message();
msg.what=0x02;
msg.obj="hello server!";
mhandler.sendMessage(msg);
}
}
主线程:
public class TestHandler extends Activity{
……
Button bt;
Handler uihandler;
……
public void onCreate(***){
……
bt=(Button)findViewById();
bt.setOnClickListener(new mOnClickListener());
……
}
public class mOnClickListener implements OnClickListener{
……
//new thread
new Thread(new TestThread(uihandler)).start();
//handleMessage
uihandler=new Handler(){
……
};
……
}
}
我的主线程和子线程大致是这样,仔细查看代码才发现:主线程中Handler在新建Thread之前并没有初始化,而是在线程发起后new Handler对象,所以报NullPointerException,将位置对换,实现主线程与子线程的通信。
正确的主线程结构是:
public class TestHandler extends Activity{
……
Button bt;
Handler uihandler;
……
public void onCreate(***){
……
bt=(Button)findViewById();
bt.setOnClickListener(new mOnClickListener());
……
}
public class mOnClickListener implements OnClickListener{
……
//handleMessage
uihandler=new Handler(){
……
};
//new thread
new Thread(new TestThread(uihandler)).start();
……
}
}
//currentHandler是在子线程中声明的handler对象,用于接收主线程发送的消息
TestThread.currentHandler.sendMessage(msg);
public class TestThread implements Runnable{
……
Handler mhandler;//
Handler currentHandler;//接收主线程信息
……
currentHandler=new Handler(){
public void handleMessage(){
……
}
}
}