避免使用onActivityResult,以提高代码可读性,解决其业务逻辑代码日益壮大的问题.
需要和 BaseFragmentAvoidOnResult 保持一致
使用onSaveInstanceState 和 onRestoreInstanceState 来恢复回调函数来实现此功能.
- 实现的方式有参考性(有别于网上已知的方案)
- 实现了"非匿名回调"里 调用 时,能解决上层 Activity 被 Destroy 后,返回时正常触发回调.(参考"局限性"一节的错误示范代码)
- 假如不考虑 "上层 Activity 被 Destroy 后能正常回调错误示范场景下"的情况,那么功能应该和网上已知方案是一致的.
- 支持大部分"简单情况下"的匿名函数里调用startActivityForResult,如常见控件的事件里等.
@Override
protected void onRestoreInstanceState(final Bundle savedInstanceState)
{
super.onRestoreInstanceState(savedInstanceState);
try
{
mActivityResultListenerClassArray = savedInstanceState.getBundle("mActivityResultListenerClassArray");
if (mActivityResultListenerClassArray != null)
{
if (mActivityResultListenerArray == null)
mActivityResultListenerArray = new SparseArray<>();
for (String requestCode : mActivityResultListenerClassArray.keySet())
{
try
{
final String className = mActivityResultListenerClassArray.getString(requestCode);
final Constructor<?> constructor = Class.forName(className).getDeclaredConstructors()[0];
constructor.setAccessible(true);
final OnActivityResultListener c = (OnActivityResultListener) constructor.newInstance(this);
mActivityResultListenerArray.put(Integer.parseInt(requestCode), c);
}
catch (Throwable e)
{
e.printStackTrace();
}
}
}
}
catch (Throwable e)
{
LogEx.e("BaseActivityAvoidOnResult", mActivityResultListenerClassArray, mActivityResultListenerArray, e);
}
}
按照 @AnotherJack 在 AvoidOnResult 的 issues 里提出来的建议,写了测试代码实际验证后发现的确存在问题.(新版本180912.03.01.004
部分解决了此问题)
创建listener的代码是在点击事件中,在OnClickListener中,是不是这个构造器的参数类型就不是外部Activity而是OnClickListener了
匿名类里带变量的情况.简单的通过反射实例化的话可能会导致数据状态不一致.所以新版本180912.03.01.004
也不支持此类情况.
this.btnLogin.setOnClickListener(new OnClickListener()
{
int testCode = 0;
@Override
public void onClick(final View v)
{
startActivityForResult(new Intent(getApplicationContext(), ServerSettingActivity.class), new OnActivityResultListener()
{
@Override
public void onActivityResult(final int resultCode, final Intent data)
{
testCode++;
ToastEx.makeTextAndShowLong("testCode=" + testCode + " resultCode=" + resultCode);
}
});
}
});
新版本180912.03.01.004
已经可以支持此类情况.
this.btnLogin.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
startActivityForResult(new Intent(getApplicationContext(), ServerSettingActivity.class), new OnActivityResultListener()
{
@Override
public void onActivityResult(final int resultCode, final Intent data)
{
ToastEx.makeTextAndShowLong(" resultCode=" + resultCode);
}
});
}
});
System.err: java.lang.IllegalArgumentException: argument 1 should have type LoginActivity$5, got LoginActivity
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at cn.asiontang.BaseActivityAvoidOnResult.onRestoreInstanceState(BaseActivityAvoidOnResult.java:96)
在
new OnActivityResultListener
里调用了new OnClickListener
的变量,导致实际生成的OnActivityResultListener
匿名类名字为LoginActivity$5$1
,因此其默认的构造函数具有唯一的一个参数类型必须为LoginActivity$5
.
必须保证
OnActivityResultListener的匿名回调类
的new
生成 是在 其子类直属 范围内 即可. 不能在匿名函数里再new OnActivityResultListener
出来调用.
Update:
新版本
180912.03.01.004
解决了此问题的部分情况.
新版本180912.03.01.004
支持大部分"简单情况下"的匿名函数里调用startActivityForResult,如常见控件的事件里等.
this.btnLogin.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
startActivityForResult(new Intent(getApplicationContext(), ServerSettingActivity.class), new OnActivityResultListener()
{
@Override
public void onActivityResult(final int resultCode, final Intent data)
{
ToastEx.makeTextAndShowLong(" resultCode=" + resultCode);
}
});
}
});
public class LoginActivity extends BaseActivity implements OnClickListener
{
@Override
public void onCreate(final android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setContentView(R.layout.login);
//other code
this.btnLogin.setOnClickListener(this);
}
@Override
public void onClick(final View v)
{
switch (v.getId())
{
case R.id.btnLogin:
startActivityForResult(new Intent(getApplicationContext(), ServerSettingActivity.class), new OnActivityResultListener()
{
@Override
public void onActivityResult(final int resultCode, final Intent data)
{
ToastEx.makeTextAndShowLong(" resultCode=" + resultCode);
}
});
break;
}
}
}
public class LoginActivity extends BaseActivity
{
@Override
public void onCreate(final android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setContentView(R.layout.login);
//other code
this.btnLogin.setOnClickListener(setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
onLoginClick();
}
});
}
public void onLoginClick()
{
startActivityForResult(new Intent(getApplicationContext(), ServerSettingActivity.class), new OnActivityResultListener()
{
@Override
public void onActivityResult(final int resultCode, final Intent data)
{
ToastEx.makeTextAndShowLong(" resultCode=" + resultCode);
}
});
}
}
public class LoginActivity extends BaseActivity implements OnClickListener
{
@Override
public void onCreate(final android.os.Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setContentView(R.layout.login);
//other code
final OnActivityResultListener mListener = new OnActivityResultListener()
{
@Override
public void onActivityResult(final int resultCode, final Intent data)
{
ToastEx.makeTextAndShowLong(" resultCode=" + resultCode);
}
};
this.btnLogin.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
startActivityForResult(new Intent(getApplicationContext(), ServerSettingActivity.class), mListener);
}
});
}
}
当A被销毁后,从B返回时,A会被重建,此时回调函数无法自动创建导致无效!
遇到activity进入后台被系统回收的情况,就没办法接收到回调了,这点可以开启开发者选项->不保留活动 来验证
- java - onDestroy() while "waiting" for onActivityResult() - Stack Overflow
- Activity被回收后Callback不会回调 · Issue #4 · AnotherJack/AvoidOnResult
- EasyAndroid基础集成组件库之:EasyActivityResult 拒绝臃肿的onActivityResult代码 - 掘金
@author AsionTang
@version 180912.02.01.003