-1

I'm trying to separate my AsyncTask class and MainActivity class by putting them in other files. Here is my fully-working program:

package com.example.kamilh.pierwsza;

import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Locale;


public class MainActivity extends ActionBarActivity {
    String region = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    private void getRegion()
    {
        TextView textView = (TextView) findViewById(R.id.textView3);
        Criteria cr = new Criteria();
        LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        Location loc = lm.getLastKnownLocation(lm.getBestProvider(cr, true));
        double lat = loc.getLatitude();
        double lon = loc.getLongitude();

        new Region().execute(lat, lon);
        textView.setText(region);
    }

    public void count(View view) throws IOException {
        EditText editText = (EditText) findViewById(R.id.editText);
        EditText editText2 = (EditText) findViewById(R.id.editText2);

        double cost = 5.25;
        double petrol = Double.valueOf(editText.getText().toString());
        double distance = Double.valueOf(editText2.getText().toString());

        double result = Math.round(cost*(distance/100)*petrol);
        //textView.setText("The cost of your trip is: "+String.valueOf(result)+" zł");

        getRegion();
    }

    private class Region extends AsyncTask<Double, Void, String> {

        @Override
        public String doInBackground(Double... params) {
            URL url = null;
            BufferedReader in = null;
            try {
                url = new URL("https://maps.googleapis.com/maps/api/geocode/json?latlng="+params[0]+","+params[1]);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            try {
                if (url != null) {
                    in = new BufferedReader(new InputStreamReader(url.openStream()));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            String line = null;
            String x = null;
            for (int i = 0; i<31; i++){
                if (in != null) {
                    try {
                        line = in.readLine();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return line;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            region = result;
        }
}

Now, I'd like to be able to clean up a bit my code, so I decided to separate those two classes. I saw this example (above) and I tried to implement this solution in my project, but i failed. Android: How to run asynctask from different class file?

Here are my MainActivity class:

package com.example.kamilh.pierwsza;

import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

import java.io.IOException;


public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    public void getRegion(String result)
    {
        TextView textView = (TextView) findViewById(R.id.textView3);
        textView.setText(result);
    }

    public void count(View view) throws IOException {
        EditText editText = (EditText) findViewById(R.id.editText);
        EditText editText2 = (EditText) findViewById(R.id.editText2);

        double cost = 5.25;
        double petrol = Double.valueOf(editText.getText().toString());
        double distance = Double.valueOf(editText2.getText().toString());

        double result = Math.round(cost*(distance/100)*petrol);
        //textView.setText("The cost of your trip is: "+String.valueOf(result)+" zł");

        Criteria cr = new Criteria();
        LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
        Location loc = lm.getLastKnownLocation(lm.getBestProvider(cr, true));
        double lat = loc.getLatitude();
        double lon = loc.getLongitude();

        new Region(this).execute(lat, lon);
    }
}

Here is my Region class:

package com.example.kamilh.pierwsza;

import android.content.Context;
import android.os.AsyncTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by KamilH on 2015-02-19.
 */
class Region extends AsyncTask<Double, Void, String> {
    private Context context;
    MainActivity activity;

    public Region (Context context){
        this.context = context;
    }

    @Override
    public String doInBackground(Double... params) {
        URL url = null;
        BufferedReader in = null;
        try {
            url = new URL("https://maps.googleapis.com/maps/api/geocode/json?latlng="+params[0]+","+params[1]);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        try {
            if (url != null) {
                in = new BufferedReader(new InputStreamReader(url.openStream()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        String line = null;
        String x = null;
        for (int i = 0; i<31; i++){
            if (in != null) {
                try {
                    line = in.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return line;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        activity.getRegion(result);
    }
}

After I run the app with separated files I get those errors:

02-19 14:42:39.793  13842-13842/com.example.kamilh.pierwsza E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.kamilh.pierwsza, PID: 13842
    java.lang.NullPointerException
            at com.example.kamilh.pierwsza.Region.onPostExecute(Region.java:57)
            at com.example.kamilh.pierwsza.Region.onPostExecute(Region.java:15)
            at android.os.AsyncTask.finish(AsyncTask.java:632)
            at android.os.AsyncTask.access$600(AsyncTask.java:177)
            at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5867)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:674)
            at dalvik.system.NativeStart.main(Native Method)

Could you please, tell me how to fix it?

Community
  • 1
  • 1
user3448282
  • 2,629
  • 3
  • 25
  • 47

4 Answers4

1

Change your Region class to this:

package com.example.kamilh.pierwsza;

import android.os.AsyncTask;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by KamilH on 2015-02-19.
 */
class Region extends AsyncTask<Double, Void, String> {
    private MainActivity activity;

    public Region (MainActivity activity){
        this.activity = activity;
    }

    @Override
    public String doInBackground(Double... params) {
        URL url = null;
        BufferedReader in = null;
        try {
            url = new URL("https://maps.googleapis.com/maps/api/geocode/json?latlng="+params[0]+","+params[1]);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        try {
            if (url != null) {
                in = new BufferedReader(new InputStreamReader(url.openStream()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        String line = null;
        String x = null;
        for (int i = 0; i<31; i++){
            if (in != null) {
                try {
                    line = in.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return line;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        activity.getRegion(result);
    }
}

Why? Well. You call getRegion on activity in the onPostExecute. But activity is never initialised. And since you want it to call that method in the MainActivity where you did new Region(this), the constructor has to be changed. Since you don't use the Context, we remove that and replace it by MainActivity and make sure it gives the value to the activity field in your class.

Note that an Activity is a subclass of Context. And that this in the activity is the activity and thus a context. Not that you need it here.

It could also be good to look into callback routines. It is what you're doing here, but it can be done by using an interface. And then re-using your code will be easier.

se_bastiaan
  • 1,716
  • 14
  • 19
0

You are not initializing activity in Region constructor, so activity is null when you try to call getRegion in asyncTask postExecute. You should init activity in Region constructor.

Álvaro Pérez Soria
  • 1,443
  • 1
  • 13
  • 26
0

Your activity is null

public Region (Context context, MainActivity act){
    this.context = context;
    this.activity = act;
}
Jonas
  • 88
  • 7
-2

You're getting NullPointerException, because your Region class does not find getRegion() method which is inside your MainActivity.

Provide the activity to the constructor of Region class.

Vamsi
  • 878
  • 1
  • 8
  • 25