I have developed my first android application.
What that application does: I update mysql database with new results on the website and the android application fetches the same data from mysql. I am using JSON.
What i want it to do: I want it to notify user that the results have been updated. It can bee a timely notification or the normal one. It does not matter. I just want the user to know about it as soon as i update database.
Code for your reference:
1) Java code that displays results inside the application.
package in.thespl.spl.notifications;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.http.NameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
public class AllResultsActivity extends ListActivity {
// Progress Dialog
private ProgressDialog pDialog;
// Creating JSON Parser object
JSONParser jParser = new JSONParser();
ArrayList<HashMap<String, String>> productsList;
// url to get all products list
private static String url_all_products = "http://mydomain.in/fetchresult.php";
// JSON Node names
private static final String TAG_SUCCESS = "success";
private static final String TAG_PRODUCTS = "result";
private static final String TAG_PID = "rid";
private static final String TAG_NAME = "rname";
private static final String TAG_INFO = "rinfo";
// products JSONArray
JSONArray products = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.all_products);
// Hashmap for ListView
productsList = new ArrayList<HashMap<String, String>>();
// Loading products in Background Thread
new LoadAllProducts().execute();
// Get listview
ListView lv = getListView();
// on seleting single product
// launching Edit Product Screen
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String pid = ((TextView) view.findViewById(R.id.rid)).getText()
.toString();
// Starting new intent
Intent in = new Intent(getApplicationContext(),
AllResultsActivity.class);
// sending pid to next activity
in.putExtra(TAG_PID, pid);
// starting new activity and expecting some response back
startActivityForResult(in, 100);
}
});
}
// Response from Edit Product Activity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// if result code 100
if (resultCode == 100) {
// if result code 100 is received
// means user edited/deleted product
// reload this screen again
Intent intent = getIntent();
finish();
startActivity(intent);
}
}
/**
* Background Async Task to Load all product by making HTTP Request
* */
class LoadAllProducts extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(AllResultsActivity.this);
pDialog.setMessage("Loading results. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* getting All products from url
* */
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(url_all_products, "GET", params);
// Check your log cat for JSON reponse
Log.d("All Products: ", json.toString());
try {
// Checking for SUCCESS TAG
int success = json.getInt(TAG_SUCCESS);
if (success == 1) {
// products found
// Getting Array of Products
products = json.getJSONArray(TAG_PRODUCTS);
// looping through All Products
for (int i = 0; i < products.length(); i++) {
JSONObject c = products.getJSONObject(i);
// Storing each json item in variable
String id = c.getString(TAG_PID);
String name = c.getString(TAG_NAME);
String info = c.getString(TAG_INFO);
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
// adding each child node to HashMap key => value
map.put(TAG_PID, id);
map.put(TAG_NAME, name);
map.put(TAG_INFO, info);
// adding HashList to ArrayList
productsList.add(map);
}
} else {
// no products found
// Launch Add New product Activity
// Intent i = new Intent(getApplicationContext(),
// AllResultsActivity.class);
// Closing all previous activities
//i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// startActivity(i);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting all products
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
AllResultsActivity.this, productsList,
R.layout.list_item, new String[] { TAG_PID,
TAG_NAME, TAG_INFO },
new int[] { R.id.rid, R.id.rname, R.id.rinfo});
// updating listview
setListAdapter(adapter);
}
});
}
}
}
Any idea how to add a notification feature in this?
You have multiple ways to do that.
First way is to poll the server to ask for update.
This solution isn't really efficient and lot of params are had to choose:
Time to update-> will affect battery and reactivity.
Second way is to use Google Cloud Messaging. It provides a solution to push data from server to user. It's really simple to implement. (took me some hours).
Android documentation.
http://developer.android.com/guide/google/gcm/index.html
This second way optimizes battery and you could receive push even if your app is off.
Choose the way it's better for your needs.
Hope it helps you.
Related
I am learning networking from UDACITY, there I came across an app named Quake Report, I wanted to add Swipe to refresh feature in the app but I am not able to get the results I want.
package com.example.android.quakereport;
import android.app.LoaderManager;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class EarthquakeActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<Earthquake>> {
/**
* Constant value for the earthquake loader ID. We can choose any integer.
* This really only comes into play if you're using multiple loaders.
*/
private static final int EARTHQUAKE_LOADER_ID = 1;
// TextView that is displayed when the list is empty
private TextView mEmptyStateTextView;
// progress bar
private ProgressBar progressBar;
public static final String LOG_TAG = EarthquakeActivity.class.getName();
// URL for earthquake data from the USGS dataset
private static final String USGS_REQUEST_URL =
"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&orderby=time&minmag=5&limit=15";
/**
* Adapter for the list of earthquakes
*/
private EarthquakeAdapter mAdapter;
#Override
public Loader<List<Earthquake>> onCreateLoader(int id, Bundle args) {
Log.i(LOG_TAG, "Test: onCreateLoader() called...");
// Create a new loader for the given URL
return new EarthquakeLoader(this, USGS_REQUEST_URL);
}
#Override
public void onLoadFinished(Loader<List<Earthquake>> loader, List<Earthquake> data) {
Log.i(LOG_TAG, "Test: onLoadFinished() called...");
// Clear the adapter of previous earthquake data
mAdapter.clear();
// Hiding the progress bar as the results have been loaded
progressBar.setVisibility(View.GONE);
// Check if Internet Connection is present or not and show text accordingly
ConnectivityManager connManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
mEmptyStateTextView.setText(R.string.no_earthquakes);
} else {
mEmptyStateTextView.setText(R.string.no_internet_connection);
}
// If there is a valid list of {#link Earthquake}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (data != null && !data.isEmpty()) {
mAdapter.addAll(data);
}
}
#Override
public void onLoaderReset(Loader<List<Earthquake>> loader) {
Log.i(LOG_TAG, "Test: onLoaderReset() called...");
// Loader reset, so we can clear out our existing data.
mAdapter.clear();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(LOG_TAG, "Test: Earthquake Activity onCreate() called.");
super.onCreate(savedInstanceState);
setContentView(R.layout.earthquake_activity);
// Creating a swipe to refresh feature
final SwipeRefreshLayout pullToRefresh = findViewById(R.id.swipe_refresh);
pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
pullToRefresh.setRefreshing(false);
}
});
// Find a reference to the {#link ListView} in the layout
ListView earthquakeListView = (ListView) findViewById(R.id.list);
// Get a reference to the ConnectivityManager to check state of network connectivity
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
// Get details on the currently active default data network
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
// If there is a network connection, fetch data
if (networkInfo != null && networkInfo.isConnected()) {
// Get a reference to the LoaderManager, in order to interact with loaders.
LoaderManager loaderManager = getLoaderManager();
// Initialize the loader. Pass in the int ID constant defined above and pass in null for
// the bundle. Pass in this activity for the LoaderCallbacks parameter (which is valid
// because this activity implements the LoaderCallbacks interface).
// Create a new adapter that takes an empty list of earthquakes as input
Log.i(LOG_TAG, "Test: calling initLoader()...");
loaderManager.initLoader(EARTHQUAKE_LOADER_ID, null, this);
} else {
// Otherwise, display error
// First, hide loading indicator so error message will be visible
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
progressBar.setVisibility(View.GONE);
// Update empty state with no connection error message
mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
mEmptyStateTextView.setText(R.string.no_internet_connection);
}
mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
earthquakeListView.setEmptyView(mEmptyStateTextView);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
mAdapter = new EarthquakeAdapter(this, new ArrayList<Earthquake>());
// Set the adapter on the {#link ListView}
// so the list can be populated in the user interface
earthquakeListView.setAdapter(mAdapter);
// Set an item click listener on the ListView, which sends an intent to a web browser
// to open a website with more information about the selected earthquake.
earthquakeListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// Find the current earthquake that was clicked on
Earthquake currentEarthquake = mAdapter.getItem(position);
// Convert the String URL into a URI object (to pass into the Intent constructor)
Uri earthquakeUri = Uri.parse(currentEarthquake.getUrl());
// Create a new intent to view the earthquake URI
Intent websiteIntent = new Intent(Intent.ACTION_VIEW, earthquakeUri);
// Send the intent to launch a new activity
startActivity(websiteIntent);
}
});
// EarthquakeAsyncTask task = new EarthquakeAsyncTask();
// task.execute(USGS_REQUEST_URL);
}
/**
* {#link AsyncTask} to perform the network request on a background thread, and then
* update the UI with the list of earthquakes in the response.
* <p>
* AsyncTask has three generic parameters: the input type, a type used for progress updates, and
* an output type. Our task will take a String URL, and return an Earthquake. We won't do
* progress updates, so the second generic is just Void.
* <p>
* We'll only override two of the methods of AsyncTask: doInBackground() and onPostExecute().
* The doInBackground() method runs on a background thread, so it can run long-running code
* (like network activity), without interfering with the responsiveness of the app.
* Then onPostExecute() is passed the result of doInBackground() method, but runs on the
* UI thread, so it can use the produced data to update the UI.
*/
private class EarthquakeAsyncTask extends AsyncTask<String, Void, List<Earthquake>> {
/**
* This method runs on a background thread and performs the network request.
* We should not update the UI from a background thread, so we return a list of
* {#link Earthquake}s as the result.
*/
#Override
protected List<Earthquake> doInBackground(String... urls) {
// Don't perform the request if there are no URLs, or the first URL is null.
if (urls.length < 1 || urls[0] == null) {
return null;
}
List<Earthquake> result = QueryUtils.fetchEarthquakeData(urls[0]);
return result;
}
/**
* This method runs on the main UI thread after the background work has been
* completed. This method receives as input, the return value from the doInBackground()
* method. First we clear out the adapter, to get rid of earthquake data from a previous
* query to USGS. Then we update the adapter with the new list of earthquakes,
* which will trigger the ListView to re-populate its list items.
*/
#Override
protected void onPostExecute(List<Earthquake> data) {
// Clear the adapter of previous earthquake data
mAdapter.clear();
// If there is a valid list of {#link Earthquake}s, then add them to the adapter's
// data set. This will trigger the ListView to update.
if (data != null && !data.isEmpty()) {
mAdapter.addAll(data);
}
}
}
}
I want this app to get data from the given URL whenever the user swipes down, but I am not able to find a way to do it. Can anyone please help me with the code that is to be written in the following code block:
final SwipeRefreshLayout pullToRefresh = findViewById(R.id.swipe_refresh);
pullToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
pullToRefresh.setRefreshing(false);
}
});
call you methods which responsible for network call inside doRefresh method
I have a method in a library I am creating for a series of apps I am doing. This method will display an input dialog for the user to input a string entry. I am writing this project for android using android studio, and I am writing it in Java.
Here is the Logcat:
2020-11-17 00:44:23.819 6758-6758/com.phoenixhosman.launcher E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.phoenixhosman.launcher, PID: 6758
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
at android.content.ContextWrapper.getResources(ContextWrapper.java:91)
at android.view.ContextThemeWrapper.getResourcesInternal(ContextThemeWrapper.java:127)
at android.view.ContextThemeWrapper.getResources(ContextThemeWrapper.java:121)
at android.content.Context.getString(Context.java:594)
at com.phoenixhosman.phoenixlib.ActivityPhoenixLib.InputDialog(ActivityPhoenixLib.java:97)
at com.phoenixhosman.launcher.ActivityHome.onClick(ActivityHome.java:151)
at android.view.View.performClick(View.java:6603)
at android.view.View.performClickInternal(View.java:6576)
at android.view.View.access$3100(View.java:780)
at android.view.View$PerformClick.run(View.java:26090)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6714)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:503)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)
Here in my ActivityHome.java file:
/*
The Phoenix Hospitality Management System
Launcher App Source Code
Main Activity Code File
Copyright (c) 2020 By Troy Marker Enterprises
All Rights Under Copyright Reserved
The code in this file was created for use with the Phoenix Hospitality Management System (PHMS).
Use of this code outside the PHMS is strictly prohibited.
*/
package com.phoenixhosman.launcher;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.phoenixhosman.phoenixapi.*;
import com.phoenixhosman.phoenixlib.ProviderUser;
import com.phoenixhosman.phoenixlib.ActivityPhoenixLib;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.concurrent.atomic.AtomicInteger;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.phoenixhosman.phoenixapi.ManagerSecurityApi.*;
/**
* This activity display links to the other apps in the Phoenix Hospitality
* system, and use authentication to only show those that the user has
* permission to use.
* #author Troy L. Marker
* #version 1.0.0
* #since 0.5.0
*/
public class ActivityHome extends Activity implements View.OnClickListener
{
private String strCoName;
private String strApiUrl;
private String strLockPass;
private EditText etUsername;
private EditText etPassword;
final private static int REQUEST_CODE_1 = 1;
final ActivityPhoenixLib Phoenix = new ActivityPhoenixLib();
/**
* This method will create the activity, read content to display, and show the main activity screen
* Used when the activity is (re)created.
* #param savedInstanceState current saved instance state
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
setContentView(R.layout.activity_home);
etUsername = findViewById(R.id.etUsername);
etPassword = findViewById(R.id.etPassword);
TextView tvWarning = findViewById(R.id.tvWarning);
Button btnLogon = findViewById(R.id.btnLogon);
Button btnLockPass = findViewById(R.id.btnLockPass);
btnLogon.setOnClickListener(this);
btnLockPass.setOnClickListener(this);
#SuppressLint("Recycle") Cursor cursor = getContentResolver().query(Uri.parse("content://com.phoenixhosman.installer.ProviderSettings/settings"), null, null, null, null, null);
assert cursor != null;
if(cursor.moveToFirst()) {
while(!cursor.isAfterLast()) {
strCoName = cursor.getString(cursor.getColumnIndex("coname"));
strApiUrl = cursor.getString(cursor.getColumnIndex("apiurl"));
strLockPass = cursor.getString(cursor.getColumnIndex("lockpass"));
cursor.moveToNext();
}
new ManagerSecurityApi(strApiUrl);
tvWarning.setText(getString(R.string.warning, rtrim(strCoName)));
} else {
Phoenix.Error(getApplicationContext(),getString(R.string.required), false);
}
}
/**
* Override of the onBackPress method from the parent class
* This disables the back button on the device.
*/
#Override
public void onBackPressed() {
Phoenix.Error(ActivityHome.this, getString(R.string.disabled, getString(R.string.back)),false);
}
/**
* This method overrides the parents click listner.
* #param v the view clicked.
*/
#Override
public void onClick(View v) {
Button button = (Button)v;
String buttonText = button.getText().toString();
if (buttonText.equals(getString(R.string.login))) {
if (etUsername.getText().toString().isEmpty() || etPassword.getText().toString().isEmpty()) {
Phoenix.Error(ActivityHome.this, getString(R.string.both_required,getString(R.string.username_password)), false);
} else {
Call<String> call = getInstance().getApi().login(etUsername.getText().toString(), etPassword.getText().toString());
call.enqueue(new Callback<String>() {
#Override
public void onResponse(#NonNull Call<String> call, #NonNull Response<String> response) {
String body = response.body();
try {
assert body != null;
JSONObject obj = new JSONObject(body);
if (obj.optBoolean("success")) {
etUsername.setText("");
etPassword.setText("");
etUsername.requestFocus();
getContentResolver().delete(ProviderUser.CONTENT_URI, null, null);
ContentValues values = new ContentValues();
values.put(ProviderUser.name, obj.optString("username"));
values.put(ProviderUser.grade, obj.optInt("grade"));
values.put(ProviderUser.gradename, obj.optString("gradename"));
values.put(ProviderUser.department, obj.optInt("department"));
values.put(ProviderUser.departmentname, obj.optString("departmentname"));
getContentResolver().insert(ProviderUser.CONTENT_URI, values);
Phoenix.Success(ActivityHome.this, obj.optString("message"), 5);
showApps(obj.optString("username"), obj.optInt("grade"), obj.optString("gradename"), obj.optInt("department"), obj.optString("departmentname"));
} else {
Phoenix.Error(getApplicationContext(), getString(R.string.user_not), false);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(#NonNull Call<String> call, #NonNull Throwable t) {
}
});
}
} else if (buttonText.equals(getString(R.string.admin_access))) {
String LockPass = Phoenix.InputDialog(ActivityHome.this.getApplicationContext(), getString(R.string.input_prompt, getString(R.string.enter_lock_pass)));
if (LockPass.equals(strLockPass)) {
this.getPackageManager().clearPackagePreferredActivities(this.getPackageName());
finish();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
} else {
throw new IllegalStateException(getString(R.string.unexpected) + v.getId());
}
}
/**
* This method will call the App Display Activity
*/
private void showApps(String username, Integer grade, String gradename, Integer department, String departmentname){
Intent intent = new Intent(ActivityHome.this.getApplicationContext(), ActivityApp.class);
intent.putExtra("username", username);
intent.putExtra("grade", String.valueOf(grade));
intent.putExtra("gradename", gradename);
intent.putExtra("department", String.valueOf(department));
intent.putExtra("departmentname", departmentname);
startActivityForResult(intent, REQUEST_CODE_1);
}
/**
* Function to trim whitespace from the end of a string.
* #param s the string to trim
* #return the trimmed string
*/
#NonNull
public static String rtrim(String s) {
AtomicInteger i;
i = new AtomicInteger(s.length() - 1);
while (i.get() >= 0 && Character.isWhitespace(s.charAt(i.get()))) {
i.getAndDecrement();
}
return s.substring(0, i.get() +1);
}
}
And finially, here is my ActivityPhoenixLib.java file:
package com.phoenixhosman.phoenixlib;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import static android.view.View.inflate;
public class ActivityPhoenixLib extends Activity {
/**
* While not needed, this constructor makes calls to the member method of the class
* to clear errors in the editor.
*/
public ActivityPhoenixLib() {
Error(this, "", false);
Success(this,"",0);
String dummy = InputDialog(this, "");
if (dummy.equals("test")) {
}
}
/**
* This method displays a dialog box with an error message and a close button.
* #param strError the error message to display
*/
public void Error(Context context, #NonNull String strError, Boolean exit) {
if (strError.equals("")) {
return;
}
AlertDialog.Builder mBuilder = new AlertDialog.Builder(context);
View view = inflate(context, R.layout.dialog_error, null);
Button btnExit = view.findViewById(R.id.btnExitButton);
Button btnError = view.findViewById(R.id.btnErrorMessage);
btnError.setText(strError);
mBuilder.setView(view);
AlertDialog dialog = mBuilder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
btnExit.setOnClickListener(v -> {
dialog.dismiss();
if (exit) System.exit(0);
});
}
/**
* This method displays a dialog box with a message and a close button.
* It also has an auto close function to auto close after a specified number of seconds.
* #param strMessage the message to display
*/
public void Success(Context context, #NonNull String strMessage, Integer autoclose) {
if (strMessage.equals("")) {
return;
}
AlertDialog.Builder mBuilder = new AlertDialog.Builder(context);
View view = inflate(context, R.layout.dialog_success, null);
Button btnExit = view.findViewById(R.id.btnButton);
Button btnError = view.findViewById(R.id.btnMessage);
btnError.setText(strMessage);
mBuilder.setView(view);
AlertDialog dialog = mBuilder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
btnExit.setOnClickListener(v -> dialog.dismiss());
new Handler().postDelayed(dialog::dismiss, autoclose * 1000);
}
/**
* This method show an input box to get string input from the user.
* #param strPrompt - the dialog prompt
*/
public String InputDialog(Context context, String strPrompt) {
if (strPrompt.equals("")) {
return "";
}
AlertDialog.Builder mBuilder = new AlertDialog.Builder(context);
final String[] retval = new String[1];
View view = inflate(context, R.layout.dialog_input, null);
TextView txtPrompt = view.findViewById(R.id.txtPrompt);
EditText edtLockPass = view.findViewById(R.id.edtLockPass);
Button btnEnter = view.findViewById(R.id.btnEnter);
--> Line 97 <-- txtPrompt.setText(getString(R.string.input_prompt, strPrompt));
mBuilder.setView(view);
AlertDialog dialog = mBuilder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
dialog.show();
btnEnter.setOnClickListener(v -> {
if (edtLockPass.getText().toString().equals("")) {
retval[0] = "";
} else {
retval[0] = edtLockPass.getText().toString();
}
});
dialog.dismiss();
return retval[0];
}
}
I have tried several different things. I am going on the assumption that the context is not being passed to the InputDialog function, and I have tried different way of pass the context to the function: this. ActivityHome.this, getApplicationContext, and none of them seemed to work. Is there something I have nbot considered? Any help would be appreciated. Thanks.
Edit-In responce to one of the comments about my getString usage, on the page linked here my usage is documented, the second string is is the argument object for the formatting string.
Edit 2: I also tried to use a single parameter getSting on the line in question, and got the smae error.
I'm new in andoid studio and trying out Json, fetching Covid-19 data from an API. Please i want to add commas to large numbers fetched using Json. Here's the code below. I tried everything but no avail. I dont know if TextView need to be changed to another data format to allow that. The numbers just dispaly without commas. Thanks as you help me out.
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONException;
import org.json.JSONObject;
public class MainActivity
extends AppCompatActivity {
// Create the object of TextView
TextView tvCases, tvRecovered,
tvCritical, tvActive,
tvTodayCases, tvTotalDeaths,
tvTodayDeaths,
tvAffectedCountries;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Link those objects with their respective id's
// that we have given in .XML file
tvCases
= findViewById(R.id.tvCases);
tvRecovered
= findViewById(R.id.tvRecovered);
tvCritical
= findViewById(R.id.tvCritical);
tvActive
= findViewById(R.id.tvActive);
tvTodayCases
= findViewById(R.id.tvTodayCases);
tvTotalDeaths
= findViewById(R.id.tvTotalDeaths);
tvTodayDeaths
= findViewById(R.id.tvTodayDeaths);
// Creating a method fetchdata()
fetchdata();
}
private void fetchdata()
{
// Create a String request
// using Volley Library
String url = "https://coronavirus-19-api.herokuapp.com/countries/Nigeria";
StringRequest request
= new StringRequest(
Request.Method.GET,
url,
new Response.Listener<String>() {
#Override
public void onResponse(String response)
{
// Handle the JSON object and
// handle it inside try and catch
try {
// Creating object of JSONObject
JSONObject jsonObject
= new JSONObject(
response.toString());
// Set the data in text view
// which are available in JSON format
// Note that the parameter inside
// the getString() must match
// with the name given in JSON format
tvCases.setText(
jsonObject.getString(
"cases"));
tvRecovered.setText(
jsonObject.getString(
"recovered"));
tvCritical.setText(
jsonObject.getString(
"critical"));
tvActive.setText(
jsonObject.getString(
"active"));
tvTodayCases.setText(
jsonObject.getString(
"todayCases"));
tvTotalDeaths.setText(
jsonObject.getString(
"deaths"));
tvTodayDeaths.setText(
jsonObject.getString(
"todayDeaths"));
}
catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error)
{
Toast.makeText(
MainActivity.this,
error.getMessage(),
Toast.LENGTH_SHORT)
.show();
}
});
RequestQueue requestQueue
= Volley.newRequestQueue(this);
requestQueue.add(request);
}
}
You can do like this :
first get the JSON data then convert it to long and use Number format.
This for total cases :
String total_json = jsonObject.getString("cases");
long totals = Long.parseLong(total_json);
total.setText(NumberFormat.getNumberInstance(Locale.US).format(totals));
I am relatively new to Java and working with the ArcGIS Runtime SDK for Android. I am making an app where the user selects the parcel id from spinner list. If the user clicks on a 'ZOOM' button the map should zoom to the parcel that was selected. Here is my code:
package gist8010.main;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISDynamicMapServiceLayer;
import com.esri.android.map.ags.ArcGISTiledMapServiceLayer;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Point;
import com.esri.core.map.Feature;
import com.esri.core.map.FeatureResult;
import com.esri.core.tasks.query.QueryParameters;
import com.esri.core.tasks.query.QueryTask;
public class Spinner_WalkActivity extends Activity {
MapView mMapView;
Button mBtnZoom;
ArcGISDynamicMapServiceLayer mDynamicLayer;
Spinner mSpnParcels;
String mMapServiceURL = "http://indy14.athena.bcit.ca:8080/"
+ "esri_rest/services/gist_8010_test_ms/MapServer";
int mLotLayerID = 0;
String mLotLayerURL = mMapServiceURL + "/" + mLotLayerID;
String mLotNumColName = "PARCELS_ID";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
/** Allow querying on main thread */
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
/** Create spinner and button */
setMapView();
this.mBtnZoom = (Button) findViewById(R.id.btnZoom);
mBtnZoom.setOnClickListener(new OnClickListener() {
/** Upon click of zoom button, invoke th zoomtoFeature Method */
public void onClick(View v) {
zoomToFeature(v);
}
});
this.mSpnParcels = (Spinner) findViewById(R.id.spnParcels);
/** Add Layer to map */
mDynamicLayer = new ArcGISDynamicMapServiceLayer(mMapServiceURL);
mMapView.addLayer(mDynamicLayer);
QueryParameters qryLotNums = new QueryParameters();
qryLotNums.setReturnGeometry(false);
qryLotNums.setOutFields(new String[] { mLotNumColName });
qryLotNums.setWhere(mLotNumColName + ">0");
com.esri.core.tasks.query.QueryTask qtask = new com.esri.core.tasks.query.QueryTask(
mLotLayerURL);
try {
FeatureResult fSet = qtask.execute(qryLotNums);
ArrayList<String> listOfLotsNums = new ArrayList<String>();
Feature tmpFeat;
for (Object featAsObj : fSet) {
tmpFeat = (Feature) featAsObj;
listOfLotsNums.add(tmpFeat.getAttributeValue(mLotNumColName)
.toString());
}
ArrayAdapter<String> adtTmp = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_dropdown_item,
listOfLotsNums);
mSpnParcels.setAdapter(adtTmp);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}// of catch
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
mMapView.pause();
}
#Override
protected void onResume() {
super.onResume();
mMapView.unpause();
}
// =============================================================================
// Zooms the map the the MBR of the feature selected in the spinner
// import android.view.View;
// =============================================================================
public void zoomToFeature(View v) {
QueryParameters zoomQuery = new QueryParameters();
zoomQuery.setReturnGeometry(true);
zoomQuery.setOutFields(new String[] { mLotNumColName });
zoomQuery.setWhere(mLotNumColName + "=" + mSpnParcels.getSelectedItem());
QueryTask qtask = new QueryTask(mLotLayerURL);
try {
FeatureResult fset = qtask.execute(zoomQuery);
Feature tmpFeat = (Feature) fset.iterator().next();
Envelope envelope = new Envelope();
envelope.queryEnvelope((Envelope) tmpFeat.getGeometry());
getMapView().setExtent(envelope);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// =============================================================================
// getter for the main map
// =============================================================================
private MapView getMapView() {
// =============================================================================
// if MapView is underlined in red, change the name to match your
// MapView
// =============================================================================
return mMapView;
}
// =============================================================================
// setter for the main map
// =============================================================================
private void setMapView() {
// ========================================================================
// if mapView is underlined in red then sync class-level var names
// if R.id.map is underlined in red ensure that you added the xml
// fragment
// such as "MapView Generic" to a layout
// ========================================================================
mMapView = (MapView) findViewById(R.id.map);
}
}
After attempting to debug, I think my issue is with the Envelope class. The queryEnvelope method accepts a Envelope argument. As you can see, I cast the geometry of the Feature tmpFeat from a geometry type into a Envelope type.
When I run the application on my phone I get an System.Err in my log Cat saying:
java.lang.ClassCastException: com.esri.core.geometry.Polygon cannnot be cast to com.esri.core.geometry.Envelope
Am I doing the casting incorrectly? I cannot think of another way of linking my Envelope instance with the geometry of the feature class i want to zoom to.
Envelop is a child class of com.esri.core.geometry.Geometry, not vice versa. I guess this is why you fail when do the cast.
https://developers.arcgis.com/android/api-reference/reference/com/esri/core/geometry/Envelope.html
As it to your question, I guess envelop is not necessary to zoom to a feature. MapView.zoomToResolution(Point centerPt, double res) or zoomTo(Point centerPt, float factor) may be a better choice. You may find these sample codes helpful:
https://developers.arcgis.com/android/sample-code/geocoding/
I have written a log in function for my android app, I am wanting to make it work on API 17, right now it give a network on main thread exception, which I understand you cant do network operations on the main thread, I have played around with trying to put threads in but it doesn't seem to go. So i am trying a asynctask now
any help suggestions would be great
package khs.studentsupport;
import java.util.HashMap;
import khs.supportapp.library.DatabaseHandler;
import khs.supportapp.library.UserFunctions;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class New_Login extends Activity{
// Progress Dialog
private ProgressDialog pDialog;
public String storedEmail="";
public String stroedPW = "";
boolean GCMFlag=false;
// Shared Preferences
SharedPreferences pref;
// Editor for Shared preferences
Editor editor;
// Context
Context _context;
// Shared pref mode
int PRIVATE_MODE = 0;
// Sharedpref file name
private static final String PREF_NAME = "AndroidHivePref";
// All Shared Preferences Keys
private static final String IS_LOGIN = "IsLoggedIn";
// User name (make variable public to access from outside)
public static final String KEY_NAME = "name";
// Email address (make variable public to access from outside)
public static final String KEY_EMAIL = "email";
// Constructor
public void SessionManager(Context context){
this._context = context;
pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
editor = pref.edit();
}
/**
* Create login session
* */
public void createLoginSession(String name, String email){
// Storing login value as TRUE
editor.putBoolean(IS_LOGIN, true);
// Storing name in pref
editor.putString(KEY_NAME, name);
// Storing email in pref
editor.putString(KEY_EMAIL, email);
// commit changes
editor.commit();
}
// Internet detector
ConnectionDetector cd;
AlertDialogManager alert = new AlertDialogManager();
Button btnLogin;
Button btnLinkToRegister;
EditText inputEmail;
EditText inputPassword;
TextView loginErrorMsg;
// JSON Response node names
private static String KEY_SUCCESS = "success";
//private static String KEY_ERROR = "error";
//private static String KEY_ERROR_MSG = "error_msg";
private static String KEY_UID = "uid";
private static String KEY_STUDENT_ID = "studentUser";
private static String KEY_CREATED_AT = "created_at";
public HashMap<String, String> getUserDetails(){
HashMap<String, String> user = new HashMap<String, String>();
// user name
user.put(KEY_NAME, pref.getString(KEY_NAME, null));
//ID of student
user.put(KEY_STUDENT_ID, pref.getString(KEY_STUDENT_ID, null));
// user email id
user.put(KEY_EMAIL, pref.getString(KEY_EMAIL, null));
// return user
return user;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
}
// Response from Activity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// if result code 100
if (resultCode == 100) {
// if result code 100 is received
// means user edited/deleted product
// reload this screen again
Intent intent = getIntent();
finish();
startActivity(intent);
}
}
/**
* Background Async Task to Load all product by making HTTP Request
* */
class LoadAlldetails extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(New_Login.this);
pDialog.setMessage("Logging you in. Please wait...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
/**
* getting user details from url
* */
protected String doInBackground(String... args) {
cd = new ConnectionDetector(getApplicationContext());
String storedEmail = Appconfig.stored_user_name.toString();
String stroedPW = Appconfig.stored_password.toString();
// Check if Internet present
if (!cd.isConnectingToInternet())
{
if((inputEmail.toString()==storedEmail)&&(inputPassword.toString()==stroedPW))
{
// Launch Dashboard Screen
Intent dashboard = new Intent(getApplicationContext(), DashboardActivity.class);
// Close all views before launching Dashboard
dashboard.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(dashboard);
}
}
// Importing all assets like buttons, text fields
inputEmail = (EditText) findViewById(R.id.loginEmail);
inputPassword = (EditText) findViewById(R.id.loginPassword);
//Auto fill for login only if the user has logged in before
if((Appconfig.stored_user_name.length()>0)&&(Appconfig.stored_password.length()>0))
{
inputEmail.setText(Appconfig.stored_user_name.toString());
inputPassword.setText(Appconfig.stored_password.toString());
}
// Importing all assets like buttons, text fields
btnLogin = (Button) findViewById(R.id.btnLogin);
btnLinkToRegister = (Button) findViewById(R.id.btnLinkToRegisterScreen);
loginErrorMsg = (TextView) findViewById(R.id.login_error);
// Login button Click Event
btnLogin.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
new LoadAlldetails().execute();
String email = inputEmail.getText().toString();
String password = inputPassword.getText().toString();
UserFunctions userFunction = new UserFunctions();
Log.d("Button", "Login");
JSONObject json = userFunction.loginUser(email, password);
//Check to see if user has put in details
if ((email.matches("")||(password.matches(""))))
{
loginErrorMsg.setText("Please enter your details ");
}
else
{ //Checks to see if first time in the app
// launces gcm activity
if (Appconfig.GCMactivity == false) {
Intent intent = new Intent();
intent.setClass(getApplicationContext(),RegisterForGCMActivity.class);
startActivity(intent);
//set to true so GCm register wont show again
Appconfig.GCMactivity=true;
}
else{
// check for login response
try {
if (json.getString(KEY_SUCCESS) != null) {
loginErrorMsg.setText("");
String res = json.getString(KEY_SUCCESS);
if(Integer.parseInt(res) == 1){
// user successfully logged in
// Store user details in SQLite Database
DatabaseHandler db = new DatabaseHandler(getApplicationContext());
JSONObject json_user = json.getJSONObject("user");
Appconfig.stored_user_name=json_user.getString(KEY_EMAIL);
Appconfig.stored_password = password;
if(Appconfig.email_is_set==false)
{
Appconfig.student_ID = json_user.getString(KEY_STUDENT_ID);
}
Appconfig.email_is_set=true;
// Clear all previous data in database
userFunction.logoutUser(getApplicationContext());
db.addUser(json_user.getString(KEY_NAME), json_user.getString(KEY_EMAIL), json.getString(KEY_UID), json_user.getString(KEY_CREATED_AT));
// Launch Dashboard Screen
Intent dashboard = new Intent(getApplicationContext(), DashboardActivity.class);
// Close all views before launching Dashboard
dashboard.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(dashboard);
// Close Login Screen
finish();
}else{
// Error in login
loginErrorMsg.setText("Incorrect username/password");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}}});
GCMFlag = true;
// Link to Register Screen
btnLinkToRegister.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent i = new Intent(getApplicationContext(),
RegisterActivity.class);
startActivity(i);
finish();
}
});
return null;
}
public boolean isLoggedIn(){
return pref.getBoolean(IS_LOGIN, false);
}
}
/**
* After completing background task Dismiss the progress dialog
* **/
protected void onPostExecute(String file_url) {
// dismiss the dialog after getting user details
pDialog.dismiss();
// updating UI from Background Thread
runOnUiThread(new Runnable() {
public void run() {
}
});
}
}
I see many so far so I will let you know about these but know that there may be more.
First, you call startActivity from a background Thread so you need to add a Context to it. Since its an inner class of Activity you could use
New_Login.this.startActivity(dashboard);
However, you should return data to onPostExecute() and just start the Activity from there.
Another thing I see is that you are trying to update Views from a background Thread which is a no no. You should not try to update them in doInBackground().
You are trying to compare Strings incorrectly
if((inputEmail.toString()==storedEmail)&&(inputPassword.toString()==stroedPW))
it should be
if((inputEmail.toString().equals(storedEmail))&&(inputPassword.toString().equals(stroedPW)))
It looks like you are declaring your Views in your AsyncTask but this should be done in your Activity(most likely in onCreate() or onResume().
Don't use getApplicationContext() unless absolutely necessary. Inside of an onClick() you can use v.getContext() and inside of your Activity but outside of a listener you can use ActivitiyName.this (there are more options there but I will keep that simple for now).
My suggestion, strip out your AsyncTask and get your Activity set up correctly then implement your AsyncTask. And be sure to go through the documentation well.
Activity Docs
AsyncTask Docs