Implements of thread in Android doesn't work - java

I'm writing a basic application in Android, the application will be connected to MySql server by quest in PHP, in Android Internet connection have to make in diffrent thread, so I create class which implements Runnable interface.
package com.company.opax.loginmysql;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
/**
* Created by opax on 30.08.2015.
*/
public class HttpPostMethod implements Runnable{
private String fileInHost;
private ArrayList<PostParameters> postParameterses;
private StringBuffer postResult;
public HttpPostMethod(String fileInHost, ArrayList<PostParameters> postParameterses){
this.fileInHost = fileInHost;
this.postParameterses = new ArrayList<PostParameters>(postParameterses);
}
public String getResult() {
return postResult.toString();
}
#Override
public void run() {
try {
String urlParameters = generateParameters();
URLConnection conn = initializeUrlConnection();
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
writer.write(urlParameters);
writer.flush();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null) {
postResult.append(line);
}
writer.close();
reader.close();
} catch (IOException e) {
Log.e("Exception", this.getClass().getName() + " name: " + e.toString());
}
}
private URLConnection initializeUrlConnection() throws MalformedURLException {
URL url = new URL(fileInHost);
URLConnection conn;
try {
conn = url.openConnection();
conn.setDoOutput(true);
}catch(IOException e){
throw new MalformedURLException();
}
return conn;
}
private String generateParameters(){
StringBuffer finishPostQuery = new StringBuffer();
for(PostParameters p : postParameterses){
finishPostQuery.append(p.getNameParam());
finishPostQuery.append("=");
finishPostQuery.append(p.getValueParam());
finishPostQuery.append("&");
}
if(!finishPostQuery.toString().equals("login=seba&password=pass&"))
throw new AssertionError("blad generatora zapytania: " + finishPostQuery);
return finishPostQuery.toString();
}
}
and login class:
public class Login {
private User user;
private final String paramLogin = "login";
private final String paramPass = "password";
public Login(User user){
this.user = user;
}
public boolean tryLogin(){
try{
ArrayList<PostParameters> postParameterses = new ArrayList<>();
postParameterses.add(new PostParameters(paramLogin, user.getUserName()));
postParameterses.add(new PostParameters(paramPass, user.getUserPass()));
HttpPostMethod httpPostMethod = new HttpPostMethod("http://blaba.php", postParameterses);
httpPostMethod.run();
Log.i("bla", httpPostMethod.getResult());
} catch (Exception e) {
Log.i("Exception", e.toString());
}
return false;
}
}
I'm trying to connect in other thread, but I still have an error: 'android.os.NetworkOnMainThreadException'
I would be grateful for the all suggestion what I do wrong.

Instead of:
httpPostMethod.run();
do:
new Thread(httpPostMethod).start();
In case your login call failed for some reasons (timeout, wrong login), you should report that somehow to user - this is what AsyncTask class is for. It allows you to run background code in doInBackkground, and after network operation ends - in onPostExecute you can execute UI related stuff - like show errors/results.

I suggest you two things.
First use AsyncTask instead of pure java threads.
But the main advice is to use a library that make http requests.
I like to use Retrofit, it may handle all request and thread part for you, but there are others.

Related

Is there a way to put a kind of identificator to asychronous requests?

