Display And Use Information From A DownloadTask In Android Studio - java

First time using Android Studio in any large capacity. Using the code from here: https://stackoverflow.com/a/30937657/5919360, I was able to successfully pull the information I wanted from the URL, but I can't figure out how use it.
Note: I know IMEI is not a good way to check for user registration and will be changing it later.
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
// Create instance and populates based on content view ID
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// store IMEI
String imei = tm.getDeviceId();
// store phone
String phone = tm.getLine1Number();
// Display IMEI - Testing Purposes Only
TextView imeiText = (TextView) findViewById(R.id.imeiDisplay);
imeiText.setText("IMEI:" + imei);
// Display phone number - Testing Purposes Only
TextView phoneText = (TextView) findViewById(R.id.phoneDisplay);
phoneText.setText("Phone:" + phone);
new DownloadTask().execute("http://www.url.com/mobileAPI.php?action=retrieve_user_info&IMEI="+imei);
}
private class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
try {
return downloadContent(params[0]);
} catch (IOException e) {
return "Unable to retrieve data. URL may be invalid.";
}
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
}
}
private String downloadContent(String myurl) throws IOException {
InputStream is = null;
int length = 500;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.connect();
int response = conn.getResponseCode();
Log.d(TAG, "The response is: " + response);
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = convertInputStreamToString(is, length);
return contentAsString;
} finally {
if (is != null) {
is.close();
}
}
}
public String convertInputStreamToString(InputStream stream, int length) throws IOException, UnsupportedEncodingException {
Reader reader = null;
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[length];
reader.read(buffer);
return new String(buffer);
}
}
This code returns an xml file, as a toast:
<?xml version="1.0" encoding="ISO-8859-1"?>
<mobile_user_info>
<rec>45</rec>
<IMEI>9900990099009</IMEI>
<fname>First</fname>
<lname>Last</lname>
<instance>instance1</instance>
<registered>N</registered>
</mobile_user_info>
I'm hoping someone can point me in the right direction for separating each line and using it independently. For example, if the Registered line comes back as N, a message is displayed like, 'You are not registered. Please contact administrator.'

Actually you should use an XML parser to parse the server's response. But if responses are always as simple as your example, you can use a regular expression to extract out the IMEI field.
String contentAsString = ...
Pattern pattern = Pattern.compile("<IMEI>(\d*)</IMEI>");
Matcher matcher = pattern.matcher(contentAsString);
if (matcher.find()) {
String imei = matcher.group(1);
}

Related

Pull specific JSON objects from a specific array to put in another activity by an Intent in Android

