可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am implementing a REST client in Android.
I have seen an example of using a Service
to perform the connection to the server and the ResultReceiver
to be notified of the operation completion. I am calling the service from a fragment and, if I try to rotate the screen while the service is running, the getActivity() method in ResultReceiver
returns null because probably that fragment is not in layout anymore.
The callback method in the fragment:
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
Response response = (Response) resultData
.getSerializable(RestService.RESULT);
if (resultCode == RestService.SUCCESS
&& response != null) {
if (getActivity() != null) {
recommendationResponse = response;
getLoaderManager().restartLoader(0, new Bundle(),
Fragment.this);
}
}
}
The getActivity()
returns null.
Is this normal? What approach could I use to allow notification even on screen rotation? Local Broadcast?
回答1:
No,
android:configChanges="orientation"
is not a solution.
To use ResultReceiver I:
save it on orientation changes:
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putParcelable(Consts.RECEIVER, mReceiver);
super.onSaveInstanceState(outState);
}
reset the receiver:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (savedInstanceState != null) {
mReceiver = savedInstanceState.getParcelable(Consts.RECEIVER);
}
else {
mReceiver = new MyResultReceiver(new Handler());
}
mReceiver.setReceiver(this);
}
Here is my ResultReceiver class:
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
public class MyResultReceiver extends ResultReceiver {
private Receiver mReceiver;
public MyResultReceiver(Handler handler) {
super(handler);
}
public void setReceiver(Receiver receiver) {
mReceiver = receiver;
}
public interface Receiver {
public void onReceiveResult(int command, Bundle resultData);
}
@Override
protected void onReceiveResult(int command, Bundle resultData) {
if (mReceiver != null) {
mReceiver.onReceiveResult(command, resultData);
}
}
}
回答2:
I am using a BroadcastReceiver
registered using LocalBroadcastManager
and it is working properly. It wasn't so simple. Does a better solution exist?
回答3:
I think I stumbled upon the same issue and resolved it by verifying for NULL in the onReceivedResult method of my ResultReceiver. The code posted here works on a worker fragment (fragment without UI and setRetainInstance(true) in onCreate)
protected void onReceiveResult(int resultCode, Bundle resultData) {
//Verify activity
if(getActivity() != null){
//Handle result
}else{
notificationPending = true;
}
}
The notificationPending flags helps the fragment hold the pending notification if the activity was not found (Activity is not available on fragment Detach).
When the fragment reattaches to the activity i perform this logic
public void onAttach(Activity activity){
super.onAttach(activity);
if(notificationPending){
//Handle notification
notificationPending = false;
}
}
Hope it helps. You can ask for further details if you like. Cheers
回答4:
Yes, this normal since the ResultReceiver might be "headless".
I tried saving the ResultReceiver
at onSaveInstanceState()
, but it didn't work, since updates, that happen while the receiving Fragment
is destroyed, get lost, and the references to callbacks too.
An explanation and a possible solution can be found here: https://stanmots.blogspot.com/2016/10/androids-bad-company-intentservice.html
Another good read concerning this problem:
https://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
My full solution how to use a ResultReceiver
can be found here:
https://stackoverflow.com/a/54334864/6747171
回答5:
The getActivity() returns null. Is this normal?
Android Activities are recreated after device rotation.
After activity is recreated it does not holds old context.that's why your getting getActivity()
as null
What approach could I use to allow notification even on screen
rotation? Local Broadcast?
If you dont want activity to recreated on screen rotation.mention following in manifest
<activity
android:name=".MyActivity"
android:configChanges="orientation" <<<<<<<<<
android:label="@string/app_name"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
And last You will have to override following in Activity.
@Override
public void onConfigurationChanged(Configuration newConfig)
{
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
}