我是Eclipse for Android平台的新java程序员。 我正在开发一个Android应用程序,它将通过wifi接口接收多播数据,并在TextView中显示相同的内容。数据将每1秒更新一次。
我的代码如下。但我在更新GUI时面临问题。在此代码中,网络接收和gui在相同的线程中完成,即主线程,这就是我的应用程序挂起的原因。
我曾尝试使用AsynchTask,但无法成功,因为我不知道如何使用它。
package com.example.cdttiming;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.Menu;
import android.widget.EditText;
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText Seconds;
Seconds =(EditText)findViewById(R.id.Seconds);
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wm.createMulticastLock("mydebuginfo");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
InetAddress ia = null;
byte[] buffer = new byte[65535];
MulticastSocket ms = null;
int port = 4321;
try
{
ia = InetAddress.getByName("226.1.1.1");
DatagramPacket dp = new DatagramPacket(buffer, buffer.length,ia,port);
ms = new MulticastSocket(port);
ms.setReuseAddress(true);
ms.joinGroup(ia);
while (true)
{
ms.receive(dp);
String s = new String(dp.getData(),0,dp.getLength());
Seconds.setText(s);
}
}
catch (UnknownHostException e)
{
Seconds.setText(e.getMessage());
}
catch (IOException e)
{
Seconds.setText(e.getMessage());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
任何人都可以告诉我如何使用上面的代码,以便我可以每秒接收数据并在TextView中显示它吗?
提前感谢你们
答案 0 :(得分:5)
AsyncTask
并不适用于您的用例。如果后台任务需要连续运行,那么最好只需启动一个新线程。在线程中使用处理程序将值传递给UI。在处理程序的回调方法中,您可以更新gui。
有关处理程序的更多信息:
http://mobileorchard.com/android-app-developmentthreading-part-1-handlers/
http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html
http://developer.android.com/reference/android/os/Handler.html
或谷歌提供良好的例子来实现这一目标。
编辑:
好的,你需要做的是启动一个新线程,在run方法中放入从套接字读取的部分。 您可以像在内部类中一样创建线程,例如:
class SocketThread extends Thread {
private final Handler mHandler;
private final WifiManager mWifiManager;
SocketThread(Handler handler, WifiManager wifiManager) {
mHandler = handler;
}
@override public void run() {
// socket code goes here
// whenever you receive a part that should update the ui,
// do something like:
final String s = new String(dp.getData(),0,dp.getLength());
mHandler.post(new Runnable() {
@override
public void run() {
update(s);
}
});
}
}
然后在你的onCreate()
中创建一个处理程序和该线程的一个实例并启动它。
...
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText Seconds;
Seconds =(EditText)findViewById(R.id.Seconds);
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
Handler handler = new Handler();
SocketThread thread = new SocketThread(handler, wm);
thread.start();
...
还在您的活动中定义方法更新。在这里,您将收到要设置的文本。此方法如下所示:
public void update(String s) {
Seconds.setText(s);
}
我建议你将seconds变量(edittext
)保存为全局类变量。这样,您可以从更新方法写入它,而无需先findById
。
我编辑了你的代码,它可能与wifi代码有关。我不熟悉框架的这一部分。但我可以想象它与WifiManager
有关并且与它有关。如果这不起作用,设置一个断点并逐步执行它,你会看到它停止做任何事情。
package com.example.timing;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
EditText Seconds;
String s;
Button button;
byte[] buffer = new byte[65535];
InetAddress ia = null;
int port = 4321;
DatagramPacket dp = new DatagramPacket(buffer, buffer.length,ia,port);
MulticastSocket ms = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Seconds = (EditText) findViewById(R.id.et_time);
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
Handler handler = new Handler();
SocketThread thread = new SocketThread(handler, wm);
thread.start();
}
class SocketThread extends Thread {
private final Handler mHandler;
SocketThread(Handler handler, WifiManager wifiManager) {
mHandler = handler;
}
@Override
public void run() {
// socket code goes here
try {
wm.setWifiEnabled(true);
WifiManager.MulticastLock multicastLock = wm.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
ia = InetAddress.getByName("226.1.1.1");
ms.setReuseAddress(true);
ms.joinGroup(ia);
while(true) {
ms.receive(dp);
s = new String(dp.getData(),0,dp.getLength());
update(s);
}
} catch (UnknownHostException e) {
update(e.getMessage());
} catch (IOException e) {
update(e.getMessage());
}
}
}
public void update(String s)
{
Seconds.setText(s);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
答案 1 :(得分:1)
您不应该使用AsyncTask进行更持久的活动 - 请使用简单的Thread和Handler。在线程中,您执行WI-FI的操作(基本上是您的while(true)循环),并且每当您想要更新UI时,都会将消息传递给Handler并在UI线程中处理消息。
有关详细信息,请阅读Android开发者博客中着名的Painless Threading帖子。
答案 2 :(得分:1)
您只需在应用可见时收集数据吗?您应对这一挑战的方式非常依赖于数据和通信的需求和生命周期。
AsyncTask通常用于在单独的线程上执行一个off作业,然后在完成时通知主线程。
可能会查看服务,因为它适用于长期工作。
答案 3 :(得分:0)
您也可以学习Firebase for android.