I am creating a News Feed App, and I want to be able to pull information from a specific listing to a different layout that displays the title, source, image and content of the news listing. On the main page, the JSON will populate the list view with the title, source and image. I've sent an onItemClickListener, and when I click on each entry, I want it to open that entry in the new layout to display all the content. I have a class made just to pull the JSON info, so I'm not sure how to use that in the class with the onItemClick listener. I understand the putExtra, but I'm completely lost on the code to enter to transfer over what I need. Below is code from the page with the list, as well as the JsonQuery class. Thanks for any help!
TopHeadlinesFragment.java
public class TopHeadlinesFragment extends Fragment
implements LoaderManager.LoaderCallbacks<List<News>> {
public static final String NEWS_FEED_URL =
"https://newsapi.org/v2/top-headlines?country=us&apiKey=a3f791903c1a4163b223dd033563084b";
private static final int NEWS_LOADER_ID = 1;
private NewsAdapter mNewsAdapter;
private NewsAdapterListing mNewsAdapterListing;
public TopHeadlinesFragment(){
// Required empty public constructor
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.news_list, container, false);
mNewsAdapter = new NewsAdapter(getActivity(), new ArrayList<News>());
ListView listView = rootView.findViewById(R.id.list);
listView.setAdapter(mNewsAdapter);
final LoaderManager loaderManager = getLoaderManager();
loaderManager.initLoader(NEWS_LOADER_ID, null, this);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mNewsAdapterListing = new NewsAdapterListing(getActivity(), new ArrayList<News>());
News currentNews = mNewsAdapterListing.getItem(position);
Intent newsArticleDisplayIntent = new Intent(getActivity(), FullArticleListing.class);
startActivity(newsArticleDisplayIntent);
}
});
return rootView;
}
#Override
public Loader<List<News>> onCreateLoader(int id, Bundle args) {
return new NewsLoader(getActivity(), NEWS_FEED_URL);
}
#Override
public void onLoadFinished(Loader<List<News>> loader, List<News> data) {
mNewsAdapter.clear();
if (data != null && !data.isEmpty()){
mNewsAdapter.addAll(data);
}
}
#Override
public void onLoaderReset(Loader<List<News>> loader) {
mNewsAdapter.clear();
}
public static class NewsLoader extends AsyncTaskLoader<List<News>> {
private String[] mUrl;
public NewsLoader(Context context, String... url) {
super(context);
mUrl = url;
}
#Override
protected void onStartLoading() {
forceLoad();
}
#Override
public List<News> loadInBackground() {
if (mUrl.length < 1 || mUrl[0] == null) {
return null;
}
return JsonQueryUtils.fetchNewsData(mUrl[0]);
}
}
}
JsonQueryUtils.java
public class JsonQueryUtils {
/** Contains networking and JSON parsing code **/
private static final String LOG_TAG = "JsonQueryUtils";
private JsonQueryUtils(){
}
/** Helper method to fetch news data and call networking code within method **/
public static List<News> fetchNewsData(String requestUrl){
URL url = createUrl(requestUrl);
String jsonResponse = null;
try{
jsonResponse = makeHttpRequest(url);
} catch (IOException e){
Log.e(LOG_TAG, "Error closing input stream", e);
}
List<News> news = extractNews(jsonResponse);
Log.i(LOG_TAG, "fetchNewsData initialized");
return news;
}
private static List<News> extractNews (final String newsJSON) {
if (TextUtils.isEmpty(newsJSON)) {
return null;
}
List<News> news = new ArrayList<>();
try {
JSONObject jsonNewsObject = new JSONObject(newsJSON);
JSONArray newsArray = jsonNewsObject.getJSONArray("articles");
for (int i = 0; i < newsArray.length(); i++) {
JSONObject currentNews = newsArray.getJSONObject(i);
JSONObject source = currentNews.optJSONObject("source");
String imageUrl = currentNews.getString("urlToImage");
Bitmap newsImage = makeHttpRequest(imageUrl);
String title = currentNews.getString("title");
String sourceName = source.getString("name");
String content = currentNews.getString("content");
news.add(new News(newsImage, title, sourceName));
}
} catch (JSONException e) {
e.printStackTrace();
Log.e(LOG_TAG, "problem with parsing", e);
} catch (IOException e){
e.printStackTrace();
}
return news;
}
/**
* Make an HTTP request to the given imageURL and return a Bitmap as the response.
*/
private static Bitmap makeHttpRequest (String imageUrl) throws IOException {
Bitmap newsImage = null;
if (imageUrl == null){
return newsImage;
}
URL url = createUrl(imageUrl);
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);
urlConnection.connect();
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
newsImage = BitmapFactory.decodeStream(inputStream);
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error reading bitmap input stream");
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
}
return newsImage;
}
/**
* Make an HTTP request to the given URL and return a String as the response.
*/
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem reading input stream.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
}
return jsonResponse;
}
/**
* Convert the {#link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private static String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
/** Helper method to create {#link} URL object **/
private static final URL createUrl(String stringUrl) {
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "createUrl: error", e);
}
return url;
}
}
I noticed you extracted the 'content' from JSON response but I don't see anywhere the variable 'content' getting used to construct the News object... Is there a reason why you don't include it to News object?
Regarding sending the News object to the next activity, there are few ways to achieve this.
Use Parcelable to send the News to your next activity/fragment. For more details, click here.
Install GSON library and simple convert your News object to Json String. Put that String in your Intent as an extra and launch the next Activity. Retrieve the data by calling new Gson().fromJson(). However, since your object has Bitmap field, this won't be a suitable approach. For more details, click here
This is what I would have done, if the API allows: Simply call the API request again for more details about the current feed. For example, you can execute another API request in your FullArticleActivity along with an ID that is associated with the selected feed. (i.e. User clicks a feed with an id #3 -> Pass the id(Integer) to the next Activity as an extra -> Retrieve the id from extras and make another API request using the id to retrieve full article details.) However, this is possible only when your API provides a GET method like this.
Create a Singleton and let it hold your object temporarily. Retrieve the object in the next activity by simple calling something like YourSingletonClass.getInstance().getNews().

AsyncTask doInBackground to return multiple strings

I'm trying to build a very basic weather app in android studio. I am using AsyncClass to return multiple strings.
As you can see in the code, I used a class named "Wrapper" that is used to store my strings so I can just return a class object and use it in the onPostExecute method of the AsyncTask. The problem I am facing is that when I test the app, all of the returned Strings somehow are undefined (the default for the Wrapper class). This means the strings are not being updated in the doInBackground method and I can't seem to figure out why!
My Activity
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(MainActivity.class.getSimpleName(), "Can't connect to Google Play Services!");
}
private class Wrapper
{
String Temperature = "UNDEFINED";
String city = "UNDEFINED";
String country = "UNDEFINED";
}
private class GetWeatherTask extends AsyncTask<String, Void, Wrapper> {
private TextView textView;
public GetWeatherTask(TextView textView) {
this.textView = textView;
}
#Override
protected Wrapper doInBackground(String... strings) {
Wrapper w = new Wrapper();
String Temperature = "x";
String city = "y";
String country = "z";
try {
URL url = new URL(strings[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String inputString;
while ((inputString = bufferedReader.readLine()) != null) {
builder.append(inputString);
}
JSONObject topLevel = new JSONObject(builder.toString());
JSONObject main = topLevel.getJSONObject("main");
JSONObject cityobj = topLevel.getJSONObject("city");
Temperature = String.valueOf(main.getDouble("temp"));
city = cityobj.getString("name");
country = cityobj.getString("country");
w.Temperature= Temperature;
w.city= city;
w.country=country;
urlConnection.disconnect();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return w;
}
#Override
protected void onPostExecute(Wrapper w) {
textView.setText("Current Temperature: " + w.Temperature + " C" + (char) 0x00B0
+"\n" + "Current Location: "+ w.country +"\n" + "City: "+ w.city );
}
}
}
UPDATE:
turned out that that I was using the wrong url in my code,I was using :
http://api.openweathermap.org/data/2.5/weather?lat=%f&lon=%f&units=%s&appid=%s
Instead I should've been using:
http://api.openweathermap.org/data/2.5/forecast?lat=%f&lon=%f&units=%s&appid=%s
-aka instead of weather I should've been using forcast
Your error starts here
JSONObject main = topLevel.getJSONObject("main");
Probably because the topLevel object has no "main" key.
{
"city":{ },
"cod":"200",
"message":0.1859,
"cnt":40,
"list":[ ]
}
Throw your JSON into here. https://jsonformatter.curiousconcept.com/
You'll notice that there are many, many "main" keys that are within the "list" element, but you have to parse those starting from getJSONArray("list").
Basically, something like this
String city = "undefined";
String country = "undefined";
List<Double> temperatures = new ArrayList<Double>();
try {
JSONObject object = new JSONObject(builder.toString());
JSONObject jCity = object.getJSONObject("city");
city = jCity.getString("name");
country = jCity.getString("country");
JSONArray weatherList = object.getJSONArray("list");
for (int i = 0; i < weatherList.length(); i++) {
JSONObject listObject = weatherList.getJSONObject(i);
double temp = listObject.getJSONObject("main").getDouble("temp");
temperatures.add(temp);
}
} catch (JSONException e) {
e.printStackTrace();
}
return new Wrapper(city, country, temperatures);
After studying your code, either your try block is failing, which is returning your object, but empty, or there is something wrong with your JSON parsing. If you could show us the JSON you are trying to parse that would be a great help.
That being said, the fact that it is still showing as "UNDEFINED" is because that is how you initialised it, and becuase (the JSON parse is likely failing), the object is being returned in an un-edited state.
EDIT:
You are parsing the JSON wrong. You are trying to find an object called "main" in the top directory, however the main object only exists inside of an array called list!
Please look here for a more easy to see and visual representation: http://prntscr.com/dlhlrk
You can use this site to help visualise your JSON and create an appropriate soluton based upon it. https://jsonformatter.curiousconcept.com/
Looking at the API you posted earlier (api.openweathermap.org) you are trying to access variables that don't exist. I suggest you have a look at what the API returns and try getting the variables one by one if you are getting a JSONException
EDIT:
What API you are using? In your initial post you said it was http://api.openweathermap.org/data/2.5/weather but in a comment above you said it was http://api.openweathermap.org/data/2.5/forecast.
If you're using the weather API (as initially stated) you can use the below:
#Override
protected Wrapper doInBackground(String... strings) {
Wrapper w = new Wrapper();
try {
URL url = new URL(strings[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String inputString;
while ((inputString = bufferedReader.readLine()) != null) {
builder.append(inputString);
}
Log.d("JSON", builder.toString());
JSONObject topLevel = new JSONObject(builder.toString());
JSONObject main = topLevel.getJSONObject("main");
JSONObject sys = topLevel.getJSONObject("sys");
w.Temperature = String.valueOf(main.getDouble("temp"));
w.city = topLevel.getString("name");
w.country = sys.getString("country");
urlConnection.disconnect();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
return w;
}

Java code gets not executed

I developing android app and now I have problem. Below is a part of my code, and it keeps skipping the "for" part. When I put a breakpoint inside for statement, it stops at the point, and executes the lines very well and makes an output that I want. When I just 'run' app, it skips that part so "String locations" value doesn't change. I googled and some say it's thread-related problem. So I put synchroinzed on the method, still not working. Any other suggestions?
UPDATE
I was trying to show code only related to the problem, but I think now showing the whole would be more useful for those who try to help so here's my entire code on showMapActivity. You can see I've tried some ways around and nothing worked. Saving path's information into String url is where I'm having problem. I tested, and other parts seem to work fine. I know my code is really massy, that was why I only posted parts of the code. TMap related classes are imported from .jar file.
public class showMapActivity extends Activity {
TMapData tmapdata=new TMapData();
TMapView tmapView;
TMapPoint origin, dest;
volatile ArrayList<TMapPoint> points=new ArrayList<>();
private TextView x;
private TextView y;
private HashMap<String,LatLng> coordinates;
private HashMap<LatLng,Double> finalpoint;
static private ConcurrentHashMap<Double,Double> path;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_map);
coordinates=new HashMap<>();
Intent intent=getIntent();
tmapView=new TMapView(this);
path=new ConcurrentHashMap<>();
coordinates=(HashMap<String,LatLng>)intent.getSerializableExtra("coordinate");
path=getPathPoints(coordinates);
int i=0;
String url=getUrl();
//String url = "https://maps.googleapis.com/maps/api/elevation/json?locations=";
//String locations="";
/*
Iterator<Double> keys= path.keySet().iterator();
while(keys.hasNext()){
Double key=keys.next();
//String lat=String.valueOf(key);
//String lng=String.valueOf(path.get(key));
locations=locations+String.valueOf(key)+","+String.valueOf(path.get(key));
if(keys.hasNext())
locations=locations+"|";
}path.entrySet()
*/
/*
for(ConcurrentHashMap.Entry<Double,Double> elem : path.entrySet())
{
String lat=String.valueOf(elem.getKey());
String lng=String.valueOf(elem.getValue());
locations=locations+lat+","+lng;
i++;
if(i!=path.size())
{
locations=locations+"|";
}
}
*/
//url=url+locations+"&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto";
//String url=getUrl(path);
FetchUrl fetchUrl=new FetchUrl();
fetchUrl.execute(url);
}
private ConcurrentHashMap<Double,Double> getPathPoints(HashMap<String,LatLng> coordinates)
{
final ConcurrentHashMap<Double,Double> Path=new ConcurrentHashMap<>();
tmapView.setSKPMapApiKey("6bb5b7f3-1274-3c5e-ba93-790aee876673");
origin=new TMapPoint(coordinates.get("origin").latitude,coordinates.get("origin").longitude);
dest=new TMapPoint(coordinates.get("dest").latitude,coordinates.get("dest").longitude);
tmapdata.findPathData(origin, dest, new TMapData.FindPathDataListenerCallback() {
#Override
public void onFindPathData(TMapPolyLine polyLine) {
points=polyLine.getLinePoint();
for(TMapPoint point : points )
Path.put(point.getLatitude(),point.getLongitude());
}
});
return Path;
}
//ConcurrentHashMap<Double,Double> path
private synchronized String getUrl() {
int i=0;
String url = "https://maps.googleapis.com/maps/api/elevation/json?locations=";
String locations="";
for(HashMap.Entry<Double,Double> elem : path.entrySet())
{
String lat=String.valueOf(elem.getKey());
String lng=String.valueOf(elem.getValue());
locations=locations+lat+","+lng;
i++;
if(i!=path.size())
{
locations=locations+"|";
}
}
url=url+locations+"&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto";
//https://maps.googleapis.com/maps/api/elevation/json?locations=
// 39.7391536,-104.9847034|36.455556,-116.866667&key=AIzaSyDD88VFMPIfC5sr0XsFL0PDCE-QRN8gQto
// Output format
return url;
}
private class FetchUrl extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... url) {
// For storing data from web service
String data = "";
try {
// Fetching the data from web service
//downloadURL
data = downloadUrl(url[0]);
Log.d("Background Task data", data.toString());
} catch (Exception e) {
Log.d("Background Task", e.toString());
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
//ParserTask
ParserTask parserTask = new ParserTask();
// Invokes the thread for parsing the JSON data
parserTask.execute(result);
}
}
private String downloadUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
//읽은 데이터를 버퍼에 저장
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
Log.d("downloadUrl", data.toString());
br.close();
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
private class ParserTask extends AsyncTask<String, Integer, ArrayList<Double>> {
// Parsing the data in non-ui thread
#Override
protected ArrayList<Double> doInBackground(String... jsonData) {
JSONObject jObject;
ArrayList<Double> altitude = null;
try {
jObject = new JSONObject(jsonData[0]);
Log.d("ParserTask",jsonData[0].toString());
//DataParser class 호출
DataParser parser = new DataParser();
Log.d("ParserTask", parser.toString());
// Starts parsing data
altitude = parser.parse(jObject);
Log.d("ParserTask","Getting Altitudes");
Log.d("ParserTask",altitude.toString());
} catch (Exception e) {
Log.d("ParserTask",e.toString());
e.printStackTrace();
}
return altitude;
}
// Executes in UI thread, after the parsing process
#Override
protected void onPostExecute(ArrayList<Double> result) {
finalpoint=new HashMap<>();
LatLng latLng;
int i=0;
for(HashMap.Entry<Double,Double> elem : path.entrySet() )
{
latLng=new LatLng(elem.getKey(),elem.getValue());
finalpoint.put(latLng,result.get(i++));
}
x = (TextView) findViewById(R.id.textView5);
y = (TextView) findViewById(R.id.textView6);
x.setText(String.valueOf(finalpoint.get(coordinates.get("origin"))));
y.setText(String.valueOf(finalpoint.get(coordinates.get("dest"))));
}
}
}
(Apologies for posting this as an answer - I don't yet have the required reputation to comment)
Simply adding synchronized to a method doesn't necessarily guarantee thread safety.
How and when is path being populated?
Update after additional information provided
The problem seems to be that the path points are being generated asynchronously, and you are trying to use them before the generation process has finished (or perhaps even started). This happens because the findPathData simply starts the generation process and returns immediately (i.e. before the generation process has finished). In your code, you then go on and build the URL which is supposed to contain the point data immediately. At this point the background point generation process may not have finished, and may not have even started. As a result the point map may be empty or incomplete, and your URL will not be generated as you expect.
You need to find a way to wait until all of the path point data has been returned by the asynchronous processing before creating the URL. This looks like it could be very difficult, if not impossible, with the version of the findPathData method you are using, because it returns points via the callback one at a time and you may not know how many will be generated.
I had a quick look at the API for TMapData and it has a findPathDataAll method which seems to generate all the points and return them in a single callback call rather than one by one. If this is indeed what it does (sorry, I can't read Korean), you could use this method and then generate the URL from the callback, because when it's called you know that the generation process has been completed. If you do this, be careful to make sure that you're on the main thread before interacting with the UI or Activity.
Hope that helps.

Images(base64) not uploading correctly

Unfortunately I'm facing some issues when I try to upload some images from an android device to a database.
The images are in a folder. This folder contains images as well as other stuff. I don't know the names of the images and I need to upload only the images(jpg). Before I upload the images I need to encode them with base64.
First I get the jpg files from the folder. Then I get the ID out of the image name. After that I encode it via base64:
Button upload = (Button) findViewById(R.id.upload);
upload.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
String path = Environment.getExternalStorageDirectory().getPath();
File dir = new File(path);
File[] files = dir.listFiles();
for (int i = 0; i < files.length; ++i) {
if (files[i].getName().endsWith(".jpg")) {
pics = new File(String.valueOf(files[i]));
id = String.valueOf(files[i]);
String sub = id.substring(id.lastIndexOf("/") + 1);
int index = sub.indexOf("_");
String book;
if (index >= 0) {
book = sub.substring(0, index);
ID = book;
Log.e("ID", ID);
}
Bitmap imagex = BitmapFactory.decodeFile(pics.getAbsolutePath());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imagex.compress(Bitmap.CompressFormat.JPEG, 70, baos);
byte[] b = baos.toByteArray();
Image = Base64.encodeToString(b, Base64.DEFAULT);
try {
new HttpAsyncTask(ID,Image,Nummer).execute("https://....");
} catch (Exception e) {
Log.e("InputStream", e.getMessage());
}
Log.e("PICS", id);
}
}
}
});
public String POST(String url) {
InputStream inputStream;
try {
HttpClient httpclient = classxy.getNewHttpClient();
HttpPost httpPost = new HttpPost(url);
String json = "";
JSONObject jsonObject = new JSONObject();
jsonObject.put("bookId", ID);
jsonObject.put("imageString", Image);
jsonObject.put("imageNumber", Nummer);
json = jsonObject.toString();
StringEntity se = new StringEntity(json);
httpPost.setEntity(se);
httpPost.setHeader("Apikey", data);
httpPost.setHeader("Modul", "upload_image");
HttpResponse httpResponse = httpclient.execute(httpPost);
inputStream = httpResponse.getEntity().getContent();
if (inputStream != null)
result = classxy.convertInputStreamToString(inputStream);
else
result = "Fehler!";
} catch (Exception e) {
Log.e("InputStream", e.getLocalizedMessage());
}
int num = Integer.parseInt(Nummer);
num++;
Nummer = Integer.toString(num);
return result;
}
public class HttpAsyncTask extends AsyncTask<String, Void, String> {
private final Object ID, Image, Nummer;
public HttpAsyncTask(Object ID, Object Image, Object Nummer) {
this.ID = ID;
this.Image = Image;
this.Nummer = Nummer;
}
protected String doInBackground(String... urls) {
return POST(urls[0]);
}
protected void onPostExecute(String result) {
if (result.matches("(.*)false(.*)")) {
Toast.makeText(getApplicationContext(), "....", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "...", Toast.LENGTH_SHORT).show();
}
Log.e("RESPONSE", result);
}
}
It does encode the images via base64 and it does upload some of the images. Unfortunately it uploads only the first image or one image multiple times. It never uploads the correct amount of images in the correct order. I've been sitting on this problem for a while now and can't figure out what I'm doing wrong.
Can you tell me what I'm doing wrong?
Your program doesn't seem to be thread-safe at all.
Your fields ID, Image and Nummer are updated with every iteration of the for loop. Most likely the loop has already finished before POST runs for the first time. Your observation would support this assumption:
Unfortunately it uploads only the first image or one image multiple times.
You can observe this by logging every access to these fields. You'll find, that it's not alternating like you expect it to be.
Therefore you should implement everything without using these fields at all. Instead use local variables and pass these around. Using the Nummer field could be usefull if you want to use it for more than one upload. But it might be better to use an int directly:
upload.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
String ID = "", Image;
int Nummer = 0;
[...]
for (int i = 0; i < files.length; ++i) {
if (files[i].getName().endsWith(".jpg")) {
[...]
try {
new HttpAsyncTask(ID,Image,Integer.toString(Nummer++)).execute("https://....");
} catch (Exception e) {
Log.e("InputStream", e.getMessage());
}
Log.e("PICS", id);
}
}
}
});
public String POST(String url, String ID, String Image, String Nummer) {
InputStream inputStream;
try {
[...]
} catch (Exception e) {
Log.e("InputStream", e.getLocalizedMessage());
}
//int num = Integer.parseInt(Nummer);
//num++;
//Nummer = Integer.toString(num);
return result;
}
public class HttpAsyncTask extends AsyncTask<String, Void, String> {
private final String ID, Image, Nummer;
public HttpAsyncTask(String ID, String Image, String Nummer) {
this.ID = ID;
this.Image = Image;
this.Nummer = Nummer;
}
protected String doInBackground(String... urls) {
return POST(urls[0], ID, Image, Nummer);
}
protected void onPostExecute(String result) {
[...]
}
}
In My suggestion Dont call Asynctask directly from for loop because there are no any monitor on we can set for which image selected.
So Go through below steps:
1) In for loop get all images ID,Name and number and store it to ArrayList
2) Check ArrayList first is empty or not
if not then get first position ID, Image and number
call new HttpAsyncTask(ID,Image,Integer.toString(Nummer++)).execute("https://....");
3) In HttpAsyncTask onPostExecute(String result) method
first remove first position data
then create
for loop (i=0;i<ArrayList.Size();i++) {
ID=ArrayList first position data ID
Image=ArrayList first position data IMAGE
number=ArrayList first position data number
Call new HttpAsyncTask(ID,Image,Integer.toString(Nummer++)).execute("https://....");
}
So here first Image send by then after second then after third up to your list not empty and every time different image selected.
Thats it...

