[解決済み】Android. Fragment getActivity()がNULLを返すことがある
質問
開発者コンソールのエラーレポートで、NPE問題が報告されているのを見ることがあります。私のコードのどこが問題なのか理解できません。エミュレータと私のデバイスでは、アプリケーションは強制終了せずにうまく動作しますが、一部のユーザーは、getActivity()メソッドを呼び出したときにフラグメントクラスでNullPointerExceptionが発生します。
アクティビティ
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) {}
});
}
AsyncTask クラス
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()が呼ばれる前にisAddedをチェックするのは良い習慣です。これは、フラグメントがアクティビティから切り離されたときに、ヌルポインタの例外が発生するのを防ぐのに役立ちます。たとえば、アクティビティには、非同期タスクをプッシュするフラグメントを含めることができます。タスクが終了すると、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();
}
}
フラグメントを開いてタスクをプッシュし、すぐにバックを押して前のアクティビティに戻ると、タスクが終了したときに、onPostExecute()でgetActivity()メソッドを呼び出して、そのアクティビティにアクセスしようとするのです。 もし、アクティビティがすでにデタッチされており、このチェックがない場合。
if (isAdded())
を実行すると、アプリケーションがクラッシュします。
関連
-
aapt2エラー:ログを確認する(具体的な原因の探り方)
-
android block certificate validation CertPathValidatorException: 認証パスのトラストアンカーが見つかりません
-
AndroidStudioのショートカット 検索/置換
-
[解決済み] Androidのソフトキーボードをプログラムで閉じる/隠すにはどうすればよいですか?
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] instanceofを呼び出す前にnullチェックは必要ですか?
-
[解決済み] Androidアプリケーションのアクティビティ間でデータを受け渡すにはどうすればよいですか?
-
[解決済み] Androidのローテーションでアクティビティを再開する
-
[解決済み] FragmentでonActivityResultが呼び出されない
-
[解決済み】Android UserManager.isUserAGoat()の正しい使用例?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
adb シェルがデバイスのオフラインを求めるプロンプトを表示する
-
AndroidStudio reports Could not resolve all artifacts for configuration ':app:classpath'.
-
Android: インポートモジュールエラー Android リソースのリンクに失敗しました
-
エラー:未宣言の識別子(AS)の使用
-
プロセス 'command 'F:\sdkbuild-tools', 26.0.2 AAAPT.exe' finished with non-zero exit value 1
-
Androidで、onTouchEventでダブルクリックを実装し、ダブルクリックイベントとして判定する方法
-
android bluetooth--Bluetooth on、検索、ペアリング、接続
-
Android Studioのgitの使用とgitの設定パス
-
Android TextViewは、テキスト内容が表示省略記号を超えているかどうかを判断する
-
[解決済み] ViewPagerとフラグメント - フラグメントの状態を保存する正しい方法は何ですか?