在扩展AsyncTask的类中使用DoInBackground方法来更改不是MainActivity的Activity中TextView的Text

时间:2018-04-21 11:53:01

标签: java android android-activity android-asynctask textview

我是一名大学生编程的Android应用程序,它将显示消息,Android设备通过TCP从服务器接收消息。

类ListenForMessage(扩展AsyncTask)打开TCP连接,并在DoInBackground方法中从服务器接收消息。我可以在日志中打印出来自服务器的消息,但如果我尝试编辑TextView的文本,我的应用程序崩溃了。我似乎无法从DoInBackground方法编辑TextView的文本,尤其是不能,因为该类不会扩展创建TextView的活动。

我有两个活动,我在第二个活动“StreamPageMain”的onCreate中执行“ListenForMessage”类(在此之前,我在MainActivity中执行它,但这也没有用)。我试图让方法知道,TextView属于哪个活动,正如你在我的代码中看到的那样,我在类“ListenForMessage”中创建了另一个方法来设置文本,因此不是DoInBackground方法试图改变文本,但没有一个工作。

要点: 我在代码中标出了这个位置,这是错误的。我需要做的是,以某种方式获取名为“message”的String并将该String放在TextView中,ID为“textView1”,它是“StreamPageMain”活动的一部分,而不是MainActivity。

按下按钮时,我在MainActivity中使用此方法:

 public void stream(View V) {

    EditText IPText = (EditText) findViewById(R.id.editTextBox2);  //Extracting the IP from an EditTextView
    EditText portText = (EditText) findViewById(R.id.editTextBox3); //Extracting the port from an EditTextView

    String IP = IPText.getEditableText().toString();            //correcting the format to String
    Integer port = Integer.parseInt(portText.getEditableText().toString()); //correcting the format to Integer

    Intent i = new Intent(MainActivity.this, StreamPageMain.class);
    i.putExtra("IP", IP);
    i.putExtra("port", port);
    startActivity(i);
}

启动第二个活动“StreamPageMain”。这样可行。

import android.widget.VideoView;   

public class StreamPageMain extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.stream_page);

    Log.d("StreamingApp", "OnCreate is running.");

    //In this middle part I am implementing a videostream into the second 
    activity, but that does not affect anything        

    String IP = getIntent().getStringExtra("IP");
    Integer port = getIntent().getExtras().getInt("port");
    ListenForMessage listenForMessage = new ListenForMessage(StreamPageMain.this, IP, port);
    listenForMessage.execute();
}
}

您可以在此处看到我如何将Activity StreamPageMain传递给ListenForMessage类。如果我注释掉标记的行,那么类本身,连接和一切都可以正常工作:

package comn.example.ezio.streamingapp;

import android.app.Activity;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

public class ListenForMessage extends AsyncTask<Void, Void, Void> {

public Activity executingActivity;
public String IP;
public Integer port;

public ListenForMessage(Activity activity, String IPString, Integer portNumber) {
    this.executingActivity = activity;
    IP = IPString;
    port = portNumber;    
}

@Override
protected Void doInBackground(Void... voids) {

    try (Socket socket = new Socket(IP, port)) {

        Boolean connectionCancelled = false;

        while (connectionCancelled == false) {

            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            BufferedReader br = new BufferedReader(isr);
            String message = br.readLine();
            Log.d("StreamingApp", "Server says: " + message);

            setTextOfTextView(message); //!!!! This is it. At this line it 
                                        //crashes, no matter how I put it. 
                                        //Doing it directly here or in an 
                                        //extra method like now.
        }

    } catch (
            UnknownHostException e)

    {
        e.printStackTrace();
    } catch (
            IOException e)

    {
        e.printStackTrace();
    }
    return null;
}

public void setTextOfTextView(String textOfTextView) {
    TextView textView1 = executingActivity.findViewById(R.id.textView1);
    textView1.setText("Server says: " + textOfTextView);
}
}

我毕竟是Java的新手,我的知识并没有超出我在这里发布的内容。请原谅格式错误和非最佳做法,我很乐意学习和改进!

1 个答案:

答案 0 :(得分:0)

如您所见,您无法在doInBackground中对UI进行更改,因为其中的代码在另一个线程中执行,您只能在UI线程中更改UI。 (您可以从其他线程发布对UI线程的更改)。

要更新AsyncTasks中的UI,您可以使用onProgressUpdate更新UI,因为此处的代码在UI线程上运行。您可以在AsyncTask

中覆盖此方法
protected void onProgressUpdate(String... progress) {
         setTextOfTextView(progress[0]);
     }

要将更新从doInBackground发送到onProgressUpdate,请调用方法publishProgress()

@Override
protected Void doInBackground(Void... voids) {

    try (Socket socket = new Socket(IP, port)) {

        Boolean connectionCancelled = false;

        while (connectionCancelled == false) {

            InputStreamReader isr = new InputStreamReader(socket.getInputStream());
            BufferedReader br = new BufferedReader(isr);
            String message = br.readLine();
            Log.d("StreamingApp", "Server says: " + message);

            publishProgress(message); //!!!! This is it. At this line it 
                                        //crashes, no matter how I put it. 
                                        //Doing it directly here or in an 
                                        //extra method like now.
        }

    } catch (
            UnknownHostException e)

    {
        e.printStackTrace();
    } catch (
            IOException e)

    {
        e.printStackTrace();
    }
    return null;
}

编辑:

此外,为了发布任何结果,您应该将AsyncTask签名更改为AsyncTask<Void, String, Void>