안드로이드.fragment getActivity()가 null을 반환하는 경우가 있습니다.
개발자 콘솔 오류 보고서에서 NPE 문제가 있는 보고서가 가끔 나타납니다.저는 제 코드에 무엇이 문제인지 이해할 수 없습니다.에뮬레이터에서 장치 응용 프로그램이 강제로 닫히지 않고 잘 작동하지만 일부 사용자는 NullPointer를 얻습니다.getActivity() 메서드가 호출될 때 fragment 클래스에서 예외입니다.
활동
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
pager = (ViewPager) findViewById(R.id.pager);
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) adapter.getItem(0));
firstTask.execute();
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
}
비동기 태스크 클래스
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
프래그먼트 클래스
public class FirstFragment extends Fragment immplements Taskable, TaskListener{
public FirstFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_view, container, false);
}
@Override
public void executeTask() {
FirstTask firstTask = new FirstTask(MyActivity.this);
firstTask.setTaskListener(this);
firstTask.execute();
}
@Override
public void onTaskComplete(T result) {
// NPE is here
Resources res = getActivity().getResources();
...
}
}
백그라운드에서 응용 프로그램을 다시 시작할 때 이 오류가 발생할 수 있습니다.이 경우 어떻게 해야 이 상황에 적절하게 대처할 수 있습니까?
제 문제에 대한 해결책을 찾은 것 같습니다.아주 좋은 설명이 여기저기서 나오고 있습니다.다음은 제 예입니다.
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
private Bundle savedInstanceState;
@Override
public void onCreate(Bundle savedInstanceState) {
....
this.savedInstanceState = savedInstanceState;
pager = (ViewPager) findViewById(R.id.pager);;
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
if (savedInstanceState == null){
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
}else{
Integer count = savedInstanceState.getInt("tabsCount");
String[] titles = savedInstanceState.getStringArray("titles");
for (int i = 0; i < count; i++){
adapter.addFragment(getFragment(i), titles[i]);
}
}
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) getFragment(0));
firstTask.execute();
}
private Fragment getFragment(int position){
return savedInstanceState == null ? adapter.getItem(position) : getSupportFragmentManager().findFragmentByTag(getFragmentTag(position));
}
private String getFragmentTag(int position) {
return "android:switcher:" + R.id.pager + ":" + position;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tabsCount", adapter.getCount());
outState.putStringArray("titles", adapter.getTitles().toArray(new String[0]));
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
이 코드의 주요 개념은 응용 프로그램을 정상적으로 실행하는 동안 새 조각을 만들어 어댑터에 전달한다는 것입니다.응용 프로그램 프래그먼트 관리자가 이미 이 프래그먼트의 인스턴스를 가지고 있으므로 프래그먼트 관리자로부터 이 인스턴스를 가져와 어댑터에 전달해야 합니다.
갱신하다
또한 getActivity()를 호출하기 전에 fragment를 사용하여 Added를 확인하는 것이 좋습니다.이렇게 하면 프래그먼트가 활동에서 분리될 때 널 포인터 예외를 피할 수 있습니다.예를 들어, 활동에는 비동기 작업을 푸시하는 프래그먼트가 포함될 수 있습니다.작업이 완료되면 onTaskComplete 수신기가 호출됩니다.
@Override
public void onTaskComplete(List<Feed> result) {
progress.setVisibility(View.GONE);
progress.setIndeterminate(false);
list.setVisibility(View.VISIBLE);
if (isAdded()) {
adapter = new FeedAdapter(getActivity(), R.layout.feed_item, result);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
프래그먼트를 열고 작업을 푸시한 다음 빠르게 뒤로 눌러 이전 작업으로 돌아갑니다. 작업이 완료되면 onPost의 작업에 액세스하려고 합니다.getActivity() 메서드를 호출하여 실행합니다.활동이 이미 분리되어 있는데 이 체크가 없는 경우:
if (isAdded())
응용프로그램이 충돌합니다.
는 이 문제가 해결된 이 입니다.나는 나의 부모님을 위해 추상적인 수업을 만들었습니다.Fragment
:
public abstract class ABaseFragment extends Fragment{
protected IActivityEnabledListener aeListener;
protected interface IActivityEnabledListener{
void onActivityEnabled(FragmentActivity activity);
}
protected void getAvailableActivity(IActivityEnabledListener listener){
if (getActivity() == null){
aeListener = listener;
} else {
listener.onActivityEnabled(getActivity());
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (aeListener != null){
aeListener.onActivityEnabled((FragmentActivity) activity);
aeListener = null;
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (aeListener != null){
aeListener.onActivityEnabled((FragmentActivity) context);
aeListener = null;
}
}
}
마다 말입니다. 그래서 필요할 때마다Fragments
Activity
d getActivity()
, 전화해 봐야겠습니다.
getAvailableActivity(new IActivityEnabledListener() {
@Override
public void onActivityEnabled(FragmentActivity activity) {
// Do manipulations with your activity
}
});
이 좋은 방법은 때 하는 것입니다.onAttach
예:예)를 사용합니다.
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
@Override
public void onDetach() {
super.onDetach();
mContext = null;
}
됨 ,onAttach(Activity)
은 ㅇonAttach(Context)
사용되고 있습니다.
상위 액티비티에서 시작할 때까지 getActivity()가 필요한 메서드를 Fragment 내에서 호출하지 마십시오.
private MyFragment myFragment;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
myFragment = new MyFragment();
ft.add(android.R.id.content, youtubeListFragment).commit();
//Other init calls
//...
}
@Override
public void onStart()
{
super.onStart();
//Call your Fragment functions that uses getActivity()
myFragment.onPageSelected();
}
이런 문제와 한동안 씨름을 해왔는데, 믿을 만한 해결책을 생각해 낸 것 같습니다.
를 .this.getActivity()
않을 것입니다null
당분간은Fragment
. .Activity
문헌
에서, 는 라고합니다.ActivityBuffer
으로, class
입니다에 할 수 참조를 을 다룹니다.Activity
을 약속하고 .Runnable
Activity
유효한 참조가 있을 때마다 상황을 파악할 수 있습니다.Runnable
는 UI가 됩니다될 됩니다.Context
할 수 있습니다. 그렇지 됩니다. 그렇지 않으면 실행이 지연됩니다.Context
준비가 되었습니다.
/** A class which maintains a list of transactions to occur when Context becomes available. */
public final class ActivityBuffer {
/** A class which defines operations to execute once there's an available Context. */
public interface IRunnable {
/** Executes when there's an available Context. Ideally, will it operate immediately. */
void run(final Activity pActivity);
}
/* Member Variables. */
private Activity mActivity;
private final List<IRunnable> mRunnables;
/** Constructor. */
public ActivityBuffer() {
// Initialize Member Variables.
this.mActivity = null;
this.mRunnables = new ArrayList<IRunnable>();
}
/** Executes the Runnable if there's an available Context. Otherwise, defers execution until it becomes available. */
public final void safely(final IRunnable pRunnable) {
// Synchronize along the current instance.
synchronized(this) {
// Do we have a context available?
if(this.isContextAvailable()) {
// Fetch the Activity.
final Activity lActivity = this.getActivity();
// Execute the Runnable along the Activity.
lActivity.runOnUiThread(new Runnable() { @Override public final void run() { pRunnable.run(lActivity); } });
}
else {
// Buffer the Runnable so that it's ready to receive a valid reference.
this.getRunnables().add(pRunnable);
}
}
}
/** Called to inform the ActivityBuffer that there's an available Activity reference. */
public final void onContextGained(final Activity pActivity) {
// Synchronize along ourself.
synchronized(this) {
// Update the Activity reference.
this.setActivity(pActivity);
// Are there any Runnables awaiting execution?
if(!this.getRunnables().isEmpty()) {
// Iterate the Runnables.
for(final IRunnable lRunnable : this.getRunnables()) {
// Execute the Runnable on the UI Thread.
pActivity.runOnUiThread(new Runnable() { @Override public final void run() {
// Execute the Runnable.
lRunnable.run(pActivity);
} });
}
// Empty the Runnables.
this.getRunnables().clear();
}
}
}
/** Called to inform the ActivityBuffer that the Context has been lost. */
public final void onContextLost() {
// Synchronize along ourself.
synchronized(this) {
// Remove the Context reference.
this.setActivity(null);
}
}
/** Defines whether there's a safe Context available for the ActivityBuffer. */
public final boolean isContextAvailable() {
// Synchronize upon ourself.
synchronized(this) {
// Return the state of the Activity reference.
return (this.getActivity() != null);
}
}
/* Getters and Setters. */
private final void setActivity(final Activity pActivity) {
this.mActivity = pActivity;
}
private final Activity getActivity() {
return this.mActivity;
}
private final List<IRunnable> getRunnables() {
return this.mRunnables;
}
}
그 구현의 관점에서, 우리는 Pawan M이 위에서 설명한 동작과 일치하도록 라이프 사이클 방법을 적용하는 데 주의해야 합니다.
public class BaseFragment extends Fragment {
/* Member Variables. */
private ActivityBuffer mActivityBuffer;
public BaseFragment() {
// Implement the Parent.
super();
// Allocate the ActivityBuffer.
this.mActivityBuffer = new ActivityBuffer();
}
@Override
public final void onAttach(final Context pContext) {
// Handle as usual.
super.onAttach(pContext);
// Is the Context an Activity?
if(pContext instanceof Activity) {
// Cast Accordingly.
final Activity lActivity = (Activity)pContext;
// Inform the ActivityBuffer.
this.getActivityBuffer().onContextGained(lActivity);
}
}
@Deprecated @Override
public final void onAttach(final Activity pActivity) {
// Handle as usual.
super.onAttach(pActivity);
// Inform the ActivityBuffer.
this.getActivityBuffer().onContextGained(pActivity);
}
@Override
public final void onDetach() {
// Handle as usual.
super.onDetach();
// Inform the ActivityBuffer.
this.getActivityBuffer().onContextLost();
}
/* Getters. */
public final ActivityBuffer getActivityBuffer() {
return this.mActivityBuffer;
}
}
으로 내의 Fragment
BaseFragment
할 수 걸 됐어요getActivity()
, 에 를 걸 수 있습니다.this.getActivityBuffer().safely(...)
합니다.ActivityBuffer.IRunnable
작업을 위해!
은 내용.void run(final Activity pActivity)
그러면 UI 스레드를 따라 실행할 수 있습니다.
ActivityBuffer
다음과 같이 사용할 수 있습니다.
this.getActivityBuffer().safely(
new ActivityBuffer.IRunnable() {
@Override public final void run(final Activity pActivity) {
// Do something with guaranteed Context.
}
}
);
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// run the code making use of getActivity() from here
}
이것이 오래된 질문이라는 것을 알고 있지만 다른 사람들에 의해 내 문제가 해결되지 않았기 때문에 나는 그것에 대한 답을 제공해야 한다고 생각합니다.
우선 : fragmentTransactions를 사용하여 fragments를 동적으로 추가하고 있었습니다.둘째: 내 프래그먼트는 AsyncTasks(서버의 DB 쿼리)를 사용하여 수정되었습니다.셋째: 내 프래그먼트가 액티비티 시작 시 인스턴스화되지 않았습니다. 넷째: 프래그먼트 변수를 가져오기 위해 사용자 지정 프래그먼트 인스턴스화 "create or load it"을 사용했습니다.넷째: 방향전환으로 인해 활동이 재창조되었습니다.
문제는 질의응답 때문에 프래그먼트를 '제거'하고 싶었는데 바로 직전에 프래그먼트가 잘못 생성된 것입니다.나중에 "커밋"을 했기 때문에 제거할 시간이 되었을 때 프래그먼트가 아직 추가되지 않은 이유를 모르겠습니다.따라서 getActivity()가 null을 반환했습니다.
해결책 : 1)새 프래그먼트를 생성하기 전에 프래그먼트의 첫 번째 인스턴스를 올바르게 찾고 있는지 확인해야 했습니다 2)방향 변경을 통해 유지하기 위해 해당 프래그먼트에 serRetainInstance(true)를 넣어야 했습니다(백스택이 필요 없으므로 문제 없음) 3)"제거" 직전에 "재생하거나 오래된 조각을 가져오는" 대신에, 저는 그 조각을 직접 활동 시작에 넣었습니다.fragment 변수를 제거하기 전에 fragment 변수를 "로딩"(또는 인스턴스화)하는 대신 액티비티 시작 시에 인스턴스화하면 getActivity 문제가 방지됩니다.
Kotlin에서 getActivity() null 조건을 처리하기 위해 이 방법을 시도할 수 있습니다.
activity?.let { // activity == getActivity() in java
//your code here
}
활동이 null인지 아닌지 확인하고 null이 아닌 경우 내부 코드를 실행합니다.
언급URL : https://stackoverflow.com/questions/11631408/android-fragment-getactivity-sometimes-returns-null
'programing' 카테고리의 다른 글
MySQL(MariaDB)에서 SQL(Azure)로 마이그레이션 (0) | 2023.09.25 |
---|---|
워드프레스 플러그인 기능을 자체 플러그인으로 대체 (0) | 2023.09.25 |
검색 결과에 ACF 필드 추가 페이지 WordPress (0) | 2023.09.25 |
Oracle PL/SQL Developer로 덤프를 만드는 방법은? (0) | 2023.09.25 |
알 수 없는 초기 문자 집합 인덱스 '255'가 서버에서 수신됨 (0) | 2023.09.25 |