I'm writing an Android client that works with a Google App Engine backend. The client compiles and runs just fine, but the execute() method is yet unidentified.
My AsyncTask's doInBackground(...):
#Override
protected String doInBackground(Pair<Context, String>... params) {
context = params[0].first;
if(mService == null) {
DatastoreRequests.Builder builder = new DatastoreRequests.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), null)
.setRootUrl(myRootUrl);
mService = builder.build();
}
try {
return String.valueOf(mService.sayHi(params[0].second).execute()); // 'execute' is red colored
} catch (IOException e) {
return e.getMessage();
}
}
sayHi:
public DatastoreRequests.SayHi sayHi(String name) throws IOException {
DatastoreRequests.SayHi result = new DatastoreRequests.SayHi(name);
this.initialize(result);
return result;
}
As I mentioned, the code does run, and for example, when removing the String.valueOf() method - the build fails. So, why is it unrecognized? Any explanation for such behavior and how to solve it? Thanks.
I'm working with IntelliJ IDEA 2016.1.1.
Related
I am working on a project right now where I use jsoup in a class with the function retrieveMedia in order to return an ArrayList filled with data from the webpage. I run it in a thread since you shouldn't be connecting to URLs from the main thread. I run it and join it. However, it doesn't work (I tested the same code in Eclipse separate from Android Studio and it worked fine). It seems that no matter what I do I can't get jsoup to connect to the webpage. Below is my class MediaRetriever.
public class MediaRetreiever {
public ArrayList<Media> retrieveMedia() {
ArrayList<Media> mediaOutput = new ArrayList<Media>(); //Store each scraped post
Thread downloadThread = new Thread(new Runnable() {
public void run() {
Document doc = null;
try {
doc = Jsoup.connect(<Website Im connecting to>).timeout(20000).get();
} catch (IOException e) {
System.out.println("Failed to connect to webpage.");
mediaOutput.add(new Media("Failed to connect", "oops", "", "oh well"));
return;
}
Elements mediaFeed = doc.getElementById("main").getElementsByClass("node");
for (Element e : mediaFeed) {
String title, author, imageUrl, content;
title=e.getElementsByClass("title").text().trim();
author=e.getElementsByClass("content").tagName("p").select("em").text().trim();
content=e.getElementsByClass("content").text().replace(author,"").trim();
Media media = new Media(title, author, "", content);
mediaOutput.add(media);
}
}
});
downloadThread.start();
try {
downloadThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mediaOutput;
}
}
Running this class's method from another class and it doesn't ever connect. Any ideas?
Since you say that the problem persists only in Android, it looks like that you should add the user agent string to your request - first get the user agent string of a browser that displays correctly the site, and then add it to the request:
doc = Jsoup.connect(<Website Im connecting to>)
.userAgent("your-user-agent-string")
.timeout(20000).get();
And as a sidenote - if you are catching exception, don't print your own error message - print the original message, it may be very useful.
I am using OkHttp 3.1.2.
I've created file upload similar to the original recipe which is found here: https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/PostMultipart.java
I can't find example how to abort an upload of large file upon user request. I mean not how to get the user request but how to tell the OkHttp to stop sending data.
So far the only solution that I can imagine is to use custom RequestBody, add an abort() method and override the writeTo() method like this:
public void abort() {
aborted = true;
}
#Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = null;
try {
source = Okio.source(mFile);
long transferred = 0;
long read;
while (!aborted && (read = source.read(sink.buffer(), SEGMENT_SIZE)) != -1) {
transferred += read;
sink.flush();
mListener.transferredSoFar(transferred);
}
} finally {
Util.closeQuietly(source);
}
}
Is there any other way?
It turns out it is quite easy:
Just hold reference to the Call object and cancel it when needed like this:
private Call mCall;
private void executeRequest (Request request) {
mCall = mOkHttpClient.newCall(request);
try {
Response response = mCall.execute();
...
} catch (IOException e) {
if (!mCall.isCanceled()) {
mLogger.error("Error uploading file: {}", e);
uploadFailed(); // notify whoever is needed
}
}
}
public void abortUpload() {
if (mCall != null) {
mCall.cancel();
}
}
Please note that when you cancel the Call while uploading an IOException will be thrown so you have to check in the catch if it is cancelled (as shown above) otherwise you will have false positive for error.
I think the same approach can be used for aborting download of large files.
I am using the Kohsuke GitHub-API to connect to the GitHub from my Java (server-side) application and I wanted to use the OkHttp's ability to cache responses from the GitHub. This worked perfectly when I wrote a test for it, but it doesn't work in the application itself and I don't have a clue why that is. I have managed to trace the problem back to the creation of the URLConnection object that is created with its useCache variable set to false, but I cannot figure out why. Does it maybe have something to do with the server configuration or something like that?
I would appreciate any ideas or even a nudge in any direction, because frankly I don't have any ideas left... Thanks
Provider:
public class GitHubProvider implements Provider<GitHub> {
#Override
public GitHub get() {
GitHub gitHub = null;
HttpResponseCache cache = null;
OkHttpClient okHttpClient = new OkHttpClient();
File cacheDir = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
try {
cache = new HttpResponseCache(cacheDir, 10L * 1024 * 1024);
} catch (IOException e) {
// NOTHING
}
okHttpClient.setResponseCache(cache);
try {
gitHub = GitHub.connectUsingPassword("user", "password");
} catch (Exception e) {
// NOTHING
}
gitHub.setConnector(new OkHttpConnector(okHttpClient));
return gitHub;
}
}
Test (works):
#RunWith(JukitoRunner.class)
public class SoftwareComponentServiceTest {
public static class Module extends TestModule {
#Override
protected void configureTest() {
bind(GitHub.class).toProvider(GitHubProvider.class);
}
}
#Inject
GitHub gitHub;
#Test
public void testInjectedGitHubResponseCache() {
try {
GHUser ghUser = gitHub.getUser("user");
GHRepository repository = ghUser.getRepository("repository");
int limit = gitHub.getRateLimit().remaining;
repository.getFileContent("README.md");
assertEquals(limit - 1, gitHub.getRateLimit().remaining);
repository.getFileContent("README.md");
assertEquals(limit - 1, gitHub.getRateLimit().remaining);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Service that is used in the application (doesn't work):
#Singleton
#RequiresAuthentication
public class SoftwareComponentService {
#Inject
GitHub gitHub;
public List<SoftwareComponent> findAll() {
List<SoftwareComponent> softwareComponentList = new ArrayList<SoftwareComponent>();
try {
GHUser ghUser = gitHub.getUser("user");
List<GHRepository> repositories = ghUser.listRepositories().asList();
for (int i = 0; i < repositories.size(); i++) {
GHRepository repository = repositories.get(i);
if (!repository.getName().startsWith("sc_")) {
continue;
}
softwareComponentList.add(new SoftwareComponent(repository.getName(), repository.getDescription()));
}
} catch (IOException e) {
// NOTHING
}
return softwareComponentList;
}
}
The reason
The URLConnection object is created with its useCache variable set to false because its defaultUseCaches variable is also set to false by the Tomcat server at the time of initialization. Tomcat does this through its JreMemoryLeakPreventionListener class because reading resources from JAR files using java.net.URLConnections can sometimes result in the JAR file being locked (urlCacheProtection variable). The workaround they implemented to solve this problem was to disable URLConnection caching by default (!?!?).
The solution
The workaround to this workaround is to create a dummy URLConnection and use its setDefaultUseCaches() method to change the default value of every subsequently created URLConnection (as suggested by Jesse Wilson).
URL url = new URL("jar:file://dummy.jar!/");
URLConnection uConn = url.openConnection();
uConn.setDefaultUseCaches(true);
Big thanks to Jesse Wilson for pointing me in the right direction!
There's an insane method called URLConnection.setDefaultUseCaches() that could be doing it globally. That's an instance method that works like a static method: it sets the property for everyone.
I am in a situation where i need to create a simple launcher that allows me too select which web address to launch with different versions of java. I have researched several sites. Having the user change windows settings is not an option as it would generate too many support calls or user does not have priviliges. What i want is a programming way to set or change the version of java being used to launch a url. I have seen proprietary systems make launchers with a gui that allows you to change address and java version and then launch it in a browser. I am new to development and obviously having trouble understanding which techniques to use.
Will you please point me in the right direction. I am comfortable writing guis(in c# or java) I just need to know how to write the function for the launch button?
function launchbutton(url, javaversion)
{
If (javaversionselect == 1.3)
{
open url in default browser running java version 1.3
}
If (javaversionselect == 1.4)
{
open url in default browser running java version 1.4
}
If (javaversionselect == 1.5)
{
open url in default browser running java version 1.5
}
If (javaversionselect == 1.6)
{
open url in default browser running java version 1.6}
}
Bare Bones Browser Launcher will detect the java version and use the appropriate calls.
http://www.centerkey.com/java/browser/
You wan't be able to change the version of java that for example 'IE' or 'Chrome' use from withing your application, your only solutions would be to use some kind of embedded browser
jBrowser
XPCOM from Mozilla
Browse source and look on how Eclipse embedded their browser
You can write an applet that does it. Compile something like this, using javac -target 1.3:
public class Redirector
extends Applet {
#Override
public void start() {
String newURL;
Package pkg = Object.class.getPackage();
if (pkg.isCompatibleWith("1.7")) {
newURL = "java17.html";
} else if (pkg.isCompatibleWith("1.6")) {
newURL = "java16.html";
} else if (pkg.isCompatibleWith("1.5")) {
newURL = "java15.html";
} else if (pkg.isCompatibleWith("1.4")) {
newURL = "java14.html";
} else {
newURL = "java13.html";
}
try {
getAppletContext().showDocument(new URL(newURL));
} catch (MalformedURLException e) {
showStatus(e.toString());
}
}
}
If you really want let the user choose the Java version for himself, you can create UI elements in your applet for that:
public class Redirector
extends Applet
implements ActionListener {
private Choice list;
#Override
public void init() {
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
list = new Choice();
list.add("1.7");
list.add("1.6");
list.add("1.5");
list.add("1.4");
list.add("1.3");
Button button = new Button("Launch");
button.addAtionListener(Redirector.this);
add(new Label("Java version:"));
add(list);
add(button);
}
});
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void actionPeformed(ActionEvent event) {
String newURL;
String version = list.getSelectedItem();
if (version.equals("1.7")) {
newURL = "java17.html";
} else if (version.equals("1.6")) {
newURL = "java16.html";
} else if (version.equals("1.5")) {
newURL = "java15.html";
} else if (version.equals("1.4")) {
newURL = "java14.html";
} else {
newURL = "java13.html";
}
try {
getAppletContext().showDocument(new URL(newURL));
} catch (MalformedURLException e) {
showStatus(e.toString());
}
}
}
I did a mistake that apparently can be solved only by uninstalling and then installing my app again.
I delivered a message to the users, but no-one seems to uninstall it.
AFAIK, if I change the certificate file, the play store won't let me upload the application, and
obviously I don't want to upload a new app.
Is there a way to force uninstall in order to update?
Thanks!
There's no killswitch to remotely force uninstalls (that'd be a security nightmare). What you can do is publish a fixed version on Google Play, and wait for users to upgrade.
I don't know if this can help you but i had the same problem. The solution for me is that i check the app version every time the user opens it and compare it with a version code stored on apache server (in a checkversion.php file).
If versions doesn't match, i show a not cancelable dialog that ask the user to go to market and download the update.
Here is an example (keep in mind that i use Volley library to handle connections):
public class UpdateManager {
private Activity ac;
private HashMap<String,String> params;
public UpdateManager(Activity ac) {
this.ac = ac;
}
public void checkForUpdates() {
Log.d("UpdateManager","checkForUpdates() - Started...");
params = new HashMap<String,String>();
params.put("request","checkforupdates");
try {
params.put("versioncode", String.valueOf(ac.getPackageManager().getPackageInfo(ac.getPackageName(), 0).versionCode));
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (Helper.isInternetAvailable(ac)) { //this is a class i made to check internet connection availability
checkAppVersion();
} else { Log.d("UpdateManager","CheckForUpdates(): Impossible to update version due to lack of connection"); }
}
private void checkAppVersion() {
Log.d("UpdateManager","checkAppVersion() - Request started...");
JsonObjectRequest req = new JsonObjectRequest("http://yourserver/checkappversion.php", new JSONObject(params),
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
if (response != null && response.has("result")) {
try {
Log.d("UpdateManager","checkAppVersion() - Request finished - Response: "+response.getString("result"));
if (response.getString("result").matches("updaterequested")) { //Update requested. Show the relative dialog
Log.d("UpdateManager","Update requested");
askUserForUpdate();
}
else if (response.getString("result").matches("current")) { //Same version. Do nothing
Log.d("UpdateManager","Version is up to date");
}
else if (response.getString("result").matches("error")) { //You can return an error message if error occurred on server
Log.d("UpdateManager","checkappversion Error - "+response.getString("error"));
}
VolleyLog.v("Response:%n %s", response.toString(4));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("UpdateManager","Volley Error - "+error.getMessage());
}
});
req.setRetryPolicy(new DefaultRetryPolicy(60000,0,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
ConnectionController.getInstance().addToRequestQueue(req);
}
public void askUserForUpdate() {
final Dialog diag = new Dialog(ac);
diag.requestWindowFeature(Window.FEATURE_NO_TITLE);
diag.setContentView(R.layout.updatemanager_requestupdate_dialog);
diag.setCancelable(false);
diag.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
TextView t = (TextView)diag.findViewById(R.id.requestupdate_dialog_main_text);
ImageView im_ok = (ImageView)diag.findViewById(R.id.requestupdate_dialog_ok);
ImageView im_canc = (ImageView)diag.findViewById(R.id.requestupdate_dialog_canc);
t.setText(ac.getResources().getString(R.string.update_manager_askuserforupdate));
im_canc.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
diag.dismiss();
ac.finish();
}
});
im_ok.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://details?id="+ac.getPackageName()));
diag.dismiss();
ac.startActivity(intent);
ac.finish();
}
});
diag.show();
}
}
You can then use it when your main activity (or maybe login activity) starts like this:
UpdateManager updateManager = new UpdateManager(MainActivity.this); //i assume MainActicity as the calling activity
updateManager.checkForUpdates();
Obviously this has to be implemented into the application code so, the first time, you have to rely only on the user to manually upgrade it. But this can help if you have the same problem in the future.
This is an extract from my personal code so you have to rearrange it to your needings. Hope this helps someone.
Users should be able to go to Settings > Applications > Manage Applications and select the application to be removed. I've never seen a case where the application can't be removed this way, except in the case of built-in applications which require a rooted device to remove.