I'm getting a null pointer exception on the line marked with /Here/ in my code. I've spent about 2 hours looking up the AssetManager and how to use it, etc, but still can't figure out why it's null. I've called getAssets() by itself, from the context and from the resources but still I'm getting null. Can anyone help me out here?
Thanks.
package com.hamc17.CatFacts;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;
public class FactsActivity extends Activity{
Context context;
Resources res;
#Override
public void onCreate(Bundle savedInstanceBundle){
super.onCreate(savedInstanceBundle);
context = getApplicationContext();
res = context.getResources();
Button getFactButton = (Button) findViewById(R.id.getFactButton);
getFactButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast toastMessageOnClick = new Toast(FactsActivity.this);
toastMessageOnClick.setText(getFact());
if((toastMessageOnClick.toString()).length()>50)
{
toastMessageOnClick.setDuration(10);
}
else
{
toastMessageOnClick.setDuration(Toast.LENGTH_LONG);
}
toastMessageOnClick.show();
}
});
}
String[] factArray = getFactsFromTextFile().split(";");
private String getFactsFromTextFile(){
/*Here*/ AssetManager assMan = context.getAssets();
try{
BufferedReader buff = new BufferedReader(new InputStreamReader(assMan.open("facts.txt")));
String line;
StringBuilder build = new StringBuilder();
while((line = buff.readLine()) != null)
{
build.append(line).append(System.getProperty("line.seperator"));
}
return build.toString();
}
catch (IOException e)
{
Toast toastMessage = new Toast(getApplicationContext());
toastMessage.setText(e.toString() + "\n Whoops, there was an error! ");
toastMessage.show();
return "";
}
finally
{
try{
assMan.close();
}
catch (Exception e)
{
//Whatever Trevor
}
}
}
private String getFact(){
String randomFactString = "";
int factCount = factArray.length;
Random rng = new Random();
int randomNum = rng.nextInt()*factCount;
randomFactString = factArray[randomNum];
return randomFactString;
}
}
You are missing setContentView(R.layout.mylayout);
#Override
public void onCreate(Bundle savedInstanceBundle){
super.onCreate(savedInstanceBundle);
setContentView(R.layout.mylayout);
Button getFactButton = (Button) findViewById(R.id.getFactButton);
findViewById looks for a resource with the id in the current inflated layout. So you should set the content of your layout to the activity before initializing views
Also you can use
res = getResources();
Instead of creating a local variable to get the Context of the Activity just use getBaseContext(); each time you want to get the reference to the Context.
So something like this instead:
AssetManager assMan = getBaseContext().getAssets();
Related
from this i'm getting latitude and longitude in a single textview. But I want the latitude to be in 1 textview and longitude in another text view. Please help me on this.
My main activity
package com.shopping.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button addressButton;
TextView addressTV;
TextView latLongTV;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addressTV = (TextView) findViewById(R.id.addressTV);
addressButton = (Button) findViewById(R.id.addressButton);
addressButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
EditText editText = (EditText) findViewById(R.id.addressET);
String address = editText.getText().toString();
GeocodingLocation locationAddress = new GeocodingLocation();
locationAddress.getAddressFromLocation(address,
getApplicationContext(), new GeocoderHandler());
}
});
}
private class GeocoderHandler extends Handler {
#Override
public void handleMessage(Message message) {
String locationAddress;
switch (message.what) {
case 1:
Bundle bundle = message.getData();
locationAddress = bundle.getString("address");
break;
default:
locationAddress = null;
}
latLongTV.setText(locationAddress);
}
}
}
my geocodinglocation class.java
package com.shopping.myapplication;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
public class GeocodingLocation {
private static final String TAG = "GeocodingLocation";
public static void getAddressFromLocation(final String locationAddress,
final Context context, final Handler handler) {
Thread thread = new Thread() {
#Override
public void run() {
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
String result = null;
try {
List
addressList = geocoder.getFromLocationName(locationAddress, 1);
if (addressList != null && addressList.size() > 0) {
Address address = (Address) addressList.get(0);
StringBuilder sb = new StringBuilder();
sb.append(address.getLatitude()).append("\n");
sb.append(address.getLongitude()).append("\n");
result = sb.toString();
}
} catch (IOException e) {
Log.e(TAG, "Unable to connect to Geocoder", e);
} finally {
Message message = Message.obtain();
message.setTarget(handler);
if (result != null) {
message.what = 1;
Bundle bundle = new Bundle();
result = "Address: " + locationAddress +
"\n\nLatitude and Longitude :\n" + result;
bundle.putString("address", result);
message.setData(bundle);
} else {
message.what = 1;
Bundle bundle = new Bundle();
result = "Address: " + locationAddress +
"\n Unable to get Latitude and Longitude for this address location.";
bundle.putString("address", result);
message.setData(bundle);
}
message.sendToTarget();
}
}
};
thread.start();
}
}
from this i'm getting latitude and longitude in a single textview. But I want the latitude to be in 1 textview and longitude in another text view. Please help me on this.
Please correct me if I'm wrong, but it appears that you are getting lat long as a single string for the address. Inside run() method for the thread, there are these lines:
sb.append(address.getLatitude()).append("\n");
sb.append(address.getLongitude()).append("\n");
result = sb.toString();
As you can see, you can get latitued and longitude from the address object here directly! There are many ways you can go about this. You can stick the lat and long values into the bundle if you wish. According to documentation, getLatitude() and getLongitude() return double:
public double getLatitude()
You could try putting the values independantly into the bundle, and give them appropriate keys. Or, if you don't want to mess with the geo code, you could in onCreate() method simply do:
String address = editText.getText().toString();
String[] values = address.split("\\n"); //we know that we need to split by \\n because we did sb.append(address.getLatitude()).append("\n")
//N.b: make sure to include \\n double backslash!
String lat = values[0];
String long = values[1];
Hope this helps! Please let me know if this works :D
EDIT: I have tried implementing it myself and it seems to work no problem! Here is a screenshot:
Here is main activity:
import androidx.appcompat.app.AppCompatActivity;
import android.location.Address;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button addressButton;
TextView addressTV;
TextView latTV;
TextView longTV;
EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addressTV = findViewById(R.id.addressTV);
latTV = findViewById(R.id.latTV);
longTV = findViewById(R.id.longTV);
addressButton = findViewById(R.id.addressButton);
editText = (EditText) findViewById(R.id.addressET);
addressButton.setOnClickListener(arg0 -> {
String address = editText.getText().toString();
GeocodingLocation locationAddress = new GeocodingLocation();
locationAddress.getAddressFromLocation(address,
getApplicationContext(), new GeocoderHandler());
});
}
private class GeocoderHandler extends Handler {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case 1:
Bundle bundle = message.getData();
Address address = bundle.getParcelable("address");
latTV.setText(address.getLatitude()+"");
longTV.setText(address.getLongitude()+"");
break;
case 2:
addressTV.setText("unable to get address");
}
}
}
}
Notes: I simplified some things here for you, but its essentially the same. Important point however is that you can stick Parcable objects directly into the bundle, and since Address objects are Parcable, you can put the Address object directly into the bundle!
Here is the geo coding location class:
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
public class GeocodingLocation {
private static final String TAG = "GeocodingLocation";
public static void getAddressFromLocation(final String locationAddress,
final Context context, final Handler handler) {
Thread thread = new Thread() {
#Override
public void run() {
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
Message message = Message.obtain();
message.setTarget(handler);
try {
List addressList = geocoder.getFromLocationName(locationAddress, 1);
if (addressList != null && addressList.size() > 0) {
Address address = (Address) addressList.get(0);
message.what = 1;
Bundle bundle = new Bundle();
bundle.putParcelable("address", address);
message.setData(bundle);
}
} catch (IOException e) {
Log.e(TAG, "IOException", e);
message.what = 2;
}
message.sendToTarget();
}
};
thread.start();
}
}
Note: here I simplified your code a little bit also. Personally (and I think most people will agree), I like to code in a way that uses least indentations, but is still interpretable. Instead of doing try catch finally I just placed the correct pieces of code in try and catch separately, so there is no longer the need for finally clause at all.
Before you had a message with address string, and in the catch clause you would put the string "unable to get address for location" into bundle with key "address":
Bundle bundle = new Bundle();
result = "Address: " + locationAddress +
"\n\nLatitude and Longitude :\n" + result;
bundle.putString("address", result);
The result string doesn't contain an address, but rather an error message, so its probably not a good idea to put it in bundle with "address" key (because its an error message). I did it slightly differently, I set message.what property to message.what = 2;, and made that a case in the switch inside the main activity.
I hope this helps you further! :D
Developing a program that reads text from a file and shows it in a dynamic layout.
However, if you execute the code below, the error as below appears.
Can I get a solution?
The code is as below.
ReadFile is a function that reads text from files in file paths received by a factor, and MakeLinearLayout shows some of the text it has read through a TextView in a dynamic layout.
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.applandeo.Tempus.R;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
#SuppressLint("SdCardPath")
public class FriendListActivity extends AppCompatActivity {
final static String FilePath= "/data/data/com.applandeo.materialcalendarsampleapp/files/friendList.txt";
LinearLayout lm;
public FriendListActivity(LinearLayout lm) {
this.lm = lm;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_friend_list);
Button addButton = findViewById(R.id.addButton);
addButton.setOnClickListener(v -> {
Intent intent = new Intent(this, AddFriendsActivity.class);
startActivity(intent);
});
lm = findViewById(R.id.ll);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
Toolbar.LayoutParams.WRAP_CONTENT, Toolbar.LayoutParams.WRAP_CONTENT);
MakeLinearLayout(lm);
}
public String ReadFile (String path){
StringBuffer strBuffer = new StringBuffer();
try {
InputStream is = new FileInputStream(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = "";
while ((line = reader.readLine()) != null) {
strBuffer.append(line+"\n");
}
reader.close();
is.close();
}
catch(Exception e){
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionAsStrting = sw.toString();
Log.e("Fileread", exceptionAsStrting);
e.printStackTrace();
Toast.makeText(this.getApplicationContext(), "Failed to read file.", Toast.LENGTH_SHORT).show();
return "";
}
return strBuffer.toString();
}
public void MakeLinearLayout (LinearLayout lm){
String read = ReadFile(FilePath);
String[] readArr = read.split("\\-");
if (readArr != null)
{
int nCnt = readArr.length;
// readArr[0+5n]: phone number, readArr[1+5n]: registration name, readArr [2+5n]: email, readArr[3+5n]: group name, readArr[4+5n]: note
for (int i=0; i<nCnt; ++i)
{
Log.i("ARRTAG", "arr[" + i + "] = " + readArr[i]);
}
for(int n=0; ;n++){
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
TextView InfoView = new TextView(this);
InfoView.setText(" " + read);
//InfoView.setText(" " + readArr[5*n+1] + " " + readArr[5*n+3]);
ll.addView(InfoView);
lm.addView(ll);
}
}
else{
Toast.makeText(this.getApplicationContext(), "No acquaintances have been added.", Toast.LENGTH_SHORT).show();
}
}
}
The second error occurred after reflecting the contents of the comment.
Remove below constructor from your activity code. There is no way you can pass parameters to constructor of your activity
public FriendListActivity(LinearLayout lm) {
this.lm = lm;
}
I am working on a project. My program shows a video by videoview and get values from an excel file. I am having difficulty in showing the values one by one. I am trying to use some delay methods. I have used Thread.sleep and SystemClock.sleep methods but they freeze the entire app and phone. Now I am trying to use handler method. I don't receive any error but there is no delay. I am putting my code below.
If anyone can help me with this delay, I will be very happy.
package com.example.exceldeneme;
import androidx.appcompat.app.AppCompatActivity;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.MediaController;
import android.widget.VideoView;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.lang.String;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.List;
public class MainActivity<number_cars> extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
VideoView videoView = findViewById(R.id.video_view);
Button button = findViewById(R.id.button);
TextView text_cars = findViewById(R.id.textEmpty);
TextView text_total_lots = findViewById(R.id.textTotalLots);
readData();
int number_of_park = 100;
text_total_lots.setText(String.valueOf(number_of_park));
int counter = 0;
String videoPath = "android.resource://" + getPackageName() + "/" + R.raw.camera_out;
Uri uri = Uri.parse(videoPath);
videoView.setVideoURI(uri);
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
mediaController.setAnchorView(videoView);
for (String i : number_of_cars.get(0)){
counter = counter + 1 ;
}
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int counter = 0;
for (String i : number_of_cars.get(0)){
counter = counter + 1 ;
}
for (int i = 1; i < counter-1;i= i +1){
String count_park = number_of_cars.get(0)[i];
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
text_cars.setText(count_park);
}
}, 1000);
//SystemClock.sleep(1000); //ms
Log.d("Selam","SORUN YOK");
}
}
});
}
private ArrayList<String[]> number_of_cars = new ArrayList<String[]>();
private void readData() {
InputStream is = getResources().openRawResource(R.raw.numberofcars);
BufferedReader reader = new BufferedReader(
new InputStreamReader(is, Charset.forName("UTF-8"))
);
String line = "";
try {
while(((line = reader.readLine()) != null)) {
String[] tokens = line.split(",");
number_of_cars.add(tokens);
Log.d("MyActivity","Just created"+ Arrays.toString(tokens));
}
}
catch (IOException e) {
Log.wtf("MyActivity","Error reading data file on line" + line, e);
e.printStackTrace();
}
}
}
for the isolated issue you probably want :
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
text_cars.setText(count_park);
}
}, 1000 * i);
But you should really have a single instance Handler and post all Runnable objects to it, with a way to remove all pending Runnable, if any when ui is destroyed using : Handler::removeCallbacksAnMessages(null) in the relevant hook method like onDestroy.
What I want to achieve is the following:
In my view, I have 4 TextViews that should show the amount of items in the connected databases. This is done using a simple php script.
The problem I have is that I get all the correct values from the database, but when I try to set those values to my TextViews, the app crashes.
I have tried to look if using to many Asynctasks could be a problem, but when I decide to comment out the only line inside the SetTextForTextView() function, it all works like a charm and all the expected values are printed to my log. So with that being said, I dont think using multiple Asynctasks at the same time is the problem here, but I have really no idea what is.
Something that might be worth mentioning is when I comment out the following bit like this, the app doesn't crash...
shoesAmount = (TextView) findViewById(R.id.menuTvShoesAmount);
DatabaseTask taskA = new DatabaseTask(shoesAmount);
taskA.execute("getAmount", "shoes");
// tshirtsAmounts = (TextView) findViewById(R.id.menuTvTshirtsAmount);
// DatabaseTask taskB = new DatabaseTask(tshirtsAmounts);
// taskB.execute("getAmount", "tshirts");
//
// jeansAmount = (TextView) findViewById(R.id.menuTvJeansAmount);
// DatabaseTask taskC = new DatabaseTask(jeansAmount);
// taskC.execute("getAmount", "jeans");
//
// blousesAmount = (TextView) findViewById(R.id.menuTvBlousesAmount);
// DatabaseTask taskD = new DatabaseTask(blousesAmount);
// taskD.execute("getAmount", "blouses");
But then again with any other combination for example like this one, and the app crashes again...
// shoesAmount = (TextView) findViewById(R.id.menuTvShoesAmount);
// DatabaseTask taskA = new DatabaseTask(shoesAmount);
// taskA.execute("getAmount", "shoes");
//
tshirtsAmounts = (TextView) findViewById(R.id.menuTvTshirtsAmount);
DatabaseTask taskB = new DatabaseTask(tshirtsAmounts);
taskB.execute("getAmount", "tshirts");
//
// jeansAmount = (TextView) findViewById(R.id.menuTvJeansAmount);
// DatabaseTask taskC = new DatabaseTask(jeansAmount);
// taskC.execute("getAmount", "jeans");
//
// blousesAmount = (TextView) findViewById(R.id.menuTvBlousesAmount);
// DatabaseTask taskD = new DatabaseTask(blousesAmount);
// taskD.execute("getAmount", "blouses");
Does anyone can point me out into the direction where I might be going wrong?
Thanks!
(here is the full code)
package ishopper.theindiestudio.com.appname;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
public class Menu extends AppCompatActivity {
private ImageButton btnHelp, btnAccount, newest1, newest2, newest3;
private TextView shoesAmount, tshirtsAmounts, jeansAmount, blousesAmount;
private Button browseShoes, browseTshirts, browseJeans, browseBlouses;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
context = this;
btnHelp = (ImageButton) findViewById(R.id.menuBtnHelp);
btnAccount = (ImageButton) findViewById(R.id.menuBtnAccount);
btnAccount.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onAccountOptions();
}
});
btnHelp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onHelp();
}
});
newest1 = (ImageButton) findViewById(R.id.menuIbNewest1);
newest2 = (ImageButton) findViewById(R.id.menuIbNewest2);
newest3 = (ImageButton) findViewById(R.id.menuIbNewest3);
//set newest items
shoesAmount = (TextView) findViewById(R.id.menuTvShoesAmount);
DatabaseTask taskA = new DatabaseTask(shoesAmount);
taskA.execute("getAmount", "shoes");
tshirtsAmounts = (TextView) findViewById(R.id.menuTvTshirtsAmount);
DatabaseTask taskB = new DatabaseTask(tshirtsAmounts);
taskB.execute("getAmount", "tshirts");
jeansAmount = (TextView) findViewById(R.id.menuTvJeansAmount);
DatabaseTask taskC = new DatabaseTask(jeansAmount);
taskC.execute("getAmount", "jeans");
blousesAmount = (TextView) findViewById(R.id.menuTvBlousesAmount);
DatabaseTask taskD = new DatabaseTask(blousesAmount);
taskD.execute("getAmount", "blouses");
}
public void SetTextForTextView(TextView textview, String result){
textview.setText(result);
}
public void onAccountOptions () {
Intent i = new Intent(this, AccountDetailsActivity.class);
startActivity(i);
}
public void onHelp () {
}
public void onBackPressed() {
//disabled back button
}
private class DatabaseTask extends AsyncTask<String, Void, String> {
private String taskType;
private String productType;
private TextView textView;
private ImageButton imageButton;
DatabaseTask (TextView mTextView){textView = mTextView;}
#Override
protected String doInBackground(String... params) {
String task = params[0];
if (task.equals("getAmount")) {
Log.e("doInBg", "getAmount");
String login_url = "http://url.eu/directory/script.php";
String tProductType = params[1];
try {
URL url = new URL(login_url);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
OutputStream outputStream = httpURLConnection.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "UTF-8"));
String postData = URLEncoder.encode("producttable", "UTF-8") + "=" + URLEncoder.encode(tProductType, "UTF-8");
bufferedWriter.write(postData);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"));
String result = "";
String line = "";
while ((line = bufferedReader.readLine()) != null) {
result += line;
Log.e("doInBgResult", result.toString());
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
Menu activity = (Menu) context;
activity.SetTextForTextView(textView, result.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}
}
The AsyncTask's doInBackground() runs in another thread and you can't change the UI from another thread, Only the main one. I suggest you do the same job in onPostExecute() after you finish your long job. Return the String result you want to use to the main thread
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
// no need for that
//Menu activity = (Menu) context;
//activity.SetTextForTextView(textView, result.toString());
reutrn result;
then update the text
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(result != null){
SetTextForTextView(textView, result);
}
}
I suggest reading more about it from here and here
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?
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.
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.
Your activity is null
public Region (Context context, MainActivity act){
this.context = context;
this.activity = act;
}
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.