代码之家  ›  专栏  ›  技术社区  ›  Paolo

AsyncTask导致NotSerializableException

  •  1
  • Paolo  · 技术社区  · 7 年前

    我想在活动之间导航并传递对象。 对象是客户端(电话)和服务器(计算机)之间的Tcp连接。当用户按下按钮时,将启动新活动,并将用户重定向到新页面。

    我希望能够从不同的活动向服务器发送某些命令。

    但是,我在活动之间传递对象时遇到问题。 每当我尝试转到下一个活动时,都会出现以下错误:

    Java语言lang.RuntimeException:Parcelable在写入可序列化对象时遇到IOException 原因:java。io。NotSerializableException: com。实例使用者myapp。主页$连接任务$1

    Asynctask抛出了错误,我相信它不是 this question 。 所有类都已实现可序列化。

    在我的onCreate中

        connecttask = new ConnectTask();
        connecttask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    
        final Intent i = new Intent(getBaseContext(),Menu.class);
        final ArrayList<TcpClient> testing = new ArrayList<TcpClient>();
    

    在我的setOnClickListener中

    public void onClick(View view) {
                if(Username.getText().toString().equals("admin") &&
                        Password.getText().toString().equals("admin")) {
                    Toast.makeText(getApplicationContext(),
                            "Redirecting...",Toast.LENGTH_SHORT).show();
    
                    testing.add(mTcpClient);
                    i.putParcelableArrayListExtra("extra",testing);
                    startActivity(i);
    }
    

    异步任务:

    public class ConnectTask extends AsyncTask<String, String, TcpClient> implements Serializable {
    
        @Override
        protected TcpClient doInBackground(String... message) {
    
            System.out.println("Executed call");
            mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
                @Override
                public void messageReceived(String message) {
                    try {
                        publishProgress(message);
                        if (message != null) {
                            System.out.println("Returned message from socket::::: >>>>>>" + message);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, ipAddressOfServerDevice);
            if (mTcpClient != null) {
                mTcpClient.sendMessage("Initial message when connected with Socket Server");
            }
            delay();
            return mTcpClient;
        }
    
        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            arrayList.add(values[0]);
            mAdapter.notifyDataSetChanged();
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Robin Davies    7 年前

    想想“可包裹”是什么意思。这意味着您可以将其序列化为二进制流,并可能在进程之间传递它。如何使用任务或线程实现这一点?没有发生。

    您需要稍微阅读一下活动生命周期,以及管理比活动寿命长的对象的各种策略。

    您需要考虑的场景。(1) 由于方向改变(活动短期终止)等原因,您的活动被拆除并重新启动。(2) 您的活动进入后台,因此android会删除您的应用程序,并在稍后重新启动(活动的长期终止)。(3) 您的应用程序进入后台,Android终止整个过程,目的是稍后将其从序列化状态恢复。场景(3)是使用包裹序列化活动状态的原因:包裹被写入某个地方的临时存储,进程终止,很长一段时间后重新启动,包裹从临时存储读取,新活动开始时,这些包裹作为适当的参数提供。很明显,你的线程将无法生存。

    正确的做法是将整个TCP连接打包到一个服务中,如果Android希望在进程进入后台时终止进程,并在以后重新启动,那么这个服务将更好地生存。服务的优点是,即使你的应用程序在后台,它也可以在后台状态下生存30分钟;如果你为你的服务发布了通知,那么它将永远存在。服务管理有点痛苦;但很多痛苦都和你们必须做的事情有关。最大的痛苦是,您的活动必须完全删除后台任务中的所有回调,以便可以对应用程序进行垃圾收集。该服务提供了一个这样做的框架,以及一些潜在有用的生命周期管理。

    您还可以使用片段(没有UI)来解决场景(1)。在场景(2)中有一段时间。您可以认为,对于简单的连接,片段任务是合适的。但我的猜测是,一旦你连接起来,你在保持连接方面也会遇到同样的问题。因此,服务可能是正确的选择。或者是一个片段,它完全负责将异步TCP操作引导到后台线程上,然后再引导回来。

    如果您的TCP连接完全是一次性的,并且您不介意丢失它,那么您也可以使用静态变量。但是,您确实需要非常小心地管理生命周期,并且非常小心地悬挂对已终止活动的引用。

    有点痛。但是,如果您完成了所有这些工作,并且如果您选择自定义解决方案,那么实现服务的大部分艰苦工作都必须以其他方式完成。