Hello i am creating an android application , and i have on my website about more than 1500 photos that i want to display on a ListView using an Array adapter
One solution i found is downloading the images from a URL link i have .
Here is the stacktrace
My problem is that i get an Out of Memory exception
: E/AndroidRuntime(1123): FATAL EXCEPTION: Thread-79
: E/AndroidRuntime(1123): Process:
android.quotations, PID: 1123
** : E/AndroidRuntime(1123): java.lang.OutOfMemoryError : E/AndroidRuntime(1123):
at** android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
: E/AndroidRuntime(1123): at
android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:613)
: E/AndroidRuntime(1123): at
android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:589)
: E/AndroidRuntime(1123): at
android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:422)
: E/AndroidRuntime(1123): at
android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:840)
: E/AndroidRuntime(1123): at
android.graphics.drawable.Drawable.createFromStream(Drawable.java:791)
: E/AndroidRuntime(1123): at
com.c.fragments.AuthorImageFragment.loadImageFromWebOperations(AuthorImageFragment.java:77)
: E/AndroidRuntime(1123): at
com.c.fragments.AuthorImageFragment.access$0(AuthorImageFragment.java:72)
: E/AndroidRuntime(1123): at
com.c.fragments.AuthorImageFragment$1.run(AuthorImageFragment.java:109)
and here is the code from the adapter:
private ImageView imageDetail(View v, int resId, Drawable drawable) {
ImageView value = (ImageView) v.findViewById(resId);
BitmapDrawable draw = (BitmapDrawable)drawable;
// value.setAdjustViewBounds(true);
Bitmap bmp=draw.getBitmap();
// value.setLayoutParams(new android.widget.TableRow.LayoutParams((width/4), (height/4)));
value.setImageBitmap(bmp);
return value;
}
Thread networkThread = new Thread() {
#Override
public void run() {
Author author;
// This is just a test i want to do :)))
for (int i=0;i<=1000;i++){
author=new Author();
try {
author.setAuthorImage(loadImageFromWebOperations("http://mySite/Directory/images/"+5+".jpg",i));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
list.add(author);
}
getActivity().runOnUiThread (new Runnable(){
public void run() {
adapter= new AuthorImageAdapter(getActivity().getApplicationContext(),list);
}
});
}
}; networkThread.start();
****Here is the Method i use to retrieve the Image****
private Drawable loadImageFromWebOperations(String url,int id) throws MalformedURLException, IOException
{ InputStream is=null;
try{
is = (InputStream) new java.net.URL(url).getContent();
LOGGER.info("Drawable -----");
Drawable d = Drawable.createFromStream(is, id+".jpg");
return d;
}catch (Exception e) {
// log Exception
LOGGER.info("Exception "+e.toString());
return null;
}
finally {
if (is!=null){
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
LOGGER.info("Exception "+e.toString());
// log Exception
return null;
}
}
}
}
any help would be appreciated ..
Best regards :)))
Now to help more i will add the code i use to retrieve the images .
There's no way you're going to be able to hold that many images in memory. I'd suggest that you download the images to local file storage and then in your Adapter when you want to actually draw the item that has the image, you should kick off a Loader that will load the image from disk on-demand. Sorry, there's just not enough memory to store that many images at once.
A more advanced strategy is to insert a cache using WeakReferences into the loading process. You load the image from disk and insert into something like a HashMap> and see if the image you want is in there first and if not, then do a load from disk as you normally would.
If you want to get architecturally really fancy what happens is the WeakReference cache I list above, try to load from disk, but if the file isn't present on disk only then load from the network. This then becomes a two-tier cache memory, then disk, before finally hitting the web.
Related
I have looked in so many places on a lead on how or if it is possible to view images uploaded to cloudinary, by a specific tag through Android studio app i am trying to build.
I was able to implement the upload option by user, with adding a tag to the images, and public id, also retrieving these information, but i cant find anything on how to view these images, for example i want the app to be able to view all images with a specific tag ( username ) to the user that uploaded the pictures, and could delete them ? and also view other images uploaded by other user with no other permission.
Is it possible and how !?
I ended up with this code, and i encountered a problem;
#Override
public void onClick(View v) {
new JsonTask().execute("http://res.cloudinary.com/cloudNAme/video/list/xxxxxxxxxxxxxxxxxxx.json");
// uploadExtract();
}
});
public class JsonTask extends AsyncTask<String ,String,String> {
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
In the log i get the following;
03-28 12:36:14.726 20333-21459/net.we4x4.we4x4 W/System.err: java.io.FileNotFoundException: http://res.cloudinary.com/we4x4/video/list/3c42f867-8c3a-423b-89e8-3fb777ab76f8.json
i am not sure if my understanding is correct of the method or i am doing something wrong ? since in the Admin API Docs. or cloudinary the syntax for the HTML request and also in the suggested page by Nadav:
https://support.cloudinary.com/hc/en-us/articles/203189031-How-to-retrieve-a-list-of-all-resources-sharing-the-same-tag-
this should've returned a JSON ?
The following feature allows you to retrieve a JSON formatted list of resources that which share a common tag:
https://support.cloudinary.com/hc/en-us/articles/203189031-How-to-retrieve-a-list-of-all-resources-sharing-the-same-tag-
Note that image removal will coerce you to use server-side code (e.g. JAVA), since deleting via Cloudinary requires a signature that is based on your API_SECRET.
I am trying to use NetSuite's suiteTalk java api for writing an interface between our lotus notes system and NetSuite.
The first error thrown by the code was a class def not found error.
for :
sun/security.provider/sun.class
sun/security.provider/sun$1.class
sun/security.provider/NativePRNG.class
I figured out that rt.jar in lotus notes was actually missing this files. So I added these class files from the jdk1.6 i had downloaded separately. Once I fixed that I started getting axis.Faults error.
Here is the simple login code that I am trying to execute from lotus note agent:
public void loginTest(){
NetSuitePortType _port=null;
// In order to use SSL forwarding for SOAP message. Refer to FAQ for details
System.setProperty("axis.socketSecureFactory","org.apache.axis.components.net.SunFakeTrustSocketFactory");
// Locate the NetSuite web service
NetSuiteServiceLocator serviceLocator= new NetSuiteServiceLocator();
//Get the service port
try {
_port=serviceLocator.getNetSuitePort();
} catch (ServiceException e) {
System.out.println("Error in intializing GlobalSuiteTalkSetup");
e.printStackTrace();
}
// Setting client timeout to 2 hours for long running operatotions
((NetSuiteBindingStub) _port).setTimeout(60*60*1000*2);
try {
// Populate Passport object with all login information
Passport passport = new Passport();
RecordRef role = new RecordRef();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
passport.setEmail("username");
passport.setPassword("password.");
role.setInternalId("3");
passport.setRole(role);
passport.setAccount("111111");
// Login to NetSuite
System.out.print("\nLogging into NetSuite");
System.out.print(" Username: " + passport.getEmail());
System.out.print(" Account: " + passport.getAccount());
System.out.print(" password: " + passport.getPassword());
System.out.print(" role: " + passport.getRole());
Status status;
status = (_port.login(passport)).getStatus();
// Process the response
if (status.isIsSuccess() == true)
{
System.out.print("\nThe login was successful and a new session has been created.");
} else
{
// Should never get here since any problems with the
// login should have resulted in a SOAP fault
System.out.print("Login failed");
//System.out.print(getStatusDetails(status));
}
} catch (InvalidVersionFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidCredentialsFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InsufficientPermissionFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExceededRequestLimitFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnexpectedErrorFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidAccountFault e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Error thrown by code:
AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
faultSubcode:
faultString: java.io.IOException
faultActor:
faultNode:
faultDetail:
{http://xml.apache.org/axis/}stackTrace:java.io.IOException
at org.apache.axis.components.net.SunJSSESocketFactory.initFactory(SunJSSESocketFactory.java:88)
at org.apache.axis.components.net.JSSESocketFactory.create(JSSESocketFactory.java:79)
at org.apache.axis.transport.http.HTTPSender.getSocket(HTTPSender.java:191)
at org.apache.axis.transport.http.HTTPSender.writeToSocket(HTTPSender.java:404)
at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:138)
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)
at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
at org.apache.axis.client.Call.invoke(Call.java:2767)
at org.apache.axis.client.Call.invoke(Call.java:2443)
at org.apache.axis.client.Call.invoke(Call.java:2366)
at org.apache.axis.client.Call.invoke(Call.java:1812)
at com.netsuite.webservices.platform_2015_1.NetSuiteBindingStub.login(NetSuiteBindingStub.java:12799)
at Login.loginTest(Unknown Source)
at JavaAgent.NotesMain(Unknown Source)
at lotus.domino.AgentBase.runNotes(Unknown Source)
at lotus.domino.NotesThread.run(Unknown Source)
{http://xml.apache.org/axis/}hostname:
java.io.IOException
at org.apache.axis.AxisFault.makeFault(AxisFault.java:101)
at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:154)
at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
at org.apache.axis.SimpleChain.doVisiting(SimpleChain.java:118)
at org.apache.axis.SimpleChain.invoke(SimpleChain.java:83)
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:165)
at org.apache.axis.client.Call.invokeEngine(Call.java:2784)
at org.apache.axis.client.Call.invoke(Call.java:2767)
at org.apache.axis.client.Call.invoke(Call.java:2443)
at org.apache.axis.client.Call.invoke(Call.java:2366)
at org.apache.axis.client.Call.invoke(Call.java:1812)
at com.netsuite.webservices.platform_2015_1.NetSuiteBindingStub.login(NetSuiteBindingStub.java:12799)
at Login.loginTest(Unknown Source)
at JavaAgent.NotesMain(Unknown Source)
at lotus.domino.AgentBase.runNotes(Unknown Source)
at lotus.domino.NotesThread.run(Unknown Source)
Caused by: java.io.IOException
at org.apache.axis.components.net.SunJSSESocketFactory.initFactory(SunJSSESocketFactory.java:88)
at org.apache.axis.components.net.JSSESocketFactory.create(JSSESocketFactory.java:79)
at org.apache.axis.transport.http.HTTPSender.getSocket(HTTPSender.java:191)
at org.apache.axis.transport.http.HTTPSender.writeToSocket(HTTPSender.java:404)
at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:138)
... 14 more
I found the solution for this issue. For anyone who might get similar issue can get some clue from this solution :
The issue was because of the following statement that I had put in the code.
System.setProperty("axis.socketSecureFactory","org.apache.axis.components.net.SunFakeTrustSocketFactory");
This statement is necessary when using Sun' JVM but since Lotus Notes uses IBM's JVM, setting axis.socketSecureFactory to org.apache.axis.components.net.SunFakeTrustSocketFactory made the system to look for Sun classes which not absent in IBM's JVM.
No need to add the missing classes from Sun JVM to rt.jat as I had done before. Just comment that statement and use the axis path available frpm NetSuite
Don't forget to put the patch in Note's /JVM/Lib/EXT folder and restart Lotus Notes before trying to run the code..
I'm using asyncTask to download some files over the internet. This is the code I've written which works
downloadUrl task = new downloadUrl(url1,"jsonData1","/sdcard/appData/LocalJson/jsonData1",context);
task.execute();
downloadUrl task1 = new downloadUrl(url2,"jsonData2","/sdcard/appData/LocalJson/jsonData2",context);
task1.execute();
downloadUrl task2 = new downloadUrl(url3,"jsonData3","/sdcard/appData/LocalJson/jsonData3",context);
task2.execute();
downloadUrl task3 = new downloadUrl(url4,"jsonData4","/sdcard/appData/LocalJson/jsonData4",context);
task3.execute();
Now, the tasks run in parallel considering the UI-Thread but they run serialized between one another, which is time consuming. So instead I've tried to execute them on the executor But the thing is that this way I'm missing some files, meaning that when they run serialized I end up with 38 files downloaded while the run on the Executor I end up with 20. I'm pretty sure that is, because I messed up something in the multi-threading code So I'll post it that to:
#Override
protected String doInBackground(String... args) {
downloadAndStoreJson(url,targetFolder);
JSONObject jsonObj = loadJSONObject(pathForLoad);
try {
processJsonData(jsonObj);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "done";
}
#Override
protected void onPostExecute(String result) {
s(targetFolder+" Finished!");
++mutex;
progressBar.setProgress(25*mutex);
if(mutex==4){
mutex=0;
progressBar.setProgress(100);
progressBar.dismiss();
s(monuments.size());
Intent intent = new Intent (getApplicationContext(),NextClass.class);
intent.putExtra("monuments", monuments);
startActivity(intent);
}
}
private void downloadAndStoreJson(String url,String tag){
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl(url);
String jsonString = json.toString();
byte[] jsonArray = jsonString.getBytes();
File fileToSaveJson = new File("/sdcard/appData/LocalJson/",tag);
BufferedOutputStream bos;
try {
bos = new BufferedOutputStream(new FileOutputStream(fileToSaveJson));
bos.write(jsonArray);
bos.flush();
bos.close();
} catch (FileNotFoundException e4) {
// TODO Auto-generated catch block
e4.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
jsonArray=null;
jParser=null;
System.gc();
}
}
private JSONObject loadJSONObject(String path){
JSONObject jsonObj = null;
File readFromJson = new File(path);
byte[] lala;
try {
lala= org.apache.commons.io.FileUtils.readFileToByteArray(readFromJson);
s("---------------"+lala.length);
String decoded = new String(lala, "UTF-8");
jsonObj = new JSONObject(decoded);
} catch (IOException e5) {
// TODO Auto-generated catch block
e5.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jsonObj;
}
and processJsonData is a long method which parses the json files, creates objects and then stores them in an ArrayList, that's where a problem might exist.
You need to make sure your code is Reentrant, meaning it must be possible to run it by several threads at the same time. Or if some code is used to syncronize the execution between your threads you need to make sure it is synchronized.
Looking at your code I see that the mutex is a static variable, which you use to keep track of your threads. Make sure that the operation on the mutex is synchronized, just to keep it clean. But that will not cause you problem...
I dont see your error in this code-snippet, either I fail to see the problem or it might be located in some other methods? Can you please share "downloadAndStoreJson"?
I have a panel with a JTabbedpane and in every tab you can set parameters to execute a query. When one query is busy retrieving his data from the database, you can already open a new tab to set the new parameters. To avoid overload on the database only one query may be executed at once. But when you click execute the program must remember which queries to execute in the right order. During the execution a loader icon is shown and the GUI may not be frozen, because there is a stop button you can click to stop the execution.
I used a swingworker to avoid the GUI from blocking while executing the query and that works fine. But now I want to prevent the next query to start before the previous has finished. In a model, common for the whole panel, I initialized a semaphore: private final Semaphore semaphore = new Semaphore(1, true);
This is the code which starts the swingworker (I've added println commands to see which is started, stopped or finished)
private void doStoredQuery() {
try {
semaphore.acquire();
System.out.println(queryName + "started");
worker.execute();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
And this is my swingworker (initializeWorker() is called from the constructor of the main class):
private SwingWorker<StoredQueryDataModel, Integer> initializeWorker() {
worker = new SwingWorker<StoredQueryDataModel, Integer>() {
#Override
protected StoredQueryDataModel doInBackground() throws Exception {
try {
StoredQueryDataModel dataModel = null;
publish(0);
try {
dataModel = new StoredQueryDataModel(queryRunner, ldbName, queryName, params);
} catch (S9SQLException e) {
//
} catch (Throwable e) {
showErrorMessage(e);
}
return dataModel;
}
finally {
semaphore.release();
System.out.println(queryName + "finished");
}
}
#Override
protected void process(List<Integer> chunks) {
//ignore chunks, just reload loader icon
panel.repaint();
}
#Override
protected void done() {
String error;
try {
result = get();
error = null;
} catch (Exception e) {
error = e.getMessage();
}
if(result == null) {
semaphore.release();
System.out.println(queryName + " stopped");
}
if(error == null) {
// process result
}
else {
showErrorMessage(new Throwable(error));
}
}
};
return worker;
}
I've tried putting the acquire and release on other positions in the code, but nothing seems to work. I am bot in Swingworker and sempahores quite new... Can someone help?
I have found the problem: the semaphore had to be a static variable. In my code there were as many semaphores as there are tabs, which caused them to run at the same time instead of sequentially.
I am developping a BlackBerry application which communicates with the server via HTTP requests(javax.microedition.io.HttpConnection). On device, user clicks some UI items, and device sends the requests to server, when the response comes, UI changes. Communication takes place under new thread, while UI thread pushes and pops ProgressDialogScreen.
The problem is sometimes, when response comes and ProgressDialogScreen is popped, UI does not change but after couple seconds UI changes. If you have requested in between when ProgressDialogScreen is popped and when new Screen is pushed, there comes the mess. First oldest new Screen is pushed, and the newest new Screen is pushed. And this situation can be observed like server responsing wrong requests. This problems occur on simulator and device.
The other problem is, sometimes two same response returns for one request. I was able to see these two problems on simulator at the logs, but i have not able to see this issue on device since i can not see the logs.
EDIT:
String utf8Response;
HttpConnection httpConn = null;
try{
httpConn = (HttpConnection) Connector.open(url);
httpConn.setRequestMethod(HttpConnection.GET);
httpConn.setRequestProperty("Content-Type", "text/html; charset=UTF8");
if(sessionIdCookie != null){
//may throw IOException, if the connection is in the connected state.
httpConn.setRequestProperty("Cookie", sessionIdCookie);
}
}catch (Exception e) {
//...
}
try{
httpConn.getResponseCode();
return httpConn;
}catch (IOException e) {
// ...
}
byte[] responseStr = new byte[(int)httpConn.getLength()];
DataInputStream strm = httpConn.openDataInputStream();
strm.readFully(responseStr);
try{
strm.close();
}catch (IOException e) {
// ....
}
utf8Response = new String(responseStr, "UTF-8");
If this code successfully run, this piece of code runs and new screen is pushed:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Vector accounts = Parser.parse(utf8Response,Parser.ACCOUNTS);
if (accounts.size() == 0){
DialogBox.inform(Account.NO_DEPOSIT);
return;
}
currentScreen = new AccountListScreen(accounts);
changeScreen(null,currentScreen);
}
});
public void changeScreen(final AbstractScreen currentScreen,final AbstractScreen nextScreen) {
if (currentScreen != null)
UiApplication.getUiApplication().popScreen(currentScreen);
if (nextScreen != null)
UiApplication.getUiApplication().pushScreen(nextScreen);
}
EDITv2:
private static void progress(final Stoppable runThis, String text,boolean cancelable) {
progress = new ProgressBar(runThis, text,cancelable);
Thread threadToRun = new Thread() {
public void run() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
try{
UiApplication.getUiApplication().pushScreen(progress);
}catch(Exception e){
Logger.log(e);
}
}
});
try {
runThis.run();
} catch (Throwable t) {
t.printStackTrace();
}
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
try {
UiApplication.getUiApplication().popScreen(progress);
} catch (Exception e) { }
}
});
}
};
threadToRun.start();
}
By the way ProgressBar is extended from net.rim.device.api.ui.container.PopupScreen and Stoppable is extended from Runnable
I preferred to pop progress bar after new Screen is prepared and pushed. This way there will be no new request between request and response.
Why not do:
private static void progress(final Stoppable runThis, String text,boolean cancelable) {
progress = new ProgressBar(runThis, text,cancelable);
UiApplication.getUiApplication().pushScreen(progress);
[...]
Seems like you are parsing on the UI Thread. Please remove Vector accounts = Parser.parse(utf8Response,Parser.ACCOUNTS); from ui thread and do it in a separate thread.