7

I am using the following code to make the android device a ftp server (Android Internal storage). I am getting the exception of os.android.NetworkOnMainThread. I have tried to put the onStart code in the AsyncTask but app never executes and crashes on launch. Any help regarding the ftp server on Android will be great as i have no idea how to get it working.

Here is the MainActivity Code

package com.googlecode.simpleftp;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;


public class FTPServer extends Activity {
    private static int COMMAND_PORT = 2121;
    static final int DIALOG_ALERT_ID = 0;
    private static ExecutorService executor  = Executors.newCachedThreadPool();

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.my_menu, menu);
            return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {    
            // Handle item selection    
            switch (item.getItemId()) {
                    case R.id.new_game:    
                            System.out.println("New game button is pressed!");
                            //newGame();        
                            return true;    
                    case R.id.quit:        
                            System.out.println("Quit button is pressed!");
                            showDialog(DIALOG_ALERT_ID);        
                            return true;    
                    default:        
                            return super.onOptionsItemSelected(item);    }
    }

    @Override
    protected Dialog onCreateDialog(int id){
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage("Are you sure you want to exit?")
            .setCancelable(false).setPositiveButton("yes", new DialogInterface.OnClickListener(){
                    @Override
                    public void onClick(DialogInterface dialog, int id){
                            FTPServer.this.finish();
                    }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();

                    }
            });
            AlertDialog alert = builder.create();
            return alert;
    }

HEre is the ServerPI Code

 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.net.Socket;

 public class ServerPI implements Runnable{
    private Socket clientSocket;
    private BufferedReader in;
    private PrintWriter out;

    private String baseDir;
    private String relativeDir;
    private String absoluteDir;
    private String fileName;
    private String filePath;

    public ServerPI(Socket incoming) throws IOException{
            this.clientSocket = incoming;
            in = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
            out = new PrintWriter(this.clientSocket.getOutputStream(), true);

            baseDir = new File("").getAbsolutePath();

            relativeDir = "/";
            absoluteDir = baseDir + relativeDir;
            fileName = "";
            filePath = absoluteDir + "/" + fileName;
    }

    private void readCommandLoop() throws IOException {
            String line = null;
            reply(220, "Welcome to the SimpleFTP server!");
            while((line = in.readLine()) != null){
                    int replyCode = executeCommand(line.trim());
                    if(replyCode == 221){
                            return;
                    }
            }
    }

    private int executeCommand(String trim) {
            // TODO Auto-generated method stub
            return 0;
    }

    public int reply(int statusCode, String statusMessage){
            out.println(statusCode + " " + statusMessage);
            return statusCode;
    }

    @Override
    public void run(){
            try{
                    this.readCommandLoop();
            } catch (IOException e){
                    e.printStackTrace();
            }
            finally {
                    try {
                            if(in != null){
                                    in.close();
                                    in = null;
                            }
                            if(out != null){
                                    out.close();
                                    out = null;
                            }
                            if (clientSocket != null){
                                    clientSocket.close();
                                    clientSocket = null;
                            }
                    }
                    catch (IOException e){
                            e.printStackTrace();
                    }
            }
    }
    }

I have put the code in the AsyncTask, here it is

   private class LongOperation extends AsyncTask<String, Void, String> {

      @Override
      protected String doInBackground(String... params) {
           ServerSocket s = null;
    Socket incoming = null;

    try{
            s = new ServerSocket(COMMAND_PORT);
            String ip = (s.getInetAddress()).getHostAddress();
            Context context = this.getApplicationContext();
            CharSequence text = ip;
            int duration = Toast.LENGTH_LONG;

            Toast toast = Toast.makeText(context, text, duration);
            Thread.sleep(1000);
            toast.show();
            while(true){
                    incoming = s.accept();
                    executor.execute(new ServerPI(incoming));
            }
    }
    catch(Exception e){
            System.out.println(e.toString());
            e.printStackTrace();
    }
    finally{
            try
                    {
                            if(incoming != null)incoming.close();
                    }
                    catch(IOException ignore)
                    {
                            //ignore
                    }

                    try
                    {
                            if (s!= null)
                            {
                                    s.close();
                            }
                    }
                    catch(IOException ignore)
                    {
                            //ignore
                    }
    }

            return "Executed";
      }      

      @Override
      protected void onPostExecute(String result) {               
      }

      @Override
      protected void onPreExecute() {
      }

      @Override
      protected void onProgressUpdate(Void... values) {
      }
}

Iam calling the longOpertation in onCreate method. What is the problem that the app crashes on launch.

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_fullscreen);
            new LongOperation().execute();
    }
Jibran Khan
  • 3,236
  • 4
  • 37
  • 50

5 Answers5

3

Maybe because you didn't set up the permissions in the manifest? You've to set permission for internet usage.

If this doesn't work, please tell us which line is it throwing the exception.

