大家好,
我想为我的Android做一个聊天客户端。但我就是无法获得任何联系。
好吧,也许你可以帮我一点。
在我的主活动中.java我调用:
//connect to the server
SocketTask connection = new SocketTask(this);
connection.execute();
My SocketTask.java如下所示:
package chat.client;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import android.os.AsyncTask;
public class SocketTask extends AsyncTask<Void, Void, Void>{
private Socket socket;
private DataInputStream input;
protected PrintStream output;
private MainActivity main;
private Thread thrd;
public SocketTask(MainActivity main){
this.main = main;
}
@Override
protected Void doInBackground(Void... params) {
try {
socket = new Socket("192.168.178.23", 1338);
input = new DataInputStream(socket.getInputStream());
output = new PrintStream(socket.getOutputStream());
// submittes the name of the client
output.println("Mobile");
output.flush();
thrd = new Thread(new Runnable() {
public void run() {
while (!Thread.interrupted()) {
try {
final String data = input.readLine();
if (data != null)
main.runOnUiThread(new Runnable() {
//new Runnable(){
@Override
public void run() {
if(!data.equals("")){
//main.chatHistory.append(data+"n");
main.addText(data);
}else{
//chatHistory.append("n");
main.addText("");
}
}
});
//};
} catch (IOException e) {
//chatHistory.append("Verbindung zum Server abgebrochen!");
main.addText("Verbindung zum Server abgebrochen!");
}
}
}
});
thrd.start();
} catch (Exception e) {
//chatHistory.append("Es konnte keine Verbindung zum Server aufgebaut werden!");
main.addText("Es konnte keine Verbindung zum Server aufgebaut werden!"+e);
}
return null;
}
}
但是当我启动它时,我只会得到:
02-27 16:32:05.875:E/传感器管理器(26146(:线程启动
另外,当我尝试调用"connection.doInBackground(("而不是"connection.execute(("(我知道这根本没有任何意义(时,我得到了一个"networkonmainthreadexception" - 但我认为我已经用AsyncTask解决了这个问题。好吧,我是Android的新手,但我已经用谷歌搜索了很多,不知道我是否那么愚蠢,但现在我放弃了,所以我在这里注册了我。也许你们中的某个人可以告诉我,我做错了什么。
(不确定我是否需要发布我的主活动类。
谢谢!:)
编辑:谢谢大家的所有这些答案,知道我有点过度了,给我一些时间来尝试/理解你的所有提示,谢谢!
在 AsyncTask 的实现上有很多概念错误,甚至很难弄清楚为什么或可能出现什么问题,所以我会在这里写一个关于如何编写 AsyncTask 的食谱和感觉提示,然后你应用它们,如果你仍然收到错误,那么你再问一次:
技巧:
- 不要在 AsyncTask 中创建新线程,doInBackground(( 已经在后台线程中被调用
- 不要在 AsyncTask 上调用 runOnUiThread,onPostExecute(( 已经在 UI 线程上调用
- 如果你的活动暂停(onPause((被调用(,在你的AsyncTask上调用.pause((,否则你可能会有一些
NullPointerException
- 不要按照您的建议直接调用
doInBackground()
,execute()
调用将创建一个新线程并为您调用它(这就是 AsyncTask 的原因( - 不要保存活动对象或任何其他将上下文保存到 AsyncTask 的对象。只需将 AsyncTask 类声明放在 Activity 本身中,出于组织目的,让 doInbackground(( 调用不同类中的一个方法并进行实际处理。这样,您的onPostExecute可以调用UI来更新它,但您将数据网络共享/处理与活动分开 。
食谱:
// put this class inside your Activity and
// just call a separate class (for organisation),
// or just put the code all in there (for no organisation)
private class SocketTask extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
// Whatever you do inside here
// DO NOT create a new thread!
return APIConnection.callAPI();
}
@Override
protected void onPostExecute(String result) {
if(result!=null){
//Update your UI here
}else{
// Some error happen?
}
}
}
异常表示您需要在后台线程上运行网络操作。直接调用doInBackground((只是使所有内容在调用的同一线程中运行,显然是主线程。所以,你必须用connection.excute()
生成新的.但是,您无法从后台线程更新 UI 元素。要在主线程上执行此操作,您需要像这样为 AsyncTask 实现onProgressUpdate()
:
@Override
protected void onProgressUpdate(String... arg) {
main.addText(arg[0]);
}
现在,将doInBackground()
中的所有addText()
调用替换为 publishProgress("whatever");
。不要忘记将异步任务声明更改为 AsyncTask<Void, String, Void>
。当你完成上述所有内容时,你不需要在doInBackground()
内生成另一个线程,无论如何它都会在后台线程中执行。虽然,您当前的代码也差不多,但这将解决混乱(不再thrd = new Thread(new Runnable() {...
和main.runOnUiThread...
(,并可能解决您的问题。
与其尝试像您那样在主线程上运行某些内容,不如使用 AsynTask
,如果您需要在主线程(即 UI(上运行某些内容,您将从 doInBackground(...)
调用 publishProgess()
,这反过来调用 onProgressUpdate(...)
。不要直接拨打doInBackground
,execute()
是启动AsyncTask
的正确方法。当doInBackground()
返回时,将在主线程上自动调用onPostExecute()
。
AsyncTask
上的Android文档非常好,并且有一个很好的使用示例。
您正在尝试在doInBackground()
中使用MainActivity
,这需要在UI
线程上运行的onPostExecute()
方法中,而doInBackground()
方法不需要。
异步任务
4个步骤
执行异步任务时,任务将经历 4 个步骤:
onPreExecute((,在执行任务之前在 UI 线程上调用。 此步骤通常用于设置任务,例如通过显示 用户界面中的进度条。
doInBackground(Params...(,在后台线程上调用 在 onPreExecute(( 完成执行后立即执行。使用此步骤 执行可能需要很长时间的后台计算。这 异步任务的参数将传递到此步骤。这 计算结果必须由此步骤返回,并且将是 传回最后一步。此步骤还可以使用 publishProgress(Progress...( 以发布一个或多个进度单元。 这些值发布在 UI 线程的 在进度更新(进度...(步骤上。
onProgressUpdate(Progress...(,在调用后在 UI 线程上调用 以发布进度(进度...(。执行时间是 定义。此方法用于在 后台计算仍在执行时的用户界面。 例如,它可用于动画进度条或显示日志 文本字段。
onPostExecute(Result(,在后台之后的 UI 线程上调用 计算完成。后台计算的结果为 作为参数传递给此步骤。
您是否在清单中添加了所需的权限?
<uses-permission android:name="android.permission.INTERNET"></uses-permission>