I have a server and a client that sends requests. I don't need to identify the requests when it works in synch mode. But in asynch mode each request must have an identificator, so I could be sure that the response corresponds to exact request. The server is not to be updated, I have to put the identificator in the client's code. Is there a way do do it? I can't find out any.
Here is my main class. I guess all must be clear, the class is very simple.
public class MainAPITest {
private static int userId = 0;
private final static int NUM_OF_THREADS = 10;
private final static int NUM_OF_USERS = 1000;
public static void main(String[] args) {
Security.addProvider(new GammaTechProvider());
ExecutorService threadsExecutor = Executors.newFixedThreadPool(NUM_OF_THREADS);
for (int i = 0; i < NUM_OF_USERS; i++) {
MyRunnable user = new MyRunnable();
userId++;
user.uId = userId;
threadsExecutor.execute(user);
}
threadsExecutor.shutdown();
}
}
class MyRunnable implements Runnable {
int uId;
#Override
public void run() {
try {
abstrUser user = new abstrUser();
user.setUserId(uId);
user.registerUser();
user.chooseAndImplementTests();
user.revokeUser();
} catch (Exception e) {
e.printStackTrace();
}
}
}
User class describes the user's behaviour. It is long enough, idk if it is needed here. User runs a number of random tests. Each test has its own class that extends abstract test class, where the http connection is established:
import org.json.JSONObject;
import javax.xml.bind.DatatypeConverter;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public abstract class abstractRESTAPITest {
protected String apiUrl;
public abstractRESTAPITest() {
}
protected byte[] sendRequest(JSONObject jsonObject) throws IOException {
return this.sendRequest(jsonObject, (String) null, (String) null);
}
protected byte[] sendRequest(JSONObject jsonObject, String username, String password) throws IOException {
HttpURLConnection httpURLConnection = (HttpURLConnection) (new URL(this.apiUrl)).openConnection();
if (username != null && password != null) {
String userPassword = username + ":" + password;
httpURLConnection.setRequestProperty("Authorization", "Basic " + DatatypeConverter.printBase64Binary(userPassword.getBytes()));
}
httpURLConnection.setRequestProperty("Content-Type", "application/json");
httpURLConnection.setDoOutput(true);
DataOutputStream dataOutputStream = new DataOutputStream(httpURLConnection.getOutputStream());
dataOutputStream.write(jsonObject.toString().getBytes());
dataOutputStream.flush();
System.out.println("REST send: " + jsonObject.toString());
if (httpURLConnection.getResponseCode() != 200) {
System.out.println("REST send error, http code " + httpURLConnection.getResponseCode() + " " + httpURLConnection.getResponseMessage());
throw new IOException();
} else {
byte[] responseBody = null;
StringBuilder data = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
String line = "";
while ((line = br.readLine()) != null) {
data.append(line);
responseBody = data.toString().getBytes();
}
if (br != null) {
br.close();
}
return responseBody;
}
}
public abstract boolean test();
}
Now I am trying to transform the httpUrlConnection part of the code into a kind of this.
Jsonb jsonb = JsonbBuilder.create();
var client = HttpClient.newHttpClient();
var httpRequest = HttpRequest.newBuilder()
.uri(new URI(apiUrl))
.version(HttpClient.Version.HTTP_2)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonb.toJson(jsonObject)))
.build();
client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString());
It must send a JSON request and receive JSON response. HttpClient, introduced in Java11, has sendAsync native method, so I try to use it. But I don't understand fully how it works, so I have no success.

Display real time data from external website in Swing interface?

