Android getActivity在为片段执行线程后一直返回null
在将问题标记为重复问题之前,请先阅读我的问题 我有一个map fragment,它使用firebase实时数据库执行了很多进程,我面临的问题是一些回调会进行密集的处理,这使得map非常滞后,有时会使应用程序崩溃,所以我创建了一个新线程来执行回调,其中有一些更新UI的代码,因此,我使用Android getActivity在为片段执行线程后一直返回null,android,firebase,android-fragments,android-activity,firebase-realtime-database,Android,Firebase,Android Fragments,Android Activity,Firebase Realtime Database,在将问题标记为重复问题之前,请先阅读我的问题 我有一个map fragment,它使用firebase实时数据库执行了很多进程,我面临的问题是一些回调会进行密集的处理,这使得map非常滞后,有时会使应用程序崩溃,所以我创建了一个新线程来执行回调,其中有一些更新UI的代码,因此,我使用runOnUiThread运行它 当我第一次打开片段时,一切都很好,在我按下back并再次打开它之后,getActivity总是来null 我试过这个著名的解决办法 FragmentActivity mActivit
runOnUiThread
运行它
当我第一次打开片段时,一切都很好,在我按下back并再次打开它之后,getActivity
总是来null
我试过这个著名的解决办法
FragmentActivity mActivity;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mActivity = (FragmentActivity) context;
}
@Override
public void onDetach() {
super.onDetach();
mActivity = null;
}
并使用了mActivity
而不是getActivity
,但它不起作用mActivity
也一直以null
的形式出现
我不知道为什么会发生这种错误!当我再次打开片段时,它再次添加到backbackback上,并再次附加,因此活动不应为null,以及为什么它仅在第一次启动时添加才起作用
代码
void updateStudents() {
if (isRecursionEnable) {
return;
}
isRecursionEnable = true;
thread = new Thread(new Runnable() {
@Override
public void run() {
if (!thread.isInterrupted()) {
studentQuery.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(final DataSnapshot snapshot, String s) {
Student_User.add(snapshot.getValue(TestUserStudent.class));
if (getActivity() != null) { // NPE
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
showAllMarkers(snapshot); // show custom markers on the map
}
});
}
}
@Override
public void onChildChanged(final DataSnapshot snapshot, String s) {
Student_User.add(snapshot.getValue(TestUserStudent.class));
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
showAllMarkers(snapshot);
}
});
}
}
@Override
public void onChildRemoved(DataSnapshot snapshot) {
}
@Override
public void onChildMoved(DataSnapshot snapshot, String s) {
}
@Override
public void onCancelled(DatabaseError error) {
}
});
}
}
}, "");
thread.start();
}
此问题显示应用程序中存在一些依赖性问题。也许你应该找到其他方法来实现你的愿望 无论如何,请看一下:
.setRetainInstance(true)
这并不理想,你应该避免。但如果没有其他办法,它可能会解决你的问题
希望有帮助。这个问题很难解决,因为UI代码与数据加载逻辑纠缠在一起。我认为最好的解决办法是让这些东西独立起来。这很可能会解决问题,或者至少会使问题更容易发现和解决。也将改善总体特征设计 这里是一个简短的代码狙击手的要求,只是为了理解我的想法。我不会写整件事,因为这是不可能的 创建状态类,例如
StudentState
。该类还将提供一个侦听器接口,该接口将向片段发送更新
public class StudentState {
// You might want to store Student_User here instead
// I'm not sure how your data is currently represented.
private DataSnapshot dataSnapshot;
// Can also be a list of listeners if needed.
private StudentStateListener studentStateListener;
public void registerListener(StudentStateListener listener) {
studentStateListener = listener;
}
public void unregisterListener() {
studentStateListener = null;
}
...
public void setDataSnapshot(DataSnapshot dataSnapshot) {
this.dataSnapshot = dataSnapshot;
if (studentStateListener != null) {
studentStateListener.onDataSnapshotLoadFinished(dataSnapshot);
}
}
public interface StudentStateListener {
void onDataSnapshotLoadFinished(DataSnapshot dataSnapshot);
}
}
在片段中实现它:
public class StudentFragment implements StudentStateListener {
// The state can be initialized in multiple ways.
// It can be a singleton, or stored in Application class, or
// defined in your base activity, etc. Up to you. Ideally
// should be injected via dependency injection if you use one, such as Dagger.
private StudentState state;
@Override
public void onCreate() {
// initialize state
// ...
}
@Override
public void onResume() {
state.registerListener(this);
// If the data has already been loaded you might also want the following.
// It's up to you.
if (state.getDataSnapshot() != null) {
showAllMarkers(state.getDataSnapshot());
}
}
@Override
public void onPause() {
state.unregisterListener();
}
...
@Override
public void onDataSnapshotLoadFinished(DataSnapshot dataSnapshot) {
if (!isAdded()) {
return;
}
showAllMarkers(snapshot);
}
public void updateStudents() {
// I'm not quite sure how to work with your API but basically the idea is to load a new data snapshot and store it in the state
// This should happen in background thread.
studentQuery.loadDataSnapshot(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot) {
state.setDataSnapshot(dataSnapshot);
}
});
}
}
我希望这有帮助。。祝你好运 从附加的代码中,我只能得出结论,您必须在尚未附加到任何内容的片段中运行它。但总的来说,没有足够的信息来说明其他问题。请检查这个答案。我认为这是最好的解决办法。请试一试,你需要更多的信息吗。!我在activitycreated中调用了这个方法。很难说到底出了什么问题,但我确信如果
getActivity()
返回null,这意味着片段被分离。它要么尚未连接,要么已经分离。与其尝试将数据加载与片段附件同步,不如将它们分开。在需要时加载数据,并将其存储在方便的位置。然后抛出加载已完成的事件。当附加片段时,它将捕获事件并更新UI。如果没有,它可以从存储数据的位置获取数据。因此,您可以避免这种回调依赖关系,因为它会导致问题。@DäñishShärmá也不起作用,一旦线程被执行,活动就会始终变为null。!我在内部调用了activitycreated
,但没有任何更改。。一旦线程被执行,活动就会一直变为空。!为什么要将mActivity设置为null onDetach()?有什么特别的原因吗?如果没有,请尝试删除它。不,这只是一个变通办法,我试图解决这个问题,但没有奏效。如果您获取activity()?它还回什么吗?如果是,只需(FragmentActivity)getActivity()。如果它为null,则表示该片段已从活动中分离,我无法使用它来更新UI,因此我的问题是如何使getActivity始终不为null!