我有一个JSONObject
来自AsyncTask
课程内的API调用。我想将该JSON对象传递给我的MainActivity
类,以在GUI中显示JSONObject
数据。我在一些搜索中找到了一些解决方案并提出了一个紧密的解决方案。但是,当我从MainActivity
类访问时,它表示JSONObject
为空。我有什么不对吗?这是最好的方法吗?
以下是我的AsyncTask
班级
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
/**
* Created by Nisal on 13-Sep-17.
*/
public class GetStationsAPICall extends AsyncTask<String, Void, JSONObject> {
Context ctx;
JSONObject responseObj;
String result;
public interface AsyncResponse {
void processFinish(JSONObject output);
}
public AsyncResponse delegate = null;
public GetStationsAPICall(AsyncResponse delegate){
this.delegate = delegate;
}
// GetStationsAPICall(Context ctx){
// this.ctx=ctx;
// }
@Override
protected JSONObject doInBackground(String... params) {
String method = params[0];
if(method.equals("getStations")){
try {
HttpClient client = new DefaultHttpClient();
String getURL = "http://api.gate.com/?lang=en";
HttpGet httpGet = new HttpGet(getURL);
httpGet .setHeader("Authorization", "Bearer 690");
HttpResponse response = client.execute(httpGet);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
//parse response.
Log.e("Response", EntityUtils.toString(resEntity));
// return "Successfully Connected!";
}else{
// return "Connection Failed!";
}
} catch (Exception e) {
e.printStackTrace();
// return "Connection Failed!";
}
}
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(JSONObject obj) {
delegate.processFinish(obj);
}
}
以下是我的MainActivity
班级
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import org.json.JSONObject;
public class MainActivity extends Activity implements GetStationsAPICall.AsyncResponse{
Button btnSearch;
String method = "getStations";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GetStationsAPICall getStations = new GetStationsAPICall(this);
new GetStationsAPICall(this).execute(method);
}
public void searchClicked(View view){
Toast.makeText(MainActivity.this,"Search Clicked",Toast.LENGTH_SHORT).show();
}
@Override
public void processFinish(JSONObject output) {
Toast.makeText(MainActivity.this,"ProcessFinish",Toast.LENGTH_SHORT).show();
if(output != null){
Toast.makeText(MainActivity.this,"not null",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this," null",Toast.LENGTH_SHORT).show();
}
}
}
我可以在JSONObject
类中获得AsyncTask
,但是当我尝试将其传递给MainActivity
类并在那里使用它时。 JSONObject变为null
。我在这做错了什么?
答案 0 :(得分:2)
虽然我确定你有一个可行的解决方案,但我不建议你把你的活动变成一个可能泄漏它的监听器(如果你在得到结果之前按下主页按钮会发生什么?)。此外,如前所述,您遇到的主要问题是您从null
函数返回doInBackground
。所以我们暂时解决这两个问题:
<强> MainActivity.java 强>
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import org.json.JSONObject;
public class MainActivity extends Activity {
Button btnSearch;
String method = "getStations";
BroadcastReceiver apiListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BroadcastReceiver apiListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String output = intent.getStringExtra("API_Response); //Getting the string extra you input earlier in the AsyncTask.
Toast.makeText(MainActivity.this,"ProcessFinish",Toast.LENGTH_SHORT).show();
if(output != null){
Toast.makeText(MainActivity.this,"not null",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this," null",Toast.LENGTH_SHORT).show();
}
}
};
//Since you are starting your AsyncTask here, might want to set up the receiver prior to calling the task.
LocalBroadcastManager.getInstance(this).registerReceiver(apiListener, new IntentFilter(""));
GetStationsAPICall getStations = new GetStationsAPICall(this);
new GetStationsAPICall(this).execute(method);
}
public void searchClicked(View view){
Toast.makeText(MainActivity.this,"Search Clicked",Toast.LENGTH_SHORT).show();
}
//Registers the receiver whenever this acitivty is currently being shown or about to.
@Override
public void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this)
.registerReceiver(apiListener, new IntentFilter("StationsAPI")); //This is the intent filter this receiver will be listening for
}
//This stops the receiver from listening when the activity is no longer shown.
@Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(this).unregisterReceiver(apiListener);
}
}
我做了一些改动,并用一些评论来描述它们。这里要注意的最重要的事情是这个Activity不再是一个监听器,因为我已经替换了LocalBroadcastManager
的功能。使用它,我可以注册尽可能多的BroadcastReceiver
对象,因为我希望处理AsyncTask的响应,而不必担心会中断AsyncTask的进程。
如您所见,我使用IntentFilter
让经理知道只有这个动作的意图(“StationsAPI”)应该转到我注册的接收者(apiListener
)。此外,所以我没有可能泄漏活动的情况,一旦活动不再可见,我就取消注册接收器,并在再次看到活动时重新注册。
<强> GetStationsAPICall.java 强>
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
/**
* Created by Nisal on 13-Sep-17.
*/
public class GetStationsAPICall extends AsyncTask<String, Void, String> {
LocalBroadcastManager localBroadcastManager; //This is the manager to send a result back to your activity
GetStationsAPICall(Context ctx){
localBroadcastManager = LocalBroadcastManager.getInstance(ctx); //No matter where you call this, it is the same object throughout your app.
}
@Override
protected String doInBackground(String... params) {
String method = params[0];
if(method.equals("getStations")){
try {
HttpClient client = new DefaultHttpClient();
String getURL = "http://api.gate.com/?lang=en";
HttpGet httpGet = new HttpGet(getURL);
httpGet .setHeader("Authorization", "Bearer 690");
HttpResponse response = client.execute(httpGet);
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
//parse response.
String responseString = EntityUtils.toString(resEntity);
Log.e("Response", responseString;
return responseString; //This will be the parameter of your onPostExecute method
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(String obj) {
localBroadcastManager
.sendBroadcast( //Sending the intent with the response!
new Intent("StationsAPI") //Remember that IntentFilter? Here is where you declare where to send intent.
.putExtra("API_Response", obj)); //This is the extra data you want to send to your receivers.
}
}
与上面的MainActivity
类一样,我已经根据我所做的更改对这些部分进行了评论。 JSONObject
类不是可分区的,所以不是创建它然后将其重新转换为我可以放在Intent
内的东西,而是将其保留为String
对象,并返回doInBackground
方法中的值。
现在,只要您拨打GetStationsAPICall
任务,就应该在MainActivity
(或任何其他IntentFilter
为“API_Response”的接收方)中收到回复。虽然这个解决方案本身并不完美(如果用户旋转设备怎么办?),它应该有助于避免Android提供的一些陷阱。
答案 1 :(得分:1)
您在执行之前再次重新创建GetStationsAPICall
对象。所以你的AsyncResponse
对象将为空。
更改您的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GetStationsAPICall getStations = new GetStationsAPICall(this);
getStations.execute(method);
}