I've tried googling the web but every question seems to address web development. I'm simply wondering if it is even possible to fetch data from internet (game results and in game events) that is updated every second ,or every 10 second and so on ,from a website that's not mine and to display it in a Java desktop client with the Swing library interface? And if yes, what is the best method?
ThankYou
Yes, you can do it. You should use java.net package to work with network.
Data fetching depends on the site from which you are going to fetch data, for example:
If site have API, like Stack Overflow, you should use it.
If data is presented on the page, you can use parser like jsoup (if page is html, of course)
I get stock data when requested, rather than on a timer, but you can look at my code and see how I get the stock data.
Here's what the JPanel looks like. It's the panel on the right.
This is the HistoricalDataRunnable class.
package com.ggl.stock.picker.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.swing.SwingUtilities;
import com.ggl.stock.picker.model.Company;
import com.ggl.stock.picker.model.StockDay;
import com.ggl.stock.picker.model.StockHistory;
import com.ggl.stock.picker.model.StockPickerModel;
import com.ggl.stock.picker.view.StockPickerFrame;
public class HistoricalDataRunnable implements Runnable {
private static final String URLString =
"http://www.google.com/finance/historical?output=csv&q=";
private Company company;
private StockPickerFrame frame;
private StockPickerModel model;
public HistoricalDataRunnable(StockPickerFrame frame,
StockPickerModel model, Company company) {
this.frame = frame;
this.model = model;
this.company = company;
}
#Override
public void run() {
InputStream is = null;
BufferedReader br = null;
try {
String symbol = company.getStockSymbol();
URL url = new URL(URLString + symbol);
URLConnection hc = url.openConnection();
hc.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; "
+ "Intel Mac OS X 10.4; en-US; rv:1.9.2.2) "
+ "Gecko/20100316 Firefox/3.6.2");
is = hc.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
processCSVFile(br);
} catch (MalformedURLException e) {
e.printStackTrace();
String message = e.getMessage();
message = "<html>" + message;
setMessageLabel(message);
} catch (IOException e) {
String message = e.getMessage();
message = "<html>" + message;
setMessageLabel(message);
} finally {
closeReaders(is, br);
}
}
private void processCSVFile(BufferedReader br) throws IOException {
String line = "";
int count = 0;
StockHistory history = new StockHistory(company);
while ((line = br.readLine()) != null) {
if (count > 0) {
StockDay stockDay = createStockDay(line);
if (stockDay != null) {
history.addStockDay(stockDay);
}
}
count++;
}
if (history.calculateNumbers()) {
model.addStockHistory(history);
addStockHistory();
setMessageLabel(" ");
} else {
String message = "<html>There is no data for "
+ company.getCompanyName();
setMessageLabel(message);
}
}
private StockDay createStockDay(String line) {
String[] parts = line.split(",");
if (parts[1].equals("-"))
return null;
double open = Double.valueOf(parts[1]);
double high = Double.valueOf(parts[2]);
double low = Double.valueOf(parts[3]);
double close = Double.valueOf(parts[4]);
long volume = Long.valueOf(parts[5]);
return new StockDay(parts[0], open, high, low, close, volume);
}
private void addStockHistory() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.addStockHistory();
}
});
}
private void setMessageLabel(final String text) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setMessageLabel(text);
;
}
});
}
private void closeReaders(InputStream is, BufferedReader br) {
try {
if (br != null)
br.close();
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This class makes a URL connection with Google, and returns the historical stock information. This information is captured in a StockHistory instance, and stored in the StockPickerModel instance.
The User-Agent property is set to simulate a browser. Some web sites don’t allow programs to access their web server. By setting the User-Agent property, you can pretend to be a web browser. Your program should respect the web server, and not submit too many requests. How much is too many depends on the web server.
This class also updates the view. The only way we’ll know when the request is complete is when the HistoricalDataRunnable method receives a response from Google. It’s up to this class to update the model and the view.
Since this class is run in a separate thread, we have to call the SwingUtilities invokeLater method to execute any Swing GUI commands. That’s why the addStockHistory and setMessageLabel methods are enclosed in an invokeLater method.
This class displays any errors in the JLabel message. The stock might not be kept by Google. The stock may not have any stock day values. These error messages are displayed.
To see the rest of the code, take a look at my Stock Picker Using Java Swing article.

Cannot send data outside runnable thread

I'm having some difficulties with my app. I created a class with functions to handle HTTP POST by starting a thread, the issue is that I cannot send data outside the thread!!! The class has a variable and I want to set value to that variable when the thread is running, please help.
Here is the code:
package com.mypackage;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.json.JSONObject;
import org.json.JSONException;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Handler;
import android.util.Log;
public class HandleJSON {
private String urlString = null;
private int errorcode ;
public int getErrorcode(){return errorcode;}
public volatile boolean parsingComplete = true;
public HandleJSON(String url){
//saving the URL
this.urlString = url;
}
#SuppressLint("NewApi")
public void readAndParseJSON(String in) {
try {
parsingComplete = false;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void fetchJSON(){
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
conn.connect();
//receiving message from server
InputStream stream = conn.getInputStream();
String data = convertStreamToString(stream);
// JSON thing
try{
JSONObject obj = new JSONObject(data);
//THIS IS THE ISSUE, I'm setting here the errorcode which should set the superclass variable "errorcode" so I can use "getErrorCode" to retrieve the code, but it seems like the thread does not respond after thread starts;
errorcode = obj.getInt("error_code");
}
catch(JSONException e) {
Log.e("Catch error", e.toString());
}
readAndParseJSON(data);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}
If I understand correctly, you want to get data between a non-main thread and elsewhere. In which case you may want to create another class that has a public static variable. This is such that everyone permitted by the modifier in question (private, protected, public) can access the same content. Be careful as, if poorly managed, your code may function differently or not all on systems with execution speeds other than yours.
In such case, an anonymous daemon thread is a little tricky.
You can define a concrete class extending Thread, define data structures in it and provide the interface to access your data structures. Such as here below.
class MyThread extends Thread {
private JSONObject obj;
public void run() {
// Your parsing code goes here
// Such as obj = xxxxxx;
}
public JSONObject getData() {
return obj;
}
}
Of course, you should consider the concurrent risks when manipulating inner data structures.
The issue solved, I used AsyncTask instead and passed the variables to onPostExecute(String) which done the trick.

Programmatically Fetching Google+ status updates

Is there a way to programmatically fetch Google+ updates for a user's profile? I can't seem to find much in the documentation at https://developers.google.com/+/api/latest/people and http://developer.android.com/reference/com/google/android/gms/plus/model/people/Person.html about fetching statuses. I would like to fetch the data by making an HTTP request or if there is some sort of SDK for Android that will help me, that would work to.
The API you are looking for is plus.activities.list. This will list the Google+ equivalent of Facebook status updates. The referenced page has example code to get you started.
When accessing the API, you should use the Google API client as documented here.
The following code will be useful to retrieve the Http responses.
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Scanner;
import java.util.zip.GZIPInputStream;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class GooglePlusStatusHelper {
public GooglePlusStatusHelper() {
}
public static void main(String... args) {
GooglePlusStatusHelper googlePlusStatusHelper = new GooglePlusStatusHelper();
try {
googlePlusStatusHelper.tagsUsed();
} catch (IOException e) {
e.printStackTrace();
}
}
private void tagsUsed() throws IOException {
URL url = createQuery("users");
Type dataType = new TypeToken<Wrapper<Status>>(){}.getType();
Status status = executeQuery(url, dataType);
System.out.println(status);
}
private URL createQuery(String inputParam) throws MalformedURLException {
String baseUrl = "http://api.example.com/" + inputParam ;
System.out.println(baseUrl);
URL url = new URL(baseUrl);
return url;
}
private Status executeQuery(URL url, Type clz) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
System.out.println("Response Code:" + conn.getResponseCode());
System.out.println("Response Message:" + conn.getResponseMessage());
System.out.println("TYPE:" + conn.getContentType());
InputStream content = conn.getInputStream();
String encoding = conn.getContentEncoding();
if (encoding != null && encoding.equals("gzip")) {
content = new GZIPInputStream(content);
}
String result = new Scanner(content, "UTF-8").useDelimiter("\\A").next();
content.close();
Gson gson = new Gson();
return gson.fromJson(result, clz);
}
}
Status class :
public class Status {
private int count;
private String status;
......
public String toString() {
String result = "\ncount: " + count +
"\status:" + status;
result = result + "\n------------";
return result;
}
}

Download a file from the internet using java : How to authenticate?

Thanks to this thread How to download and save a file from Internet using Java?
I know how to download a file, now my problem is that I need to authenticate on the sever from which I'm dowloading. It's an http interface to a subversion server. Which field do I need to look up into ?
Using the code posted in the last comment, I get this exception:
java.io.IOException: Server returned HTTP response code: 401 for URL: http://myserver/systemc-2.0.1.tgz
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1305)
at java.net.URL.openStream(URL.java:1009)
at mypackage.Installer.installSystemc201(Installer.java:29)
at mypackage.Installer.main(Installer.java:38)
Thanks,
You extend the Authenticator class and register it. The javadocs at the link explain how.
I don't know if this works with the nio method that got the accepted answer to the question, but it for sure works for the old fashioned way that was the answer under that one.
Within the authenticator class implementation, you are probably going to use a PasswordAuthentication and override the getPasswordAuthentication() method of your Authenticator implementation to return it. That will be the class which is passed the user name and password you need.
Per your request, here is some sample code:
public static final String USERNAME_KEY = "username";
public static final String PASSWORD_KEY = "password";
private final PasswordAuthentication authentication;
public MyAuthenticator(Properties properties) {
String userName = properties.getProperty(USERNAME_KEY);
String password = properties.getProperty(PASSWORD_KEY);
if (userName == null || password == null) {
authentication = null;
} else {
authentication = new PasswordAuthentication(userName, password.toCharArray());
}
}
protected PasswordAuthentication getPasswordAuthentication() {
return authentication;
}
And you register it in the main method (or somewhere along the line before you call the URL):
Authenticator.setDefault(new MyAuthenticator(properties));
The usage is simple, but I find the API convoluted and kind of backwards for how you typically think about these things. Pretty typical of singleton design.
This is some code I wrote that fetches a website and displays the contents to System.out. It uses Basic authentication:
import java.net.*;
import java.io.*;
public class foo {
public static void main(String[] args) throws Exception {
URL yahoo = new URL("http://www.MY_URL.com");
String passwdstring = "USERNAME:PASSWORD";
String encoding = new
sun.misc.BASE64Encoder().encode(passwdstring.getBytes());
URLConnection uc = yahoo.openConnection();
uc.setRequestProperty("Authorization", "Basic " + encoding);
InputStream content = (InputStream)uc.getInputStream();
BufferedReader in =
new BufferedReader (new InputStreamReader (content));
String line;
while ((line = in.readLine()) != null) {
System.out.println (line);
}
in.close();
}
Problems with the above code:
This code isn't production-ready (but it gets the point across.)
The code yields this compiler warning:
foo.java:11: warning: sun.misc.BASE64Encoder is Sun proprietary API and may be removed in a future release
sun.misc.BASE64Encoder().encode(passwdstring.getBytes());
^ 1 warning
One really should use the Authenticator class, but for the life of me, I could not figure out how and I couldn't find any examples either, which just goes to show that the Java people don't actually like it when you use their language to do cool things. :-P
So the above isn't a good solution, but it does work and could easily be modified later.
Write your overriding class for Authenticator:
import java.net.Authenticator;
import java.net.PasswordAuthentication;
public class MyAuthenticator extends Authenticator {
private static String username = "";
private static String password = "";
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication (MyAuthenticator.username,
MyAuthenticator.password.toCharArray());
}
public static void setPasswordAuthentication(String username, String password) {
MyAuthenticator.username = username;
MyAuthenticator.password = password;
}
}
Write your main class:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.URL;
public class MyMain{
public static void main(String[] args) {
URL url;
InputStream is = null;
BufferedReader br;
String line;
// Install Authenticator
MyAuthenticator.setPasswordAuthentication("Username", "Password");
Authenticator.setDefault (new MyAuthenticator ());
try {
url = new URL("Your_URL_Here");
is = url.openStream(); // throws an IOException
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (MalformedURLException mue) {
mue.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (is != null) is.close();
} catch (IOException ioe) {
// nothing to see here
}
}
}
}
Have you tried building your URL in the form http://user:password#domain/path?
I would suggest checking out HttpClient from apache http://hc.apache.org/httpclient-3.x/ it makes downloading/authenticating very easy
This open source library, http://spnego.sourceforge.net, also has some examples on how to use it's SpnegoHttpURLConnection class.
One of the constructors in the class allows you to pass-in a username and password.
Take a look at the class's java doc for the examples.

Categories