Android:如何将JSON对象从AsncTask类传递到Main类

时间:2017-09-13 18:34:39

标签: java android json android-asynctask

我有一个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。我在这做错了什么?

2 个答案:

答案 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);
    }