Android 触发 OnTextMessage 时,getview() 上的片段返回 null
Android fragment reutn null on getview() when OnTextMessage is triggered
我想在收到消息时更新片段中的文本。
主要Activity我用wsuri做连接。我收到回调 onTextMessage 的每条消息都会被触发。我使用的图书馆是 autoBahn。
public class MainActivity extends AppCompatActivity{
private static WebSocketConnection mConnection = new WebSocketConnection();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intent_root_activity);
if(savedInstanceState == null){
frag_Home = new HomeFragment();
fragmentManager.beginTransaction().add(R.id.fragmentContent, frag_Home, getString(R.string.TAG_HOME)).commit();
}else{
if(fragmentManager.findFragmentByTag(getString(R.string.TAG_HOME)) == null){
frag_Home = new HomeFragment();
fragmentManager.beginTransaction().add(R.id.fragmentContent, frag_Home, getString(R.string.TAG_HOME)).commit();
}
}
}
@Override
protected void onResume() {
super.onResume();
// Start Connection
Connect(ipAdress);
Log.i("ROOT ACTIVITY", "onResume");
}
// Function callback events
private void Connect(String ipAddress){
final String wsuri = "ws://" + ipAddress + ":" + port;
try {
// Handle Websocket Event
mConnection.connect(wsuri, new WebSocketHandler() {
@Override
public void onOpen() {
Log.d("WIFI", "onOpen: Conneced to "+ wsuri);
}
@Override
public void onTextMessage(String payload) {
HomeFragment home = (HomeFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.TAG_HOME));
((TextView)home.getView().findViewById(R.id.txtMsg)).setText(payload);
}
Override
public void onClose(int code, String reason) {
}
}
}
}
}
所有 运行 很好,文本更新正确,但是当我旋转我的 phone 并且当我收到一条消息时,我收到一条错误消息
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View test.test.com.test.HomeFragment.getView()' on a null object reference
而且文本再也不会更新了。
简答
这可以通过在 activity 的清单中添加 android:configChanges="orientation"
来解决,但这可能会导致 UI 错误,因为您需要自己处理更改方向。
长答案
mConnection.connect(wsuri, new WebSocketHandler() {
@Override
public void onOpen() {
Log.d("WIFI", "onOpen: Conneced to "+ wsuri);
}
这个内部匿名 class WebSocketHandler
在创建时包含对 MainActivity
当前实例的隐式引用,但该实例将被 Android 方向改变系统。所以你在方向改变后看到的是一个不同于你的 WebSocketHandler
class 指向的实例,导致在你的 findFragmentByTag
调用中返回 null 因为 HomeFragment
您尝试请求的内容已在您的 MainActivity
的旧实例中清理干净。这也会导致内存泄漏,因为您的 WebSocketHandler
会阻止 MainActivity
的旧实例被 GC 处理。
我建议你做的是有一个完全独立的 class 来处理 websocket 连接,而不是任何 Activity
的内部 class。或者您可以使用 android:configChanges="orientation"
并确保通过
正确处理方向更改
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//handle the orientation change, ex change/rearrange fragments
}
}
我想在收到消息时更新片段中的文本。
主要Activity我用wsuri做连接。我收到回调 onTextMessage 的每条消息都会被触发。我使用的图书馆是 autoBahn。
public class MainActivity extends AppCompatActivity{
private static WebSocketConnection mConnection = new WebSocketConnection();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intent_root_activity);
if(savedInstanceState == null){
frag_Home = new HomeFragment();
fragmentManager.beginTransaction().add(R.id.fragmentContent, frag_Home, getString(R.string.TAG_HOME)).commit();
}else{
if(fragmentManager.findFragmentByTag(getString(R.string.TAG_HOME)) == null){
frag_Home = new HomeFragment();
fragmentManager.beginTransaction().add(R.id.fragmentContent, frag_Home, getString(R.string.TAG_HOME)).commit();
}
}
}
@Override
protected void onResume() {
super.onResume();
// Start Connection
Connect(ipAdress);
Log.i("ROOT ACTIVITY", "onResume");
}
// Function callback events
private void Connect(String ipAddress){
final String wsuri = "ws://" + ipAddress + ":" + port;
try {
// Handle Websocket Event
mConnection.connect(wsuri, new WebSocketHandler() {
@Override
public void onOpen() {
Log.d("WIFI", "onOpen: Conneced to "+ wsuri);
}
@Override
public void onTextMessage(String payload) {
HomeFragment home = (HomeFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.TAG_HOME));
((TextView)home.getView().findViewById(R.id.txtMsg)).setText(payload);
}
Override
public void onClose(int code, String reason) {
}
}
}
}
}
所有 运行 很好,文本更新正确,但是当我旋转我的 phone 并且当我收到一条消息时,我收到一条错误消息
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View test.test.com.test.HomeFragment.getView()' on a null object reference
而且文本再也不会更新了。
简答
这可以通过在 activity 的清单中添加 android:configChanges="orientation"
来解决,但这可能会导致 UI 错误,因为您需要自己处理更改方向。
长答案
mConnection.connect(wsuri, new WebSocketHandler() {
@Override
public void onOpen() {
Log.d("WIFI", "onOpen: Conneced to "+ wsuri);
}
这个内部匿名 class WebSocketHandler
在创建时包含对 MainActivity
当前实例的隐式引用,但该实例将被 Android 方向改变系统。所以你在方向改变后看到的是一个不同于你的 WebSocketHandler
class 指向的实例,导致在你的 findFragmentByTag
调用中返回 null 因为 HomeFragment
您尝试请求的内容已在您的 MainActivity
的旧实例中清理干净。这也会导致内存泄漏,因为您的 WebSocketHandler
会阻止 MainActivity
的旧实例被 GC 处理。
我建议你做的是有一个完全独立的 class 来处理 websocket 连接,而不是任何 Activity
的内部 class。或者您可以使用 android:configChanges="orientation"
并确保通过
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
//handle the orientation change, ex change/rearrange fragments
}
}