Can't conenct to a url

I have a link where I'm providing 2 parameters and a php server side script is executing a query and writing them to my databae.
The problem is that in this specific case, it seems that I can't connect to teh url.
Here is my button xml file:
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:includeFontPadding="#+id/btnSubmit"
android:text="#string/btnSubmit"
android:onClick="submitNewJ"
/>
Here is my click "listener":
public void submitNewJ(View view){
new submitJ().execute();
}
And here is the submitJ code:
public class submitJ extends AsyncTask<Void, Integer, Void>{
#Override
protected Void doInBackground(Void... params) {
try{
String encodedName = URLEncoder.encode(Name,"UTF-8");
String encodedBody = URLEncoder.encode(Body,"UTF-8");
URL url = new URL("http://site123.com/android/J/sJ.php?Name="+encodedName+"&Body="+encodedBody);
URLConnection urlConnection = url.openConnection();
#SuppressWarnings("unused")
InputStream in = urlConnection.getInputStream();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
And here is how I'm getting the strings:
EditText jN;
EditText jB;
String Name = "";
String Body = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_joke);
jN = (EditText)findViewById(R.id.newName);
jB = (EditText)findViewById(R.id.newBody);
Name = jN.getText().toString();
Body = jB.getText().toString();
}
It seems that the connection is not working here(even when I'm using the same code in otehr activities). Where am I mistaking?
I know that I'm missing something super small, but I'm not able to spot it.
P.s. My service and link are 100% tested and working.
The site you have in the example is probabbly for reference reasons, but mind that if it is using https protocol and you're reffering to a http, you will not get redirected to the correct link.
Everything in your code seems fine to me.
Just make sure that you're using the correct protocol.
You need to move these lines from onCreate() method to doInBackground() method,
Name = jN.getText().toString();
Body = jB.getText().toString();
put them inside the doInBackground() method like below,
public class submitJ extends AsyncTask<Void, Integer, Void>{
#Override
protected Void doInBackground(Void... params) {
try{
String Name = jN.getText().toString(); // move here and delete from the class
String Body = jB.getText().toString();
String encodedName = URLEncoder.encode(Name,"UTF-8");
String encodedBody = URLEncoder.encode(Body,"UTF-8");
URL url = new URL("http://site123.com/android/J/sJ.php?Name="+encodedName+"&Body="+encodedBody);
URLConnection urlConnection = url.openConnection();
#SuppressWarnings("unused")
InputStream in = urlConnection.getInputStream();
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}

Categories