跨App调用IntentService时Parcel解组ClassNotFoundException问题求助
解决跨进程调用Service时Parcel反序列化ClassNotFoundException问题
这个错误的核心原因很明确:你在App2中定义的AddressResultReceiver类,在App1的类加载路径里根本不存在。Android的每个应用都有独立的类加载器,当App2把自定义的ResultReceiver子类通过Intent传递给App1时,App1尝试反序列化这个对象,却找不到对应的类定义,自然就抛出了ClassNotFoundException。
下面给你两种可行的解决方案,按推荐优先级排序:
方案一:共享自定义ResultReceiver类到公共Library
把AddressResultReceiver抽成独立的Android Library模块,让App1和App2都依赖这个库,保证两个应用里的类全限定名完全一致,这样双方的类加载器都能找到这个类。
步骤1:创建公共Library并定义类
新建一个Android Library模块,在其中定义AddressResultReceiver(注意包名要固定,比如com.example.common):
package com.example.common; import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; public class AddressResultReceiver extends ResultReceiver { private ReceiverCallback mCallback; public AddressResultReceiver(Handler handler) { super(handler); } // 定义回调接口,让App2的Activity能接收结果 public interface ReceiverCallback { void onReceiveResult(int resultCode, String message); } public void setReceiverCallback(ReceiverCallback callback) { mCallback = callback; } @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (mCallback != null) { String message = resultData.getString("receiver"); mCallback.onReceiveResult(resultCode, message); } } }
步骤2:修改App1的Service代码
确保App1依赖这个Library,然后修改servicev类引用公共库的AddressResultReceiver:
package com.veritran.vttokentest; import android.app.IntentService; import android.content.Intent; import android.os.Bundle; import android.widget.Toast; import com.example.common.AddressResultReceiver; public class servicev extends IntentService { protected AddressResultReceiver mReceiver; public servicev() { super("yeah"); } @Override protected void onHandleIntent(Intent workIntent) { Toast.makeText(getApplicationContext(), "onHandle starting", Toast.LENGTH_LONG).show(); mReceiver = workIntent.getParcelableExtra("receiver"); deliverResultToReceiver(1, "value of servicev"); } private void deliverResultToReceiver(int resultCode, String message) { Bundle bundle = new Bundle(); bundle.putString("receiver", message); mReceiver.send(resultCode, bundle); } }
步骤3:修改App2的MainActivity代码
同样依赖公共Library,然后调整代码接收结果:
package com.example.idscomercial.myapplication; import android.os.Bundle; import android.os.Handler; import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; import com.example.common.AddressResultReceiver; public class MainActivity extends AppCompatActivity implements AddressResultReceiver.ReceiverCallback { protected AddressResultReceiver mResultReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startIntentService(); } protected void startIntentService() { mResultReceiver = new AddressResultReceiver(new Handler()); mResultReceiver.setReceiverCallback(this); Intent intent = new Intent("com.veritran.vttokentest.servicev.START_SERVICE"); intent.setPackage("com.veritran.vttokentest"); intent.putExtra("receiver", mResultReceiver); startService(intent); } @Override public void onReceiveResult(int resultCode, String message) { Toast.makeText(this, "收到App1返回结果:" + message, Toast.LENGTH_LONG).show(); } }
方案二:改用Messenger实现跨进程通信
如果不想维护公共Library,可以直接用Android原生的Messenger来实现跨进程消息传递。Messenger基于AIDL封装,底层用Binder通信,而且是系统类,两个应用的类加载器都能识别。
步骤1:修改App1的Service代码
package com.veritran.vttokentest; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.widget.Toast; public class servicev extends Service { // 处理App2发来的消息 class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { Toast.makeText(getApplicationContext(), "收到App2的请求", Toast.LENGTH_SHORT).show(); // 获取App2的回调Messenger Messenger replyMessenger = msg.replyTo; try { // 组装结果返回 Message replyMsg = Message.obtain(null, 1); Bundle bundle = new Bundle(); bundle.putString("receiver", "value of servicev"); replyMsg.setData(bundle); replyMessenger.send(replyMsg); } catch (Exception e) { e.printStackTrace(); } } } final Messenger mMessenger = new Messenger(new IncomingHandler()); @Override public IBinder onBind(Intent intent) { Toast.makeText(getApplicationContext(), "Service已绑定", Toast.LENGTH_SHORT).show(); return mMessenger.getBinder(); } }
步骤2:修改App1的Manifest
给Service添加绑定的IntentFilter:
<service android:enabled="true" android:exported="true" android:name="com.veritran.vttokentest.servicev"> <intent-filter> <action android:name="com.veritran.vttokentest.servicev.BIND_SERVICE" /> </intent-filter> </service>
步骤3:修改App2的MainActivity代码
package com.example.idscomercial.myapplication; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import androidx.appcompat.app.AppCompatActivity; import android.widget.Toast; public class MainActivity extends AppCompatActivity { Messenger mService = null; boolean mBound = false; // 接收App1返回结果的Handler class ReplyHandler extends Handler { @Override public void handleMessage(Message msg) { if (msg.what == 1) { String result = msg.getData().getString("receiver"); Toast.makeText(MainActivity.this, "收到结果:" + result, Toast.LENGTH_LONG).show(); } } } final Messenger mMessenger = new Messenger(new ReplyHandler()); private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { mService = new Messenger(service); mBound = true; // 绑定成功后发送请求 sendRequestToService(); } @Override public void onServiceDisconnected(ComponentName className) { mService = null; mBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定App1的Service Intent intent = new Intent("com.veritran.vttokentest.servicev.BIND_SERVICE"); intent.setPackage("com.veritran.vttokentest"); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } private void sendRequestToService() { if (!mBound) return; Message msg = Message.obtain(null, 0); // 自定义消息码,标识请求类型 msg.replyTo = mMessenger; // 设置回调Messenger try { mService.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); if (mBound) { unbindService(mConnection); mBound = false; } } }
内容的提问来源于stack exchange,提问作者arnoldssss
相关产品推荐
相关产品推荐

