This my first attempt at working with a service. My service is intended to download an image file from a server based on a filename string that it gets dynamically.
I'm getting the following error. Does anyone see what I am doing wrong? Thank you!
08-19 16:40:18.102: E/AndroidRuntime(27702): java.lang.RuntimeException: Unable to instantiate service database.DownloadPicture: java.lang.InstantiationException: can't instantiate class database.DownloadPicture; no empty constructor
Here is how I am starting the service:
Intent intent = new Intent(context, DownloadPicture.class);
intent.putExtra(DownloadPicture.FILENAME, filename);
startService(intent);
System.err.println("service started");
This is my service:
public class DownloadPicture extends IntentService {
private int result = Activity.RESULT_CANCELED;
public static final String FILENAME = "filename";
public static final String FILEPATH = "filepath";
public static final String RESULT = "result";
public static final String NOTIFICATION = "com.mysite.myapp";
public DownloadPicture(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
String urlPath = this.getResources().getString(R.string.imagesURL);
String fileName = intent.getStringExtra(FILENAME);
File output = new File(Environment.getExternalStorageDirectory(), fileName);
if (output.exists()) {output.delete();}
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
stream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(stream);
fos = new FileOutputStream(output.getPath());
int next = -1;
while ((next = reader.read()) != -1) {
fos.write(next);
}
// Successful finished
result = Activity.RESULT_OK;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
publishResults(output.getAbsolutePath(), result);
}
private void publishResults(String outputPath, int result) {
Intent intent = new Intent(NOTIFICATION);
intent.putExtra(FILEPATH, outputPath);
intent.putExtra(RESULT, result);
sendBroadcast(intent);
}
}
If you carefully read the error it says : no empty constructor . So try to have an empty default no-argument constructor for IntentService like:
public DownloadPicture() {
super("DownloadPicture");
}
See No empty constructor when create a service Hope it helps.
Have you added the service to your manifest?
<service android:name=".DownloadPicture" />
Related
I have a IntentService I am doing some task in another thread in
onHandleIntent(Intent intent)
Why is the IntentService stopping before performing the operation(task)?
Here is my code:
public class SampleIntentService extends IntentService {
public static final int DOWNLOAD_ERROR = 10;
public static final int DOWNLOAD_SUCCESS = 11;
public SampleIntentService() {
super(SampleIntentService.class.getName());
}
#Override
protected void onHandleIntent(Intent intent) {
final String url = intent.getStringExtra("url");
final ResultReceiver receiver = intent.getParcelableExtra("receiver");
final Bundle bundle = new Bundle();
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
return downloadFile(url, receiver);
}
#Override
protected void onPostExecute(String filePath) {
super.onPostExecute(filePath);
bundle.putString("filePath", filePath);
receiver.send(DOWNLOAD_SUCCESS, bundle);
}
};
}
private String downloadFile(String url, ResultReceiver receiver) {
File downloadFile = new File(Environment.getExternalStorageDirectory() + File.pathSeparator + "test.png");
if (downloadFile.exists())
downloadFile.delete();
try {
downloadFile.createNewFile();
URL downloadURL = new URL(url);
HttpURLConnection conn = (HttpURLConnection) downloadURL
.openConnection();
int responseCode = conn.getResponseCode();
if (responseCode != 200)
throw new Exception("Error in connection");
InputStream is = conn.getInputStream();
FileOutputStream os = new FileOutputStream(downloadFile);
byte buffer[] = new byte[1024];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {
os.write(buffer, 0, byteCount);
}
os.close();
is.close();
String filePath = downloadFile.getPath();
return filePath;
} catch (Exception e) {
receiver.send(DOWNLOAD_ERROR, Bundle.EMPTY);
e.printStackTrace();
}
return null;
}
}
As per the Docs:
abstract void onHandleIntent(Intent intent)
This method is invoked on the worker thread with a request to process.
Since this method is already invoked on worker thread you don't need to start another thread.
If you do that, the onHandleIntent(Intent intent) will return and the IntentService will think the task is done and it will stop itself.
Source: onHandleIntent
Here is the updated code :
public class SampleIntentService extends IntentService {
public static final int DOWNLOAD_ERROR = 10;
public static final int DOWNLOAD_SUCCESS = 11;
public SampleIntentService() {
super(SampleIntentService.class.getName());
}
#Override
protected void onHandleIntent(Intent intent) {
final String url = intent.getStringExtra("url");
final ResultReceiver receiver = intent.getParcelableExtra("receiver");
final Bundle bundle = new Bundle();
String filePath = downloadFile(url, receiver);
bundle.putString("filePath", filePath);
receiver.send(DOWNLOAD_SUCCESS, bundle);
}
private String downloadFile(String url, ResultReceiver receiver) {
File downloadFile = new File(Environment.getExternalStorageDirectory() + File.pathSeparator + "test.png");
if (downloadFile.exists())
downloadFile.delete();
try {
downloadFile.createNewFile();
URL downloadURL = new URL(url);
HttpURLConnection conn = (HttpURLConnection) downloadURL
.openConnection();
int responseCode = conn.getResponseCode();
if (responseCode != 200)
throw new Exception("Error in connection");
InputStream is = conn.getInputStream();
FileOutputStream os = new FileOutputStream(downloadFile);
byte buffer[] = new byte[1024];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {
os.write(buffer, 0, byteCount);
}
os.close();
is.close();
String filePath = downloadFile.getPath();
return filePath;
} catch (Exception e) {
receiver.send(DOWNLOAD_ERROR, Bundle.EMPTY);
e.printStackTrace();
}
return null;
}
I'm new to android so please help me out. I am trying to save my ToDoList in a file so that the next time I open it, all the items are reloaded
This is the code I have so far,
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
gson = new Gson();
try {
BufferedReader br = new BufferedReader(new FileReader("storage.json"));
Entry e = gson.fromJson(br, Entry.class);
Log.d("reading", e.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
}}
#Override
protected void onStop() {
super.onStop();
json = gson.toJson(mEntries);
Log.d("jsondata", json);
try {
file1 = new FileWriter("storage.json");
file1.write(json);
file1.flush();
file1.close();
} catch (IOException e) {
e.printStackTrace();
}
Entry.java
public class Entry {
String S;
boolean b;
public Entry(String S, boolean b) {
this.S = S;
this.b = b;
}
public String getS() {
return S;
}
public void setS(String S) {
this.S = S;
}
public void setB(boolean b) {
this.b = b;
}
public boolean isB() {
return b;
}
}
How do I proceed from here? In onCreate() I would like to check if the file exists and if yes, import data from file and display on screen.
Every android app has its own internal storage only that app can access, you can read from there or write to it.
In you case, you first want to check if you such file exist before creating one.
private String read(Context context, String fileName) {
try {
FileInputStream fis = context.openFileInput(fileName);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader bufferedReader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (FileNotFoundException fileNotFound) {
return null;
} catch (IOException ioException) {
return null;
}
}
private boolean create(Context context, String fileName, String jsonString){
String FILENAME = "storage.json";
try {
FileOutputStream fos = context.openFileOutput(fileName,Context.MODE_PRIVATE);
if (jsonString != null) {
fos.write(jsonString.getBytes());
}
fos.close();
return true;
} catch (FileNotFoundException fileNotFound) {
return false;
} catch (IOException ioException) {
return false;
}
}
public boolean isFilePresent(Context context, String fileName) {
String path = context.getFilesDir().getAbsolutePath() + "/" + fileName;
File file = new File(path);
return file.exists();
}
onCreate of the Activity, you can use do the following
boolean isFilePresent = isFilePresent(getActivity(), "storage.json");
if(isFilePresent) {
String jsonString = read(getActivity(), "storage.json");
//do the json parsing here and do the rest of functionality of app
} else {
boolean isFileCreated = create(getActivity, "storage.json", "{}");
if(isFileCreated) {
//proceed with storing the first todo or show ui
} else {
//show error or try again.
}
}
reference https://developer.android.com/guide/topics/data/data-storage.html#filesInternal
I am using the below code to download an mp3 file from my server to android
public class DownloadService extends IntentService {
private int result = Activity.RESULT_CANCELED;
public static final String RESULT = "result";
public static final String NOTIFICATION = "!##$%%^";
public DownloadService() {
super("DownloadService");
}
// will be called asynchronously by Android
#Override
protected void onHandleIntent(Intent intent) {
Integer serverTrackId=intent.getIntExtra(Constants.INTENT_PARAM_SERVER_TRACK_ID, 0);
String serverUrl=intent.getStringExtra(Constants.INTENT_PARAM_SERVER_TRACK_URL);
String trackName=intent.getStringExtra(Constants.INTENT_PARAM_SERVER_TRACK_NAME);
String filePath=intent.getStringExtra(Constants.INTENT_PARAM_ROOT_FILE_PATH);
Integer localTrackId=intent.getIntExtra(Constants.INTENT_PARAM_LOCAL_TRACK_ID, 0);
File output = new File(filePath+"/"+trackName);
if (output.exists()) {
result = Activity.RESULT_OK;
publishResults(output.getAbsolutePath(), result);
}
else {
InputStream stream = null;
FileOutputStream fos = null;
try {
URL url = new URL(serverUrl);
stream = url.openConnection().getInputStream();
InputStreamReader reader = new InputStreamReader(stream);
fos = new FileOutputStream(output.getPath());
int next = -1;
while ((next = reader.read()) != -1) {
fos.write(next);
}
// successfully finished
result = Activity.RESULT_OK;
} catch (Exception e) {
e.printStackTrace();
result = Activity.RESULT_CANCELED;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
result = Activity.RESULT_CANCELED;
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
result = Activity.RESULT_CANCELED;
e.printStackTrace();
}
}
}
publishResults(output.getAbsolutePath(), result);
}
}
private void publishResults(String outputPath, int result) {
try {
FileInputStream fileInputStream = new FileInputStream(outputPath);
Intent intent = new Intent(NOTIFICATION);
intent.putExtra(FILEPATH, outputPath);
intent.putExtra(RESULT, result);
sendBroadcast(intent);
}catch(Exception e){
e.printStackTrace();
}
}
}
After downloaded broadcast is made , and I try to play the mp3 file by the below code
if (trackPath != null) {
FileInputStream fileInputStream = new FileInputStream(trackPath);
mediaPlayer.setDataSource(fileInputStream.getFD());
} else {
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.spacer_audio);
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
}
mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mediaPlayer.setLooping(false);
mediaPlayer.prepare();
mediaPlayer.setVolume(1f, 1f);
mediaPlayer.start();
I get IOException thrown from "mediaPlayer.prepare()"
I tried to play the downloaded music file through android default music player and it shows "cannot play this media".
I tried copying it to computer to try play it and I noticed there is a size difference of several KBs from the original track and the downloaded one.
Please help me find the bug.
You use InputStreamReader to read a binary file, it may produce some unexpected problems. I suggest you use BufferedInputStream instead.
BufferedInputStream reader = new BufferedInputStream(stream);
fos = new FileOutputStream(output.getPath());
int length = -1;
byte[] buffer = new byte[1024 * 8];
while ((length = reader.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
I need your help with two Errors I´m getting on
Creating a Thread, where I`m creating a file
After the file stuff, a AsyncTask getting executed to send the file to a server (multipart/form-data)
Thats how the first part looks like:
public void startResultTransfer(final int timestamp, final int duration, final String correction, final float textSize, final int age, final int switch_count, final Activity activity){
synchronized(DataTransmission.class){
new Thread() {
public void run() {
FileWriter fw = null;
//1.Check if file exists
File file = new File(FILE_PATH);
if(!file.exists()){
//File does not exists, when we have to generate the head-line
try {
fw = new FileWriter(FILE_PATH);
fw.append("timestamp\tduration\tcorrection\ttext_size\tage\tswitch_count"); //Headline
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//2. Write Result
try {
if(fw == null)
fw = new FileWriter(FILE_PATH);
fw.append("\n"+String.valueOf(timestamp)+"\t");
fw.append(""+String.valueOf(duration)+"\t");
fw.append(""+correction+"\t");
fw.append(""+String.valueOf(textSize)+"\t");
fw.append(""+String.valueOf(age)+"\t");
fw.append(""+String.valueOf(switch_count)+"\t");
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//3. File Transfer
if(isOnline(activity))
transferFileToServer(activity);
}
}.start();
}
}
The function "transferFileToServer" looks like this:
public synchronized void transferFileToServer(Activity activity){
String id = id(activity);
File file = new File(FILE_PATH);
if(id != null && file.exists()){
final String url = URL+id;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
TransmissionTask task = new TransmissionTask();
task.execute(url);
}
});
}
}
Now, I`m getting an "ExceptionInInitializerError" with the explanatory message
Caused by java.lang.RuntimeException Can't create handler inside thread that has not called Looper.prepare()"
at the line "activity.runOnUiThread".
In the first function I need to call "transferFileToServer" after some pre settings. But the function should be called unattached from the first function, too.
Should I maybe implement a MessageHandler for executing the AsyncTask at the end of Thread?
http://developer.android.com/reference/android/os/Looper.html
Or should I maybe Change the "AsyncTask" in the "transferFileToServer" function to a Thread, because I don`t do any UI operations?
Edit: The method started from the Async-Task
class TransmissionTask extends AsyncTask<String, Void, String> {
public TransmissionTask() {
}
#Override
protected String doInBackground(String... params) {
synchronized(DataTransmission.class){
try {
HttpURLConnection urlConn;
java.net.URL mUrl = new java.net.URL(params[0]);
urlConn = (HttpURLConnection) mUrl.openConnection();
urlConn.setDoOutput(true);
urlConn.setRequestMethod("POST");
String boundary = "---------------------------14737809831466499882746641449";
String contentType = "multipart/form-data; boundary="+boundary;
urlConn.addRequestProperty("Content-Type", contentType);
DataOutputStream request = new DataOutputStream(urlConn.getOutputStream());
request.writeBytes("\r\n--"+boundary+"\r\n");
request.writeBytes("Content-Disposition: form-data; name=\"userfile\"; filename=\""+FILE_NAME+"\"\r\n");
request.writeBytes("Content-Type: application/octet-stream\r\n\r\n");
File myFile = new File(FILE_PATH);
int size = (int) myFile.length();
byte[] bytes = new byte[size];
try {
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(myFile));
buf.read(bytes, 0, bytes.length);
buf.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
request.write(bytes);
request.writeBytes("\r\n--"+boundary+"--\r\n");
request.flush();
request.close();
InputStream responseStream = new BufferedInputStream(urlConn.getInputStream());
BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = responseStreamReader.readLine()) != null)
{
stringBuilder.append(line).append("\n");
}
responseStreamReader.close();
String response = stringBuilder.toString();
responseStream.close();
urlConn.disconnect();
return response;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(result != null){
if(result.toLowerCase().contains("erfolgreich")){
//If successfull delete File
File file = new File(FILE_PATH);
file.delete();
}
}
}
}
Remove runOnUiThread:
public synchronized void transferFileToServer(Activity activity){
String id = id(activity);
File file = new File(FILE_PATH);
if(id != null && file.exists()){
final String url = URL+id;
TransmissionTask task = new TransmissionTask();
task.execute(url);
}
}
The main idea of AsyncTask to run background operation/logic without Threads or Handlers.
You don't need wrap AsyncTask with additional Thread and bind with UI Thread what you did
From your code:
public void startResultTransfer(/* ... */){
....
new Thread() {
.....
transferFileToServer(/* ... */); // its wrong!!!
....
}.start()
}
transferFileToServer starts your AsyncTask and you run it not in main UI Thread but in single Thread.
This is a problem.
Start your AsyncTask from Activity.
I have an object caching class that can save an object in memory, the problem arises when I try to retreive it later. How do I output a generic Object and then put it into a defined object on the other end. Here is the class
public class ObjectCache implements Serializable{
private static final long serialVersionUID = 1L;
private Context context;
private String objectName;
private Integer keepAlive = 86400;
public ObjectCache(Context context,String objectName) {
this.context = context;
this.objectName = objectName;
}
public void setKeepAlive(Integer time) {
this.keepAlive = time;
}
public boolean saveObject(Object obj) {
final File cacheDir = context.getCacheDir();
FileOutputStream fos = null;
ObjectOutputStream oos = null;
if (!cacheDir.exists()) {
cacheDir.mkdirs();
}
final File cacheFile = new File(cacheDir, objectName);
try {
fos = new FileOutputStream(cacheFile);
oos = new ObjectOutputStream(fos);
oos.writeObject(obj);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
public boolean deleteObject() {
final File cacheDir = context.getCacheDir();
final File cacheFile = new File(cacheDir, objectName);
return (cacheFile.delete());
}
public Object getObject() {
final File cacheDir = context.getCacheDir();
final File cacheFile = new File(cacheDir, objectName);
Object simpleClass = null;
FileInputStream fis = null;
ObjectInputStream is = null;
try {
fis = new FileInputStream(cacheFile);
is = new ObjectInputStream(fis);
simpleClass = (Object) is.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (is != null) {
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return simpleClass;
}
}
And from activity I start the object class, save it, and retreive it like so
objectCache = new ObjectCache(this,"sessionCache2");
//save object returns true
boolean result = objectCache.saveObject(s);
//get object back
Object o = objectCache.getObject();
instead of Object o i need it to be a Session object, but then that will mean the return type of the getObject method needs to return that. Can't I convert the object some
If you are sure that the object that the ObjectCache will return is a Session object all you have to do is cast it:
//get object back
Session session = (Session) objectCache.getObject();
This will throw a ClassCastException (unchecked) if the getObject() method does not return a Session object.