I previously wrote a simple currency converter program, that fetches real time rate conversion via an exchange rate API. The full code is available here: https://github.com/LaChope/expenses-robot
I want know to reuse most of this code to build an Android app, but I am really not familiar with AsyncTask and do know how to implement it (I need it for the GET requests).
Here is what I've implemented so far, but I am not sure it is the correct way to proceed.
My Converter class:
public class Converter extends AsyncTask<Void, Void, Float> {
private final RestTemplate restTemplate = new RestTemplate();
private final EditText baseCurrency;
private final EditText targetCurrency;
private final EditText amount;
public Converter(EditText baseCurrency, EditText targetCurrency, EditText amount) {
this.baseCurrency = baseCurrency;
this.targetCurrency = targetCurrency;
this.amount = amount;
}
#Override
protected Float doInBackground(Void... voids) {
String url = "https://api.exchangeratesapi.io/latest?" + baseCurrency;
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
ObjectMapper mapper = new ObjectMapper();
JsonNode root = null;
try {
root = mapper.readTree(responseEntity.getBody());
} catch (IOException e) {
e.printStackTrace();
}
String rates1 = "rates";
JsonNode name = root.get(rates1);
JsonNode rates = name.get(String.valueOf(targetCurrency));
float rate = rates.floatValue();
return rate;
}
#Override
protected void onPostExecute(Float rate) {
super.onPostExecute(rate);
output.setText();
return;
}
}
My MainActivity class:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void displayResult(View view) {
EditText textBaseCurrency = (EditText) findViewById(R.id.base_currency);
EditText textTargetCurrency = (EditText) findViewById(R.id.target_currency);
EditText textAmount = (EditText) findViewById(R.id.amount);
TextView output = (TextView) findViewById(R.id.result);
output.setInputType(InputType.TYPE_CLASS_NUMBER);
Converter converter = new Converter(textBaseCurrency, textTargetCurrency, textAmount);
output.setText();
}
}
How to communicate the output of my conversion made in the Converter class to the MainActivity to display it?
Initialize AsyncTask as
Converter converter = new Converter(textBaseCurrency, textTargetCurrency, textAmount);
converter.execute();
Then the code in AsyncTask will start executing.
Assign output.setText(); in onPostExecute(Float rate) {}.
Related
This is NetworkUtils.class
public class NetworkUtils {
final static String GITHUB_BASE_URL =
"https://api.github.com/search/repositories";
final static String PARAM_QUERY = "q";
final static String PARAM_SORT = "sort";
final static String sortBy = "stars";
public static URL buildUrl(String githubSearchQuery) {
Uri builtUri = Uri.parse(GITHUB_BASE_URL).buildUpon()
.appendQueryParameter(PARAM_QUERY, githubSearchQuery)
.appendQueryParameter(PARAM_SORT, sortBy)
.build();
URL url = null;
try {
url = new URL(builtUri.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
return url;
}
This is MainActivity.class
public class MainActivity extends AppCompatActivity {
private EditText mSearchBoxEditText;
private TextView mUrlDisplayTextView;
private TextView mSearchResultsTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSearchBoxEditText = (EditText) findViewById(R.id.et_search_box);
mUrlDisplayTextView = (TextView) findViewById(R.id.tv_url_display);
mSearchResultsTextView = (TextView) findViewById(R.id.tv_github_search_results_json);
}
private void makeGithubSearchQuery() {
String githubQuery = mSearchBoxEditText.getText().toString();
URL githubSearchUrl = NetworkUtils.buildUrl(githubQuery)
mUrlDisplayTextView.setText(githubSearchUrl.toString());
String githubSearchResults = null;
try {
githubSearchResults = NetworkUtils.getResponseFromHttpUrl(githubSearchUrl);
mSearchResultsTextView.setText(githubSearchResults);
} catch (IOException e) {
e.printStackTrace();
}
// TODO (4) Create a new GithubQueryTask and call its execute method, passing in the url to query
}
Notice that MainActivity.class uses this code.
URL githubSearchUrl = NetworkUtils.buildUrl(githubQuery)
and the NetworkUtils.class uses this code.
public static URL buildUrl(String githubSearchQuery)
I do believe that
NetworkUtils.buildUrl(githubQuery) is referring to buildUrl(String githubSearchQuery) and it is really confusing. I understand that the value of githubQuery will be the input from mSearchBoxEditText.getText().toString();, and now I'm wondering what would be the value of String githubSearchQuery, where would it come from??
2 Java Class Using Same Method With Differences
Actually the title itself is a huge mistake.
They are not same method with differences. The one you can find in NetworkUtils is the actual definition of the method. In MainActivity, You are just invoking it.
When you calls a method, the the control goes to the definition. Also a copy of arguments are passed to it(Note that in case of objects, a copy of the reference is passed, not a copy of the actual object. So any change affects in both sides). From the definition part, you can access it with a the new name.
but isnt that githubQuery is in private class?
It is not private. It is a local, means it has lesser scope than private. However, it isn't going to be a problem as long as you have a reference.
The value of githubSearchQuery will be the same as githubQuery as its being used to call buildUrl(String githubSearchQuery) method.
I am trying to get Json response from the server and pass it in intent as an arraylist to the next activity. This worked fine with volley but i am unable to get response via retrofit. Here is my code.
public class MainActivity extends AppCompatActivity {
public static final String ROOT_URL = "http://#####.####/";
String username;
String password;
private Button makerequest;
private ProgressDialog pdialog;
private EditText edittextusername;
private EditText edittextpassword;
private String DataArray[] = new String[15];
private ArrayList<Result> dataarr = new ArrayList<>();
int i=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
makerequest = (Button) findViewById(R.id.btnObjRequest);
edittextpassword = (EditText) findViewById(R.id.editpassword);
edittextusername = (EditText) findViewById(R.id.editusername);
pdialog = new ProgressDialog(this);
pdialog.setMessage("wait kar be...");
pdialog.setCancelable(false);
makerequest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
makejsonobjectrequest();
}
});
}
private void makejsonobjectrequest(){
username = edittextusername.getText().toString().trim();
password = edittextpassword.getText().toString().trim();
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ROOT_URL)
.build();
//creating object of our interface
DataApi data = adapter.create(DataApi.class);
//defining the method.
data.getposition(username, password, new Callback<ArrayList<Result>>() {
#Override
public void success(ArrayList<Result> list, Response response) {
dataarr= list;
Bundle b = new Bundle();
b.putSerializable("array", dataarr);
Intent intent = new Intent(getBaseContext(), Display.class);
intent.putExtras(b);
startActivity(intent);
}
#Override
public void failure(RetrofitError error) {
Toast.makeText(getBaseContext(), error.toString(),Toast.LENGTH_SHORT).show();
}
});
}
}
Follow this link you will get json response using retrofit library http://www.androidhive.info/2016/05/android-working-with-retrofit-http-library/
Usually this kind of error comes when the response you expect doesn't come from Server.
i think you should first check your the response which comes from server is in correct format so that your application can parse it correctly.
if you are using android studio you can see the request you are sending and the Url used for that request in android monitor after sending the request , try to use an application like https://www.getpostman.com/ to send your request and see if you get correct response from Server.
hope this helps.
So i'm trying to call a string, the call:
EditText EditTextSearch = (EditText)findViewById(R.id.editText1);
if(!isEmpty(EditTextSearch)){
Toast.makeText(this, "Getting Information", Toast.LENGTH_LONG).show();
Log.v("checkText =>", EditTextSearch.getText().toString());
getComics getComicInfo = new getComics(EditTextSearch.getText().toString(), 1);
getComicInfo.execute();
}
after that i'm calling asynctask
class getComics extends AsyncTask<Void, Void, Void>{
private String comicName;
private String comicNameForSearch;
private int getOptionNumber;
String jsonString = "";
String result = "";
getComics(String comicName, int getOptionNumber)
{
Log.v("Check name A =>", comicName); //show name
}
//set option for search
public void SetOptionNumber(int getOptionNumber){
this.getOptionNumber = getOptionNumber;
}
public int getOptionNumber(){
return this.getOptionNumber;
}
//the data that the user searching for
public void SetComicName(String comicName){
this.comicName = comicName;
}
public String GetComicName(){
return this.comicName;
}
/*the request to the API, include fixing space and getting information about the main object, data, later on i'll call
the object I got to show the the results array */
#Override
protected Void doInBackground(Void... params) {
Log.v("is callingB =>", "Yes");
comicNameForSearch = GetComicName();
Log.v("check name=>", comicNameForSearch ); // make the app crash
anyway, if i'm trying to Log.v, the app crash, what make me think that the DoInBackground doesn't recive the comicName for some reason, guess it because of the execute way, any ideas?
edit: first time going with API so sorry if any dumb problems
the error message:Caused by: java.lang.nullPointerException: println needs a message
You are missing Assinging the value in Constructor so which results in a NullPointerException
Change this
getComics(String comicName, int getOptionNumber)
{
Log.v("Check name A =>", comicName); //show name
}
into
getComics(String comicName, int getOptionNumber)
{
this.comicName = comicName;
this.getOptionNumber = getOptionNumber;
Log.v("Check name A =>", comicName); //show name
}
Your app is getting exception because your data in Asynctask is null which you are printing and passing in doInBackground.
Change you Asynctask to this:
class getComics extends AsyncTask<Void, Void, Void>{
private String comicName;
private String comicNameForSearch;
private int getOptionNumber;
String jsonString = "";
String result = "";
getComics(String comicName, int getOptionNumber)
{
this.comicName = comicName;
this.getOptionNumber = getOptionNumber;
Log.v("Check name A =>", comicName); //show name
}
//set option for search
public void SetOptionNumber(int getOptionNumber){
this.getOptionNumber = getOptionNumber;
}
public int getOptionNumber(){
return this.getOptionNumber;
}
//the data that the user searching for
public void SetComicName(String comicName){
this.comicName = comicName;
}
public String GetComicName(){
return this.comicName;
}
/*the request to the API, include fixing space and getting information about the main object, data, later on i'll call
the object I got to show the the results array */
#Override
protected Void doInBackground(Void... params) {
Log.v("is callingB =>", "Yes");
comicNameForSearch = GetComicName();
Log.v("check name=>", comicNameForSearch ); // make the app crash
And Another way is by calling the setter method you have made inside your class like this:
getComics getComicInfo = new getComics(EditTextSearch.getText().toString(), 1);
getComicInfo .SetComicName(EditTextSearch.getText().toString());
getComicInfo .SetOptionNumber(1);
getComicInfo.execute();
I tried to add button dinamically inside async task (i've choose to send view and context to async task constructor) but not works.
can you help me?
here is the code:
on create void i have this
View content = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
GetTokenRequest getToken = new GetTokenRequest(this.getApplicationContext(),content );
String[] params = new String[]{"","","http://"};
getToken.execute(params);
then i've create async task:
public static final class GetTokenRequest extends AsyncTask<String, Void, String> {
private Context context;
private View view;
public GetTokenRequest(Context ctx, View vw) {
context = ctx;
view=vw;
}
#Override
protected String doInBackground(String... params) {
String Username = params[0];
String PassWord = params[1];
String URL = params[2];
String data = sendHttpPostRequest(Username, PassWord,URL);
return data;
}
#Override
protected void onPostExecute(String result) {
if (result !=null){
try {
JSONObject jsonObj = new JSONObject(result);
// Getting JSON Array node
TokenList = jsonObj.getJSONArray(TAG_tokenlist);
// looping through All Contacts
for (int i = 0; i < TokenList.length(); i++) {
JSONObject c = TokenList.getJSONObject(i);
String deviceporttoken = c.getString("a");
String PortName = c.getString("b");
String IMageUrl = c.getString("c");
ImageButton imgToken=new ImageButton(context);
final RelativeLayout.LayoutParams paramsimgToken = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
paramsimgToken.addRule(RelativeLayout.ALIGN_LEFT);
paramsimgToken.addRule(RelativeLayout.CENTER_VERTICAL);
paramsimgToken.width=100;
paramsimgToken.width=50;
imgToken.setId(i);
imgToken.setLayoutParams(paramsimgToken);
imgToken.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
}
});
View rootView = ((Activity)context).getWindow().getDecorView().findViewById(android.R.id.content);
linearLayout1= (LinearLayout) rootView.findViewById(R.id.linearLayout1);
linearLayout1.addView(imgToken);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
//parsing json
}
}}
the problem is that linearLayout1.addView(imgToken); get null point exception.
thank you in advance.
Is your AsyncTask an inner class?
Because, if you write the AsyncTask class as inner class of your activity, you can easily acces the views of you activity in onPostExecute.
Just declare your LinearLayout as global value of the activity, call 'findById' in the onCreate of your activity and you're good to go.
Now in the onPostExecute, just call myLinearLayout.addView
Let me know if it worked :)
I have a JSON file which is populated to an activity (Main.java).
This Activity shows 3 random images from the URL on my JSON entries.
What I wanna do is: I have 13 different entries on the my JSON, whenever I click the shown random picture it goes to another activity (ProjectDetail.java) containing the picture,title,and description depends on the item I click based on its entry on the JSON.
What do I have in is by using extra by I dont know exactly how to perform that since I'm using JSON. What should I add into my top_listener method on my Main class and what should I add into my ProjectDetail class?
Thank you.
Main.java
public class Main extends Activity {
/** Called when the activity is first created. */
ArrayList<Project> prjcts=null;
private ImageThreadLoader imageLoader = new ImageThreadLoader();
private final static String TAG = "MediaItemAdapter";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
prjcts = new ArrayList<Project>();
WebService webService = new WebService("http://liebenwald.spendino.net/admanager/dev/android/projects.json");
Map<String, String> params = new HashMap<String, String>();
params.put("var", "");
String response = webService.webGet("", params);
try
{
Type collectionType = new TypeToken<ArrayList<Project>>(){}.getType();
List<Project> lst= new Gson().fromJson(response, collectionType);
for(Project l : lst)
{
prjcts.add(l);
ConstantData.projectsList.add(l);
}
}
catch(Exception e)
{
Log.d("Error: ", e.getMessage());
}
final Button project = (Button) findViewById(R.id.btn_projectslist);
final Button infos = (Button) findViewById(R.id.btn_infos);
final Button contact = (Button) findViewById(R.id.btn_contact);
project.setOnClickListener(project_listener);
infos.setOnClickListener(infos_listener);
contact.setOnClickListener(contact_listener);
ImageView image1;
ImageView image2;
ImageView image3;
try {
image1 = (ImageView)findViewById(R.id.top1);
image2 = (ImageView)findViewById(R.id.top2);
image3 = (ImageView)findViewById(R.id.top3);
} catch( ClassCastException e ) {
Log.e(TAG, "Your layout must provide an image and a text view with ID's icon and text.", e);
throw e;
}
Bitmap cachedImage1 = null;
Bitmap cachedImage2 = null;
Bitmap cachedImage3 = null;
//randomize the index of image entry
int max = prjcts.size();
List<Integer> indices = new ArrayList<Integer>(max);
for(int c = 0; c < max; ++c)
{
indices.add(c);
}
int arrIndex = (int)((double)indices.size() * Math.random());
int randomIndex1 = indices.get(arrIndex);
indices.remove(arrIndex);
int randomIndex2 = indices.get(arrIndex);
indices.remove(arrIndex);
int randomIndex3 = indices.get(arrIndex);
indices.remove(arrIndex);
setImage(cachedImage1, image1, prjcts.get(randomIndex1));
setImage(cachedImage2, image2, prjcts.get(randomIndex2));
setImage(cachedImage3, image3, prjcts.get(randomIndex3));
image1.setOnClickListener(top_listener);
image2.setOnClickListener(top_listener);
image3.setOnClickListener(top_listener);
}
public void setImage(Bitmap cachedImage, final ImageView image, Project pro)
{
//Bitmap cachedImage1 = null;
try {
cachedImage = imageLoader.loadImage(pro.smallImageUrl, new ImageLoadedListener()
{
public void imageLoaded(Bitmap imageBitmap)
{
image.setImageBitmap(imageBitmap);
//notifyDataSetChanged();
}
});
} catch (MalformedURLException e) {
Log.e(TAG, "Bad remote image URL: " + pro.smallImageUrl, e);
}
if( cachedImage != null ) {
image.setImageBitmap(cachedImage);
}
}
private OnClickListener top_listener = new OnClickListener() {
public void onClick(View v) {
Intent top = new Intent(Main.this, InfosActivity.class);
startActivity(top);
}
};
ProjectDetail.java
public class ProjectDetail extends Activity implements OnClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.project);
Button weitersagen = (Button) findViewById(R.id.btn_weitersagen);
weitersagen.setOnClickListener(this);
Button sms = (Button) findViewById(R.id.btn_sms_spenden);
sms.setOnClickListener(this);
int position = getIntent().getExtras().getInt("spendino.de.ProjectDetail.position");
Project project = ConstantData.projectsList.get(position);
try {
ImageView projectImage = (ImageView)findViewById(R.id.project_image);
Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(project.bigImageUrl).getContent());
projectImage.setImageBitmap(bitmap);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
TextView project_title = (TextView)findViewById(R.id.txt_project_title);
project_title.setText(project.project_title);
TextView organization_title = (TextView)findViewById(R.id.txt_organization_title);
organization_title.setText(Html.fromHtml("von " +project.organization_title));
TextView project_description = (TextView)findViewById(R.id.txt_project_description);
project_description.setText(Html.fromHtml(project.project_description));
}
I also have this ConstantData.java, the index which holds my JSON properties:
public class ConstantData{
public static String project_title = "project title";
public static String organization_title = "organization title";
public static String keyword = "keyword";
public static String short_code = "short code";
public static String project_description = "description";
public static String smallImageUrl = "smallImageUrl";
public static String bigImageUrl = "bigImageUrl";
public static String price= "price";
public static String country= "country";
public static ArrayList<Project> projectsList = new ArrayList<Project>();
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(project_title);
out.writeString(organization_title);
out.writeString(keyword);
out.writeString(short_code);
out.writeString(project_description);
out.writeString(smallImageUrl);
out.writeString(bigImageUrl);
out.writeString(price);
out.writeString(country);
}
public static final Parcelable.Creator<ConstantData> CREATOR
= new Parcelable.Creator<ConstantData>() {
public ConstantData createFromParcel(Parcel in) {
return new ConstantData(in);
}
public ConstantData[] newArray(int size) {
return new ConstantData[size];
}
};
private ConstantData(Parcel in) {
project_title = in.readString();
organization_title = in.readString();
keyword = in.readString();
short_code = in.readString();
project_description = in.readString();
smallImageUrl = in.readString();
bigImageUrl = in.readString();
price = in.readString();
country = in.readString();
}
}
You could make the class ConstantData serializable by extending from Parcelable and implementing a couple of methods (see the documentation). Then you could pass a constantData instance as an extra by doing
intent.putExtra("jsonData", constantDataInstance);
and retrieving it from the other activity (in it's onCreate() method) with
getIntent().getExtras().getParcelable("jsonData");
Otherwise you could just past as extra every field independently, but it would be a mess. This way is not only more easy to read and everything, but "well designed".
To pass information from one activity to another when you start the new one you do the following:
Intent top = new Intent(Main.this, InfosActivity.class);
Bundle b = new Bundle();
b.putString("key1", "value2");
b.putString("key2", "value2");
b.putString("key3", "value3");
top.putExtras(b);
startActivity(top);
Then in the newly started activity, in the onCreate() put the following:
Bundle b = getIntent().getExtras();
b.get("key1");
b.get("key2");
b.get("key3");
This will get the values from the previous activity by using the key you provided.
For more complex objects you should extend Parcelable (probably what you'll need) and then use:
b.putParcelable("Key4", yourParcelableObject);
And in your onCreate()
b.getParcelable("Key4");
I hope this helps.
Use gson to parse the json to Java. Then you can use Wagon to move the extras around with ease.
GSON:
https://github.com/google/gson
Wagon:
https://github.com/beplaya/Wagon