I am downloading images from url's provided by a JSON document. At first my app seems to be working correctly, pulling in and placing images and catching the exceptions when there is no image url in the array element but suddenly it crashes and my error log is showing something to the tune of
Caused by: java.lang.RuntimeException: java.net.MalformedURLException: Protocol not found:
The thing is I have already caught this error as shown below.
If someone could explain to me why this is happening to me and point me in the right direction I will be much obliged.
Image DwnLdr class
public Drawable loadImage (BaseAdapter adapt, ImageView view)
{
this.adapter = adapt;
String url = (String) view.getTag();
if (imageCache.containsKey(url))
{
return imageCache.get(url);
}
else {
new ImageTask().execute(url);
return DEFAULT_ICON;
}
}
private class ImageTask extends AsyncTask<String, Void, Drawable>
{
private String s_url;
#Override
protected Drawable doInBackground(String... params) {
s_url = params[0];
InputStream inStream;
try {
Log.v(debugTag, "Fetching: " + s_url);
URL url = new URL(s_url);
inStream = url.openStream();
} catch (MalformedURLException e) {
Log.v(debugTag, "Malformed: " + e.getMessage());
throw new RuntimeException(e);
} catch (IOException e)
{
Log.d(debugTag, "I/O : " + e.getMessage());
throw new RuntimeException(e);
}
return Drawable.createFromStream(inStream, "src");
}
#Override
protected void onPostExecute(Drawable result) {
super.onPostExecute(result);
synchronized (this) {
imageCache.put(s_url, result);
}
adapter.notifyDataSetChanged();
}
}
View Adapter Class
ListData data = topics.get(position);
try {
long lg = Long.valueOf(data.getPostTime())*1000;
Date date = new Date(lg);
String postTime = new SimpleDateFormat("MM dd, yyyy hh:mma").format(date);
holder.data = data;
holder.listName.setText(data.getTitle());
holder.authorName.setText(data.getAuthor());
holder.postTime.setText(postTime);
holder.redditScore.setText(data.getrScore());
Log.v(DEBUG_TAG, "Cell Created");
}catch (Exception e){
e.printStackTrace();
Log.v(DEBUG_TAG,"Cell Not Created Due to: ",e);
}
if(data.getImageUrl()!=null){
try {
holder.thumbnail.setTag(data.getImageUrl());
Drawable drawable = imgGet.loadImage(this, holder.thumbnail);
if (drawable != null) {
holder.thumbnail.setImageDrawable(drawable);
} else {
holder.thumbnail.setImageResource(R.drawable.filler_icon);
}
}catch (Exception e){
e.printStackTrace();
Log.v(DEBUG_TAG,"no image: ",e);
}
return convertView;
}
Main Class Adapter Set
public static class MyViewHolder {
public TextView listName, authorName, redditScore, postTime;
public Button goButton;
public ImageView thumbnail;
public ListData data;
}
public void setTopics(ArrayList<ListData> data) {
this.data = data;
this.postList.setAdapter(new RedditDataAdapter(this, this.getImg, this.layoutInflater,this.data));
}
Error Log
Caused by: java.lang.RuntimeException: java.net.MalformedURLException: Protocol not found:
at Tasks.RedditIconTask$ImageTask.doInBackground(RedditIconTask.java:60)
at Tasks.RedditIconTask$ImageTask.doInBackground(RedditIconTask.java:46)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
Looks like the image URL is an empty string. Debug your code to learn why is it so. The code you posted doesn't really show where the URL value comes from.
Why you're getting the exception is because you're re-throwing it, wrapped in a RuntimeException:
throw new RuntimeException(e);
I was able to solve my problem by using what laatlto said and changing the code to the following.
protected Drawable doInBackground(String... params) {
s_url = params[0];
InputStream inStream;
Drawable picture=null;
try {
Log.v(debugTag, "Fetching: " + s_url);
URL url = new URL(s_url);
inStream = url.openStream();
picture= Drawable.createFromStream(inStream, "src");
} catch (MalformedURLException e) {
Log.v(debugTag, "Malformed: " + e.getMessage());
} catch (IOException e)
{
Log.d(debugTag, "I/O : " + e.getMessage());
}
return picture;
}
Related
I am trying to change the wallpaper of Android every 15 minutes or something like this. A user can choose the time and I am running a periodic work using Workmanager.
PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(SomeWorker.class, 15, TimeUnit.MINUTES).build();
WorkManager.getInstance().enqueue(periodicWorkRequest);
This way I am calling my Worker Class. The working class is this
public class SomeWorker extends Worker {
Context context = getApplicationContext();
private String URL;
#NonNull
#Override
public Result doWork() {
new FetchWallpaper().execute();
return Result.SUCCESS;
}
private class FetchWallpaper extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... voids) {
try
{
URL = "myurl.com";
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL)
.build();
Response responses = null;
try {
responses = client
.newCall(request)
.execute();
String jsonData = responses.body().string();
JSONArray jsonArr = new JSONArray(jsonData);
JSONObject c = jsonArr.getJSONObject(new Random().nextInt(jsonArr.length()));
String imageUrl = c.getString("wallpaper");
Bitmap result= Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(result);
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
Date currentTime = Calendar.getInstance().getTime();
}
catch (Exception e)
{
Date currentTime = Calendar.getInstance().getTime();
}
return null;
}
}}
On that Particular line,
new FetchWallpaper().execute();
I am getting the error saying it must call from the main thread. I am new to Android, I don't know if this is the good approach.
Please let me know if there is any better approach to perform such kind of task.
The Worker class already calls doWork on a background thread - you don't need to use AsyncTask at all.
Just move everything from your doInBackground method directly into the Worker's doWork.
You can not update UI from doInBackground method. If you want to do something on UI you must do that on Main UI thread. So write setBitmap code in onPostExecute method as onPostExecute on on Main UI Thread.
To do that set third parameter of AsyncTask as String
AsyncTask<Void, Void, String>
So that return type of doInBackground method will be String
protected String doInBackground(Void... voids)
...
...
return imageUrl;
}
And Your onPostExecute method will be like
#Override
protected void onPostExecute(String imageUrl) {
super.onPostExecute(imageUrl);
Bitmap result= Picasso.with(getApplicationContext())
.load(imageUrl)
.get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
try {
wallpaperManager.setBitmap(result);
} catch (Exception ex) {
ex.printStackTrace();
}
}
new AsyncTask<Void, Bitmap, Bitmap>() {
#Override
protected Bitmap doInBackground(Void... params) {
Bitmap bitmap = null;
try {
InputStream inputStream;
inputStream = new java.net.URL(url).openStream();
bitmap = BitmapFactory.decodeStream(inputStream);
}catch (Exception e) {
logAppE(TAG, "BITMAP ERROR -> " + e.getMessage());
}
return bitmap
}
#Override
protected void onPostExecute(Bitmap s) {
try {
Glide.with(context).asGif().load(s).into(imgViewGIF);
} catch (Exception e) {
logAppE(TAG, "BITMAP -> " + e.getMessage());
}
}
}.execute();
My code,
public static Bitmap retriveVideoFrameFromVideo(String videoPath) throws Throwable {
Bitmap bitmap = null;
MediaMetadataRetriever mediaMetadataRetriever = null;
try {
mediaMetadataRetriever = new MediaMetadataRetriever();
if (Build.VERSION.SDK_INT >= 14)
mediaMetadataRetriever.setDataSource(videoPath, new HashMap<String, String>());
else
mediaMetadataRetriever.setDataSource(videoPath);
// mediaMetadataRetriever.setDataSource(videoPath);
bitmap = mediaMetadataRetriever.getFrameAtTime();
} catch (Exception e) {
e.printStackTrace();
throw new Throwable(
"Exception in retriveVideoFrameFromVideo(String videoPath)"
+ e.getMessage());
} finally {
if (mediaMetadataRetriever != null) {
mediaMetadataRetriever.release();
}
}
return bitmap;
}
This is Create thumbnail but take much time I used this with ListView then ListView being hangup.
You need run this task in Async Method Like this in onBindViewHolder() if you are using RecycleView or put on getView() if your are using ListView:
new AsyncTask<String, String, String>() {
Bitmap bitmapVideo;
#Override
protected String doInBackground(String... strings) {
try {
//Your method call here
bitmapVideo =retriveVideoFrameFromVideo(strings[0]);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String id) {
super.onPostExecute(id);
if (bitmapVideo != null) {
//Load your bitmap here
holder.imgVideoThumb.setImageBitmap(bitmapVideo);
}
}
}.execute(getYourVideolink());
For better efficiency you save the bitmap image in local and before calling AsyncTask() check weather this image is already save in local if its their than load from local and no new to run AsyncTask() again
This is my first async task, which gets called first, it gets data from server and then onPostExecute it executes other async task, which downloads and sets image.
private class GetData extends AsyncTask<String, Void, Void> {
private final HttpClient client = new DefaultHttpClient();
private String content;
private String error = null;
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... progress) {
}
#Override
protected Void doInBackground(String... params) {
try {
HttpGet httpget = new HttpGet(params[0]);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
content = client.execute(httpget, responseHandler);
} catch (ClientProtocolException e) {
error = e.getMessage();
cancel(true);
} catch (IOException e) {
error = e.getMessage();
cancel(true);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if (error == null) {
try {
JSONObject dataDishes = new JSONObject(content);
Log.d("DISHES", dataDishes.toString());
ArrayList<DishModel> dishData = new ArrayList<DishModel>();
for (int i = 0; i < 8; i++) {
DishModel model = new DishModel();
model.setName("Company " + i);
model.setDesc("desc" + i);
//TODO: set data img
new GetImage(model).execute("http://example.com/" + (i + 1) + ".png");
dishData.add(model);
}
ListView listAllDishes = (ListView) getView().findViewById(R.id.listView);
DishRowAdapter adapterAllDishes = new DishRowAdapter(getActivity(),
R.layout.dish_row, dishData);
listAllDishes.setAdapter(adapterAllDishes);
} catch (JSONException e) {
Log.d("DISHES", e.toString());
}
} else {
Log.e("DISHES", error);
}
}
}
This is another async task, it downloads image and onPostExecute it sets image to passed model.
private class GetImage extends AsyncTask<String, Void, Void> {
private DishModel model;
private Bitmap bmp;
public getImage(DishModel model) {
this.model = model;
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... progress) {
}
#Override
protected Void doInBackground(String... params) {
try {
URL url = new URL(params[0]);
Log.d("DISHES", params[0]);
try {
bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (IOException e) {
Log.d("DISHES", e.toString());
}
} catch (MalformedURLException e) {
Log.d("DISHES", e.toString());
}
return null;
}
#Override
protected void onPostExecute(Void result) {
model.setPhoto(bmp);
}
}
It works if I do both data/image download proccess in one AsyncTask doInBackground(String... params), but it doesnt when I split data and image downloading into seperate async tasks. Furthermore I dont get any exceptions or errors.
UPDATE: Images shows up when i switch views..
At first, getImage and getData are classes, and classes names in Java are capitalized.
Technically, you can run another AsyncTask from onProgressUpdate() or onPostExecute() - https://stackoverflow.com/a/5780190/1159507
So, try to put the breakpoint in second AsyncTask call and debug is it called.
I've build an app for managing transactions and i'm currently adding dropbox backup. I do this by uploading the databasefiles to dropbox (which seems to be appearing correctly). Then i want to download the files again and overwrite the existing databases. When i do this the databases get saved as files ei. get listed by context.fileList(); instead of context.databaseList(); How do i handle the database files to get them in the right place?
Here is the code i thought relevant:
private static class Downloader extends AsyncTask<Integer, Integer, Boolean>{
Context context;
#Override
protected void onPreExecute(){
context = SpendoBase.getContext();
}
#Override
protected Boolean doInBackground(Integer... arg0) {
System.out.println("DoInBackground:");
try {
List<DropboxAPI.Entry> entries = mDBApi.metadata("/", -1, null, true, null).contents;
File file;
FileOutputStream os;
int count = 0;
for(DropboxAPI.Entry entry: entries){
count++;
System.out.println("Entry.path(): " + entry.path + " " + count + "/" + entries.size());
file = new File(entry.path);
System.out.println("1");
os = context.openFileOutput(file.getName(), Context.MODE_PRIVATE);
System.out.println("2");
DropboxFileInfo info = mDBApi.getFile(entry.path, null, os, null);
os.flush();
os.close();
System.out.println("3 " + info);
}
} catch (DropboxException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
private static class Uploader extends AsyncTask<Integer, Integer, Boolean>{
String[] databaseList;
Context context;
#Override
protected void onPreExecute(){
context = SpendoBase.getContext();
databaseList = context.databaseList();
}
#Override
protected Boolean doInBackground(Integer... params) {
for(String dbName: databaseList){
try {
File f = context.getDatabasePath(dbName);
FileInputStream fis = new FileInputStream(f.getPath());
mDBApi.putFileOverwrite("/" + dbName, fis, f.length(), null);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DropboxException e) {
e.printStackTrace();
}
}
return null;
}
}
private static class MetaReader extends AsyncTask<Integer, Integer, List<String>>{
#Override
protected List<String> doInBackground(Integer... arg0) {
try {
List<String> result = new Vector<String>();
DropboxAPI.Entry existingEntry = mDBApi.metadata("/", -1, null, true, null);
List<DropboxAPI.Entry> temp = existingEntry.contents;
for(int i = 0; i < temp.size(); i++){
File f = new File(temp.get(i).path);
result.add(f.getName());
}
return result;
} catch (DropboxException e) {
System.out.println("Something went wrong: " + e);
}
return null;
}
#Override
protected void onPostExecute(List<String> result){
for(String str:result){
System.out.println(str);
}
}
}
I don't do much Android development, so I could be way off base here, but why can't you just use context.getDatabasePath(dbName) again in the Downloader and write the file to that path?
I managed to solve it. My error was simply that I saved the database in the wrong place.
Changing:
file = new File(entry.path);
System.out.println("1");
os = context.openFileOutput(file.getName(), Context.MODE_PRIVATE);
to:
file = new File("/data/data/com.SverkerSbrg.SpendoFull/databases/" + entry.path);
System.out.println("1");
os = new FileOutputStream(file.getPath());
Solved the problem
You need to root your target phone to save your file on /data/data/com.SverkerSbrg.SpendoFull/databases/ this location.
I would like to be able to use the facebook android sdk and post a link to facebook. An example of what I want would be is if you were on facebook and you type a link into your status part, like "http://www.google.com". When you do this a box pops up and your post ends up being a block that has an image and a link. I found documentation in the facebook api for this using an attatchment, though when I try to do this with the android facebook api it doesn't seem to work. I've looked for hours on the net, with no luck. Thanks.
Asuming when you read this that you know how to log onto facebook and such via the api...
private void fbImageSubmit(Facebook fb, String imageurl, String caption, String description, String name, String linkurl)
{
if(fb != null)
{
if(fb.isSessionValid())
{
Bundle b = new Bundle();
b.putString("picture", imageurl);
b.putString("caption",caption);
b.putString("description",description );
b.putString("name",name);
b.putString("link",linkurl);
try {
String strRet = "";
strRet = fb.request("/me/feed",b,"POST");
JSONObject json;
try {
json = Util.parseJson(strRet);
if(!json.isNull("id"))
{
Log.i("Facebook", "Image link submitted.");
}
else
{
Log.e("Facebook","Error: " + strRet);
}
} catch (FacebookError e) {
Log.e("Facebook","Error: " + e.getMessage());
}
} catch (Exception e) {
Log.e("Facebook", "Error: " + e.getMessage());
}
}
}
}
This works perfect fine with Progress Dialog box.. I have used it...
You must added the jar of Facebook...
Facebook authenticatedFacebook = new Facebook(APP_ID);
private static final String[] PERMISSIONS = new String[] { "publish_stream", "read_stream", "offline_access" };
Call below function on button Click....
authenticatedFacebook.authorize(YOUR_CLASS_NAME.this, PERMISSIONS, new FaceBookWallPostListener());
Now Add this class...
public class FaceBookWallPostListener implements DialogListener {
public void onComplete(Bundle values) {
new FacebookWallPost().execute();
}
public void onCancel() {
}
public void onError(DialogError e) {
e.printStackTrace();
}
public void onFacebookError(FacebookError e) {
e.printStackTrace();
}
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
private class FacebookWallPost extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
try {
path = "Path OF YOUR IMAGE";
Bundle parameters = new Bundle();
parameters.putString("message", "MESSAGE YOU WANT TO POST");
try {
File file = new File(path, "IMAGE_NAME.jpg");
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
data = baos.toByteArray();
if (data != null) {
parameters.putByteArray("picture", data);
}
parameters.putString("access_token", authenticatedFacebook.getAccessToken());
authenticatedFacebook.request("me");
authenticatedFacebook.request("me/photos", parameters, "POST");
} catch (Exception e) {
return e.getMessage();
}
return "success";
} catch (Exception e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
pDialog.dismiss();
if (result.equals("success")) {
Toast.makeText(YOUR_CLASS_NAME.this, "WallPost Successfully Done", Toast.LENGTH_SHORT).show();
try {
new File(Environment.getExternalStorageDirectory().toString() + "/Diegodeals", "diegodeals.jpg").delete();
} catch (Exception e) {
}
} else {
Toast.makeText(YOUR_CLASS_NAME.this, "Failed to post \n " + result, Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onPreExecute() {
pDialog = new ProgressDialog(YOUR_CLASS_NAME.this);
pDialog.setMessage("Posting Picture & Message on Facebook...");
pDialog.show();
}
}
/////GOOOD LUCK.