Reinherd
  • 5,476
  • 7
  • 51
  • 88
  • Already set the permissions of internet access in manifest file. – Jibran Khan Apr 09 '13 at 07:09
  • The exception in occurring on the first try catch block, means the socket connection never opens and the ip is displayed as 0.0.0.0 – Jibran Khan Apr 09 '13 at 07:12
  • It seems that your command to get ip address isn't working well. I've google and it seems that it's always returning 0.0.0.0. Check this post. You've an answer about how to get ip address http://stackoverflow.com/questions/7086734/how-to-get-my-ip-address – Reinherd Apr 09 '13 at 07:21
  • Cool, let me check and get back to you. – Jibran Khan Apr 09 '13 at 07:24
  • It did got the ip address displayed but in hexa format :) how can i figure that out in string or number what ever it returns ? – Jibran Khan Apr 09 '13 at 07:29
  • I'm not sure, I just found that information, but which format is that hex string? Its "easy" to parse a hex, as it's actually a number. http://www.statman.info/conversions/hexadecimal.html try this manually. If it gives a logic result, try to make a simple parser :) – Reinherd Apr 09 '13 at 08:22
  • Ip address is now displayed correctly, how now i should get it to work as a ftp server for my pc. If you can test the application then check Virtual Data Cable on play store. – Jibran Khan Apr 09 '13 at 09:38
2

while(true){ incoming = s.accept(); ...} You cannot put that in OnStart(). That should be done in a thread. So ServerSocket s = null; should be a variable of you activity.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • How should i put that in a separate thread or Async task. Can you show me a example ? – Jibran Khan Apr 09 '13 at 10:17
  • I have created a AsyncTask and all the code is now in that task body, i am calling the Async Task execute method in onCreate() function, is it correct ? It is crashing the application without even launching. – Jibran Khan Apr 09 '13 at 10:30
2

So I went with Swiftp application (open source) as a service in my application which helped me to achieve my task. Thanks everyone who stepped forward to help. Here is the link if someone wants to follow

Jibran Khan
  • 3,236
  • 4
  • 37
  • 50
1

Please post your code here.

NetworkOnMainthreadException occurs because you maybe running Network related operation on the Main UI Thread. You should use asynctask for this purpose

This is only thrown for applications targeting the Honeycomb SDK or higher. Applications targeting earlier SDK versions are allowed to do networking on their main event loop threads, but it's heavily discouraged.

http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html

class TheTask extends AsyncTask<Void,Void,Void>
{
protected void onPreExecute()
  {           super.onPreExecute();
             //display progressdialog.
  }  

protected void doInBackground(Void ...params)//return result here
{  
//http request. do not update ui here
//call webservice
//return result here
return null;
 } 

protected void onPostExecute(Void result)//result of doInBackground is passed a parameter
{     
    super.onPostExecute(result);
    //dismiss progressdialog.
    //update ui using the result returned form doInbackground()
} 
}

http://developer.android.com/reference/android/os/AsyncTask.html. Check the topic under the heading The 4 Steps.

A working example of asynctask @ To use the tutorial in android 4.0.3 if had to work with AsynxTasc but i still dont work?.

The above makes a webserive call in doInBakckground(). Returns result and updates the ui by setting the result in textview in onPostExecute().

Community
  • 1
  • 1
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • post logcat are you getting any exception in logcat – Raghunandan Apr 09 '13 at 11:33
  • I am not getting any exception but on this: while(true){ incoming = s.accept(); executor.execute(new ServerPI(incoming)); } it stops execution here and threadpoolexecuter class error occurs. – Jibran Khan Apr 09 '13 at 12:04
  • doinBackground() already runs in background. Why do you need executor.execute()? If you want parallel execution don't use asynctask – Raghunandan Apr 09 '13 at 12:07
  • If i dont use the AsyncTask then it gives me the network os onMainthread exception, is there any other way to handle this – Jibran Khan Apr 09 '13 at 12:09
  • use asynctask but not executor.execute() in doInbackground(). If you want parrallel execution don't use asyntask, use a exector instead. http://developer.android.com/reference/java/util/concurrent/Executor.html – Raghunandan Apr 09 '13 at 12:14
  • I executor.execute() is calling the ServerPI class for connectivity so may be this is neccessary. Again i am just following the code from google code. – Jibran Khan Apr 09 '13 at 12:16
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27854/discussion-between-raghunandan-and-jibran-khan) – Raghunandan Apr 09 '13 at 12:17
0

You can not do network operation in main thread in android 3.0 higher. Use AsyncTask for this network operation. See this for further explanation

Arun C
  • 9,035
  • 2
  • 28
  • 42
  • I tried to put the code in background Async task and executed it in onCreate method but the app crashed on launch. – Jibran Khan Apr 09 '13 at 07:23
  • In that case what is the exception you are getting – Arun C Apr 09 '13 at 07:26
  • It never runs the app and thus not able to cath the exception. Can you post any working sample of Async task or edit my code above so i can be on a right track – Jibran Khan Apr 09 '13 at 07:32
  • I am getting the exception on while(true){ incoming = s.accept(); executor.execute(new ServerPI(incoming)); } this. – Jibran Khan Apr 09 '13 at 11:02
  • 1
    No on the Toast. You cannot use Toast() in doInBackGround() as it concerns the UI. Also do away with String ip; and getting the ip as that will not work as you know by now. Please show how you instantiate and call your asynctask in onCreate(); – greenapps Apr 09 '13 at 13:38