この2つのクラスがあります。私のメインのアクティビティとAsyncTask
を拡張するアクティビティです。今度はメインのアクティビティでAsyncTask
のOnPostExecute()
から結果を取得する必要があります。メインのアクティビティに結果を渡したり取得したりするにはどうすればよいですか。
これがサンプルコードです。
私の主な活動.
public class MainActivity extends Activity{
AasyncTask asyncTask = new AasyncTask();
@Override
public void onCreate(Bundle aBundle) {
super.onCreate(aBundle);
//Calling the AsyncTask class to start to execute.
asyncTask.execute(a.targetServer);
//Creating a TextView.
TextView displayUI = asyncTask.dataDisplay;
displayUI = new TextView(this);
this.setContentView(tTextView);
}
}
これはAsyncTaskクラスです
public class AasyncTask extends AsyncTask<String, Void, String> {
TextView dataDisplay; //store the data
String soapAction = "http://sample.com"; //SOAPAction header line.
String targetServer = "https://sampletargeturl.com"; //Target Server.
//SOAP Request.
String soapRequest = "<sample XML request>";
@Override
protected String doInBackground(String... string) {
String responseStorage = null; //storage of the response
try {
//Uses URL and HttpURLConnection for server connection.
URL targetURL = new URL(targetServer);
HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
httpCon.setDoOutput(true);
httpCon.setDoInput(true);
httpCon.setUseCaches(false);
httpCon.setChunkedStreamingMode(0);
//properties of SOAPAction header
httpCon.addRequestProperty("SOAPAction", soapAction);
httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
httpCon.setRequestMethod(HttpPost.METHOD_NAME);
//sending request to the server.
OutputStream outputStream = httpCon.getOutputStream();
Writer writer = new OutputStreamWriter(outputStream);
writer.write(soapRequest);
writer.flush();
writer.close();
//getting the response from the server
InputStream inputStream = httpCon.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);
int intResponse = httpCon.getResponseCode();
while ((intResponse = bufferedReader.read()) != -1) {
byteArrayBuffer.append(intResponse);
}
responseStorage = new String(byteArrayBuffer.toByteArray());
} catch (Exception aException) {
responseStorage = aException.getMessage();
}
return responseStorage;
}
protected void onPostExecute(String result) {
aTextView.setText(result);
}
}
簡単です。
interface
クラスを作成します。ここで、String output
はオプションです。または、返す変数をいくつでも指定できます。
public interface AsyncResponse {
void processFinish(String output);
}
あなたのAsyncTask
クラスに行き、そしてフィールドとしてインターフェースAsyncResponse
を宣言してください:
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
public AsyncResponse delegate = null;
@Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
あなたのメインアクティビティではimplements
インターフェースAsyncResponse
が必要です。
public class MainActivity implements AsyncResponse{
MyAsyncTask asyncTask =new MyAsyncTask();
@Override
public void onCreate(Bundle savedInstanceState) {
//this to set delegate/listener back to this class
asyncTask.delegate = this;
//execute the async task
asyncTask.execute();
}
//this override the implemented method from asyncTask
@Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}
更新
私はこれがあなたの多くにとってとても好きなことを知りませんでした。だからここにinterface
を使う簡単で便利な方法があります。
まだ同じinterface
を使用しています。参考までに、これをAsyncTask
クラスに結合することができます。
AsyncTask
クラスで:
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
// you may separate this or combined to caller class.
public interface AsyncResponse {
void processFinish(String output);
}
public AsyncResponse delegate = null;
public MyAsyncTask(AsyncResponse delegate){
this.delegate = delegate;
}
@Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
これをActivity
クラスで行います。
public class MainActivity extends Activity {
MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){
@Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}).execute();
}
または、アクティビティのインターフェースを再度実装する
public class MainActivity extends Activity
implements AsyncResponse{
@Override
public void onCreate(Bundle savedInstanceState) {
//execute the async task
new MyAsyncTask(this).execute();
}
//this override the implemented method from AsyncResponse
@Override
void processFinish(String output){
//Here you will receive the result fired from async class
//of onPostExecute(result) method.
}
}
上記の2つの解決策、最初の解決策と3番目の解決策を見ることができるように、メソッドprocessFinish
を作成する必要があります。もう1つのメソッドは、呼び出し元パラメータの中にあります。入れ子になった匿名クラスがないため、3番目のものはもっときれいです。お役に立てれば
Tip :異なるオブジェクトを取得するために、String output
、String response
、およびString result
を異なるマッチングタイプに変更します。
いくつかの選択肢があります。
AsyncTask
クラスをActivity
クラス内にネストします。複数のアクティビティで同じタスクを使用しないと仮定すると、これが最も簡単な方法です。コードはすべて同じままです。既存のタスククラスをアクティビティのクラス内にネストしたクラスに移動するだけです。
public class MyActivity extends Activity {
// existing Activity code
...
private class MyAsyncTask extends AsyncTask<String, Void, String> {
// existing AsyncTask code
...
}
}
あなたのAsyncTask
への参照を取るあなたのActivity
のためのカスタムコンストラクタを作成してください。あなたはnew MyAsyncTask(this).execute(param1, param2)
のようなものでタスクをインスタンス化するでしょう。
public class MyAsyncTask extends AsyncTask<String, Void, String> {
private Activity activity;
public MyAsyncTask(Activity activity) {
this.activity = activity;
}
// existing AsyncTask code
...
}
私は以下のアプローチがとても簡単だと感じました。
コールバック用のインターフェースを宣言しました
public interface AsyncResponse {
void processFinish(Object output);
}
次に、あらゆる種類の並列要求に応答するための非同期タスクを作成しました
public class MyAsyncTask extends AsyncTask<Object, Object, Object> {
public AsyncResponse delegate = null;//Call back interface
public MyAsyncTask(AsyncResponse asyncResponse) {
delegate = asyncResponse;//Assigning call back interfacethrough constructor
}
@Override
protected Object doInBackground(Object... params) {
//My Background tasks are written here
return {resutl Object}
}
@Override
protected void onPostExecute(Object result) {
delegate.processFinish(result);
}
}
次にアクティビティクラスのボタンをクリックしたときに非同期タスクを呼び出しました。
public class MainActivity extends Activity{
@Override
public void onCreate(Bundle savedInstanceState) {
Button mbtnPress = (Button) findViewById(R.id.btnPress);
mbtnPress.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {
@Override
public void processFinish(Object output) {
Log.d("Response From Asynchronous task:", (String) output);
mbtnPress.setText((String) output);
}
});
asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });
}
});
}
}
ありがとう
あなたのMainクラスでこのコードを試すことができます。それは私のために働いたが、私は他の方法でメソッドを実装しました
try {
String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
}
catch (ExecutionException | InterruptedException ei) {
ei.printStackTrace();
}
この回答は遅れるかもしれませんが、Activity
がAsyncTask
に依存している場合、いくつか言及したいと思います。それはクラッシュやメモリ管理を防ぐのに役立ちます。上ですでに述べたように、答えはinterface
と一緒になります、我々はまたそれらにコールバックを言う。それらは情報提供者として機能しますが、Activity
またはinterface
のstrong参照を送信することは決してありません。その場合は常にweak参照を使用してください。
どのように問題を引き起こす可能性があるかについては、下のスクリーンショットを参照してください。
AsyncTask
をstrong参照で始めたかどうかが分かるように、データを取得するまでActivity
/Fragment
が有効であるという保証はありません。そのような場合はWeakReference
を使用したほうがよいでしょう。また、Activity
の強力な参照は保持されないので、メモリ管理にも役立ちます。その場合、歪み後のガベージコレクションに適します。
下のコードスニペットをチェックして、素晴らしいWeakReferenceの使い方を見つけてください -
MyTaskInformer.Java
インフォーマーとして機能するインターフェース。
public interface MyTaskInformer {
void onTaskDone(String output);
}
WeakReference
を使用する、長時間実行タスクを実行するためのMySmallAsyncTask.Java
AsyncTask。
public class MySmallAsyncTask extends AsyncTask<String, Void, String> {
// ***** Hold weak reference *****
private WeakReference<MyTaskInformer> mCallBack;
public MySmallAsyncTask(MyTaskInformer callback) {
this.mCallBack = new WeakReference<>(callback);
}
@Override
protected String doInBackground(String... params) {
// Here do whatever your task is like reading/writing file
// or read data from your server or any other heavy task
// Let us suppose here you get response, just return it
final String output = "Any out, mine is just demo output";
// Return it from here to post execute
return output;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask
// Make sure your caller is active
final MyTaskInformer callBack = mCallBack.get();
if(callBack != null) {
callBack.onTaskDone(s);
}
}
}
MainActivity.Java
このクラスは、このクラスでAsyncTask
implementation interface
を開始するため、およびこの[必須]メソッドでoverride
を開始するために使用されます。
public class MainActivity extends Activity implements MyTaskInformer {
private TextView mMyTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMyTextView = (TextView) findViewById(R.id.tv_text_view);
// Start your AsyncTask and pass reference of MyTaskInformer in constructor
new MySmallAsyncTask(this).execute();
}
@Override
public void onTaskDone(String output) {
// Here you will receive output only if your Activity is alive.
// no need to add checks like if(!isFinishing())
mMyTextView.setText(output);
}
}
AsyncTaskを呼び出すときにonPostExecuteをオーバーライドするだけで、数行で実行できます。これはあなたのための例です:
new AasyncTask()
{
@Override public void onPostExecute(String result)
{
// do whatever you want with result
}
}.execute(a.targetServer);
私はそれがあなたを助けてくれて嬉しいです。
あなたのOncreate()に:
`
myTask.execute("url");
String result = "";
try {
result = myTask.get().toString();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
`
なぜ人々はそれをそんなに難しくしますか。
これで十分でしょう。
非同期タスクにonPostExecuteを実装せず、Activityに実装します。
public class MainActivity extends Activity
{
@Override
public void onCreate(Bundle savedInstanceState) {
//execute the async task
MyAsyncTask task = new MyAsyncTask(){
protected void onPostExecute(String result) {
//Do your thing
}
}
task.execute("Param");
}
}
AsyncTask
の get()
メソッド(またはオーバーロードされた get(long, TimeUnit)
)を呼び出すことができます。このメソッドはAsyncTask
がその作業を完了するまでブロックします。その時点でResult
が返されます。
非同期タスクの作成/開始からget
メソッドの呼び出しまでの間に他の作業を行うことをお勧めします。そうしないと、非同期タスクを効率的に利用していないことになります。
こんにちはあなたはこのようなものを作ることができます:
AsyncTaskを実装するクラスを作成します
// TASK
public class SomeClass extends AsyncTask<Void, Void, String>>
{
private OnTaskExecutionFinished _task_finished_event;
public interface OnTaskExecutionFinished
{
public void OnTaskFihishedEvent(String Reslut);
}
public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
{
if(_event != null)
{
this._task_finished_event = _event;
}
}
@Override
protected void onPreExecute()
{
super.onPreExecute();
}
@Override
protected String doInBackground(Void... params)
{
// do your background task here ...
return "Done!";
}
@Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
if(this._task_finished_event != null)
{
this._task_finished_event.OnTaskFihishedEvent(result);
}
else
{
Log.d("SomeClass", "task_finished even is null");
}
}
}
メインアクティビティに追加
// MAIN ACTIVITY
public class MyActivity extends ListActivity
{
...
SomeClass _some_class = new SomeClass();
_someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
{
@Override
public void OnTaskFihishedEvent(String result)
{
Toast.makeText(getApplicationContext(),
"Phony thread finished: " + result,
Toast.LENGTH_SHORT).show();
}
});
_some_class.execute();
...
}
あなたはあなた自身のリスナーを書くことができます。 HelmiB の答えと同じですが、より自然に見えます。
リスナーインタフェースを作成します。
public interface myAsyncTaskCompletedListener {
void onMyAsynTaskCompleted(int responseCode, String result);
}
それからあなたの非同期タスクを書いてください:
public class myAsyncTask extends AsyncTask<String, Void, String> {
private myAsyncTaskCompletedListener listener;
private int responseCode = 0;
public myAsyncTask() {
}
public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
this.listener = listener;
this.responseCode = responseCode;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... params) {
String result;
String param = (params.length == 0) ? null : params[0];
if (param != null) {
// Do some background jobs, like httprequest...
return result;
}
return null;
}
@Override
protected void onPostExecute(String finalResult) {
super.onPostExecute(finalResult);
if (!isCancelled()) {
if (listener != null) {
listener.onMyAsynTaskCompleted(responseCode, finalResult);
}
}
}
}
最後にリスナーをアクティビティに実装します。
public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {
@Override
public void onMyAsynTaskCompleted(int responseCode, String result) {
switch (responseCode) {
case TASK_CODE_ONE:
// Do something for CODE_ONE
break;
case TASK_CODE_TWO:
// Do something for CODE_TWO
break;
default:
// Show some error code
}
}
そしてこれが、asyncTaskを呼び出す方法です。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Some other codes...
new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
// And some another codes...
}
Activityクラスに静的メンバーを作成します。それからonPostExecute
の間に値を代入します
たとえば、AsyncTaskの結果がStringの場合は、Activityにpublic static stringを作成します。
public static String dataFromAsyncTask;
次に、AsyncTaskのonPostExecute
で、メインクラスを静的に呼び出して値を設定します。
MainActivity.dataFromAsyncTask = "result blah";
これを試して:
public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {
private CallBack callBack;
public interface CallBack {
void async( JSONObject jsonResult );
void sync( JSONObject jsonResult );
void progress( Integer... status );
void cancel();
}
public SomAsyncTask(CallBack callBack) {
this.callBack = callBack;
}
@Override
protected JSONObject doInBackground(String... strings) {
JSONObject dataJson = null;
//TODO query, get some dataJson
if(this.callBack != null)
this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD
return dataJson;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if(this.callBack != null)
this.callBack.progress(values);// synchronize with MAIN LOOP THREAD
}
@Override
protected void onPostExecute(JSONObject jsonObject) {
super.onPostExecute(jsonObject);
if(this.callBack != null)
this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
}
@Override
protected void onCancelled() {
super.onCancelled();
if(this.callBack != null)
this.callBack.cancel();
}
}
そして使用例:
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context _localContext = getContext();
SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {
@Override
public void async(JSONObject jsonResult) {//async thread
//some async process, e.g. send data to server...
}
@Override
public void sync(JSONObject jsonResult) {//sync thread
//get result...
//get some resource of Activity variable...
Resources resources = _localContext.getResources();
}
@Override
public void progress(Integer... status) {//sync thread
//e.g. change status progress bar...
}
@Override
public void cancel() {
}
};
new SomeAsyncTask( someCallBack )
.execute("someParams0", "someParams1", "someParams2");
}
私はそれをスレッドとハンドラ/メッセージを使って動作させます。手順は以下のとおりです。進捗状況を宣言するダイアログ
ProgressDialog loadingdialog;
操作が完了したらダイアログを閉じるための関数を作成します。
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
loadingdialog.dismiss();
}
};
実行詳細をコーディングします。
public void startUpload(String filepath) {
loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
final String _path = filepath;
new Thread() {
public void run() {
try {
UploadFile(_path, getHostName(), getPortNo());
handler.sendEmptyMessage(0);
} catch (Exception e) {
Log.e("threadmessage", e.getMessage());
}
}
}.start();
}
データをAsynTask
に委任または提供するには、 "protocols" を使用する必要があります。
代行者とデータソース
デリゲートは、そのオブジェクトがプログラム内でイベントに遭遇したときに、そのオブジェクトに代わって、またはそれと協調して動作するオブジェクトです。 ( アップルの定義 )
プロトコルは、いくつかの動作を委任するためのいくつかのメソッドを定義するインタフェースです。
多少オーバーボードになるかもしれませんが、実行コードと結果の両方にコールバックを提供しました。明らかにスレッドの安全性のために、あなたはあなたの実行コールバックでアクセスするものに注意したいと思います。
AsyncTaskの実装
public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,
ResultType>
{
public interface ExecuteCallback<E, R>
{
public R execute(E executeInput);
}
public interface PostExecuteCallback<R>
{
public void finish(R result);
}
private PostExecuteCallback<ResultType> _resultCallback = null;
private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;
AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
{
_resultCallback = postExecuteCallback;
_executeCallback = executeCallback;
}
AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
{
_executeCallback = executeCallback;
}
@Override
protected ResultType doInBackground(final ExecuteType... params)
{
return _executeCallback.execute(params[0]);
}
@Override
protected void onPostExecute(ResultType result)
{
if(_resultCallback != null)
_resultCallback.finish(result);
}
}
コールバック:
AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new
AsyncDbCall.ExecuteCallback<Device, Device>()
{
@Override
public Device execute(Device device)
{
deviceDao.updateDevice(device);
return device;
}
};
そして最後に非同期タスクの実行:
new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);