Search code examples
javaandroidserviceandroid-asynctaskftp-client

Async Task FTP Upload Android Service Crashing?


I am trying to upload via FTP a file in a set directory. The file is called "advancedsettings.xml".

The code works fine when used in the Async Task of an Activity, but when attempting to use a Service to carry out the exact same operations within an Async Task, the application crashes with the following error(s):

01-13 16:21:08.403 21134-21151/com.name.example.xx E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1 Process: com.name.example.xx, PID: 21134 java.lang.RuntimeException: An error occured while executing doInBackground() at android.os.AsyncTask$3.done(AsyncTask.java:300) at java.util.concurrent.FutureTask.finishCompletion(F utureTask.java:355) at java.util.concurrent.FutureTask.setException(Futur eTask.java:222) at java.util.concurrent.FutureTask.run(FutureTask.jav a:242) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTas k.java:231) at java.util.concurrent.ThreadPoolExecutor.runWorker( ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:841) Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.(Handler.java:200) at android.os.Handler.(Handler.java:114) at android.widget.Toast$TN.(Toast.java:388) at android.widget.Toast.(Toast.java:114) at android.widget.Toast.makeText(Toast.java:273) at com.name.example.xx.MyService$FTPUpload.doInBackgr ound(MyService.java:58) at com.name.example.xx.MyService$FTPUpload.doInBackgr ound(MyService.java:55) at android.os.AsyncTask$2.call(AsyncTask.java:288) at java.util.concurrent.FutureTask.run(FutureTask.jav a:237) ************at android.os.AsyncTask$SerialExecutor$1.run(AsyncTas k.java:231) ************at java.util.concurrent.ThreadPoolExecutor.runWorker( ThreadPoolExecutor.java:1112) ************at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:587) ************at java.lang.Thread.run(Thread.java:841) 01-13 16:21:08.473 862-862/? W/ContextImpl﹕ Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1505 com.android.server.analytics.data.collection.appli cation.CrashAnrDetector.broadcastEvent:296 com.android.server.analytics.data.collection.appli cation.CrashAnrDetector.processDropBoxEntry:254 com.android.server.analytics.data.collection.appli cation.CrashAnrDetector.access$100:60 com.android.server.analytics.data.collection.appli cation.CrashAnrDetector$1.onReceive:102 01-13 16:21:08.713 862-21154/? E/android.os.Debug﹕ !@Dumpstate > sdumpstate -k -t -z -d -o /data/log/dumpstate_app_error

Here is how I call the service from within my main activity (on button click):

Intent inetnt=new Intent(FileChooser.this, MyService.class);
        startService(inetnt);

And here is the Service code:

public class MyService extends Service {

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onCreate() {
    super.onCreate();
    Toast.makeText(MyService.this, "service start", Toast.LENGTH_LONG).show();
    new FTPUpload().execute();

}

@Override
public void onDestroy() {
    super.onDestroy();


}

@Override
public void onLowMemory() {
    super.onLowMemory();

}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    return super.onStartCommand(intent, flags, startId);

}

public class FTPUpload extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void...params) {

        Toast.makeText(MyService.this, "Service FTP Upload Start", Toast.LENGTH_LONG).show();

        FTPClient con = null;

        try

        {
            con = new FTPClient();
            con.connect("host");

            // Check your USERNAME e.g [email protected] and check your PASSWORD to ensure they are OK.
            if (con.login("username", "password")) {
                con.enterLocalPassiveMode(); // important!
                con.setFileType(FTP.BINARY_FILE_TYPE);

                Random rand = new Random();
                String randomIntString = String.valueOf(rand.nextInt()).replaceAll("-", "");


                FileInputStream in = new FileInputStream("/storage/emulated/0/");
                //con.makeDirectory("/" + randomIntString + "/");
                con.storeFile("advancedsettings.xml", in);
                in.close();


                //PASS URL TO NEXT ACTIVITY AND LAUNCH NEXT ACTIVITY ON NOTIFICATION CLICK


            } else {


            }
        } catch (
                Exception e
                )

        { //if file does not upload successfully, write an error log.
            Toast.makeText(MyService.this, "An error occured, please report: " + e, Toast.LENGTH_LONG).show();
        }

        Toast.makeText(MyService.this, "Service FTP Upload Complete", Toast.LENGTH_LONG).show();

        return null;
    }

}

}

I can confirm I have declared the service in my Android Manifest file within the application tag, as follows:

<service android:name=".MyService"/>

Any ideas guys? Thank you so much in advance for your help! I'm so keen to get to the bottom of this.

K


Solution

  • Please do not access the main thread from doInBackground, like running a Toast. Use onPreExecute for this kind of opperation instead.

    Toast.makeText(MyService.this, 
                   "Service FTP Upload Start", 
                   Toast.LENGTH_LONG).show();
    

    doInBackground should/can not access the UI Thread. For your complete task Toasts try to return a value from doInBackground, you will get the returned value in onPostExecute where you can show your toasts

    For further Information have a look at the Documentation: Documentation