AsyncTask
クラスを呼び出すMainActivity.Javaというクラスがあります。最後のクラスには、実行時にこのエラーを返すfindViewById()
があります。
Java.lang.NullPointerException: Attempt to invoke virtual method 'Android.view.View <mypackage>.MainActivity.findViewById(int)' on a null object reference
ImageView
が機能し終わった後、R.layout.activity_main
に配置されたAsyncTask
を編集する方法を理解できません。
MainActivity.Java
public class MainActivity extends Activity {
public MainActivity() {}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Connection().execute();
}
}
Connection.Java
public class Connection extends AsyncTask<String, Void, String> {
public String result;
//I know, this isn't correct, how can i do?
public MainActivity MainActivity;
@Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//...
return "a string";
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
//...
// Where the error is generated
ImageView image = (ImageView) MainActivity.findViewById(R.id.image);
//...
}
}
エラーは
public MainActivity MainActivity;
初期化されないため、nullを指します。コードを機能させるための最小ステップはMainActivityにあります
new Connection(this).execute();
接続
public class Connection extends AsyncTask<String, Void, String> {
public MainActivity MainActivity;
public Connection(MainActivity activity) {
MainActivity = activity;
}
しかし、onCreateでタスクを作成してアクティビティを渡すことは、とにかく最良のアイデアではありません。また、フィールド名は常に小文字で始まる必要があります。
最良の方法は、ImageViewをAsyncTaskに渡すことです。アクティビティが開始されるまでタスクを開始しないでください。また、アクティビティが停止したときにタスクをキャンセルすることを忘れないでください。
public final class MainActivity extends Activity {
public MainActivity() {}
private Connection connection;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ImageView) findViewById(R.id.image);
}
@Override
protected void onStart() {
super.onStart();
if (connection == null || connection.getStatus() != AsyncTask.Status.RUNNING) {
connection = new Connection(imageView);
connection.execute();
}
}
@Override
protected void onStop() {
super.onStop();
if (connection != null && connection.getStatus() == AsyncTask.Status.RUNNING) {
connection.cancel(true);
}
}
}
Connection.Javaで、リークを避けるためにImageViewをWeakReferenceとして保存します。
public final class Connection extends AsyncTask<String, Void, String> {
private final WeakReference<ImageView> imageViewRef;
public Connection(ImageView view) {
imageViewRef = new WeakReference<ImageView>(view);
}
@Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//...
return "a string";
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//...
final ImageView imageView = imageViewRef.get();
// if the Activity is still alive, the ImageView will not be null
if (imageView != null) {
// set an image or whatever you need
image.setImageResource(666);
}
}
クラスの変数としてimageviewを置きます
private ImageView image;
onCreateで初期化
image = (ImageView) findViewById(R.id.image);
public class Connection extends AsyncTask<String, Void, String> {
public String result;
//I know, this isn't correct, how can i do?
public MainActivity MainActivity;
@Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//...
return "a string";
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
//...
// Where the error is generated
//do other stuff with your imageview
//...
}
}
実際に私は活動とサービスのアプリケーションを働いていました。バインドサービスでは、BIND_AUTO_CREATEを使用する代わりにBIND_IMPORTANTフラグを使用しているという点でも同じ問題があります。
フラグを変更すると、正常に機能しました。