I am using FTP to upload a file. This works great. This file contains information what the app should do.
So I am doing the following:
1) Download the file with Apache FTP Client (seems to work fine)
2) Try to read out the file with a BufferedReader and FileReader.
The problem:
I get a NullPointerException while reading the file. I guess that this is a timing problem.
The code has this structure:
...
getFile().execute();
BufferedReader br = new BufferedReader(...);
How can I solve this problem?
I have to use a seperate Thread (AsyncTask) to download the file because otherwise it will throw a NetworkOnMainThread Exception.
But how can I wait until the file is completely downloaded without freezing the UI?
I cannot use the BufferedReader inside AsyncTask because I use GUI elements and I have to run the interactions on the GUI Thread, but I have no access to it from AsyncTask. RunOnUiThread does not work as well because I am inside a BroadcastReceiver.
Some code:
private class GetTask extends AsyncTask{
public GetTask(){
}
#Override
protected Object doInBackground(Object... arg0) {
FTPClient client = new FTPClient();
try {
client.connect("*****");
}
catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
client.login("*****", "*****");
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileOutputStream fos = null;
try {
fos = new FileOutputStream( "/sdcard/"+userID+".task" );
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
resultOk &= client.retrieveFile( userID+".task", fos );
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}/**
try {
client.deleteFile(userID+".task");
}
catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
**/
try {
client.disconnect();
}
catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
return null;
}
}
The Broadcastreceiver class:
public class LiveAction extends BroadcastReceiver {
...
private Context cont;
FileReader fr = null;
BufferedReader br;
#Override
public void onReceive(Context context, Intent intent)
{
cont = context;
...
new GetTask().execute();
try {
Thread.sleep(3000);
}
catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
fr = new FileReader("/sdcard/"+userID+".task");
}
catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
br = new BufferedReader(fr)
String strline = "";
try {
while ((strline = br.readLine()) != null){
if(strline.equals("taskone")){
//Some GUI Tasks
}
....
This is the relevant code.
I think the best approach would be to read the file's contents from the doInBackground inside the AsyncTask and then output an object which contains the info you need on the onPostExecute method of the async stask and then manipulate your UI.
private AsyncTask<String,Void,FileInfo> getFile(){
return new AsyncTask<String,Void,FileInfo>{
protected FileInfo doInBackground(String url){
FileInfo finfo = new FileInfo(); // FileInfo is a custom object that you need to define that has all the stuff that you need from the file you just downloaded
// Fill the custom file info object with the stuff you need from the file
return finfo;
}
protected void onPostExecute(FileInfo finfo) {
// Manipulate UI with contents of file info
}
};
}
getFile().execute();
Another option is to call another AsyncTask from onPostExecute that does the file parsing but I would not recommend it
I would try some thing like this:
private class GetTask extends AsyncTask{
LiveAction liveAction;
public GetTask(LiveAction liveAction){
this.liveAction = liveAction;
}
...
#Override
protected void onPostExecute(String result) {
liveAction.heyImDoneWithdownloading();
}
}
Ps: why the Thread.sleep(5000)?
public class LiveAction extends BroadcastReceiver {
...
public void heyImDoneWithdownloading(){
//all the things you want to do on the ui thread
}
}
Related
I'm able to clear a single package name's data through this snippet. However, i want it to handle more than one package names. in other words, it should clear two more package names' data
private void clearData() {
//"com.uc.browser.en"
//"pm clear com.sec.android.app.sbrowser"
String cmd = "pm clear com.sec.android.app.sbrowser" ;
ProcessBuilder pb = new ProcessBuilder().redirectErrorStream(true)
.command("su");
Process p = null;
try {
p = pb.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// We must handle the result stream in another Thread first
StreamReader stdoutReader = new StreamReader(p.getInputStream(),
CHARSET_NAME);
stdoutReader.start();
out = p.getOutputStream();
try {
out.write((cmd + "\n").getBytes(CHARSET_NAME));
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
out.write(("exit" + "\n").getBytes(CHARSET_NAME));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
out.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
p.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String result = stdoutReader.getResult();
}
}
The ProcessCommandsSU class starts an su process in which to run a list of commands, and provides an interface to deliver the output to an Activity asynchronously. Unlike the example you're following, this class will not block the UI thread. The Activity must implement the OnCommandsReturnListener interface.
public class ProcessCommandsSU extends Thread {
public interface OnCommandsReturnListener {
public void onCommandsReturn(String output);
}
private final Activity activity;
private final String[] cmds;
public ProcessCommandsSU(Activity activity, String[] cmds) {
if(!(activity instanceof OnCommandsReturnListener)) {
throw new IllegalArgumentException(
"Activity must implement OnCommandsReturnListener interface");
}
this.activity = activity;
this.cmds = cmds;
}
public void run() {
try {
final Process process = new ProcessBuilder()
.redirectErrorStream(true)
.command("su")
.start();
final OutputStream os = process.getOutputStream();
final CountDownLatch latch = new CountDownLatch(1);
final OutputReader or = new OutputReader(process.getInputStream(), latch);
or.start();
for (int i = 0; i < cmds.length; i++) {
os.write((cmds[i] + "\n").getBytes());
}
os.write(("exit\n").getBytes());
os.flush();
process.waitFor();
latch.await();
process.destroy();
final String output = or.getOutput();
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
((OnCommandsReturnListener) activity).onCommandsReturn(output);
}
}
);
}
catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private class OutputReader extends Thread {
private final InputStream is;
private final StringBuilder sb = new StringBuilder();
private final CountDownLatch latch;
public OutputReader(InputStream is, CountDownLatch latch) {
this.is = is;
this.latch = latch;
}
public String getOutput() {
return sb.toString();
}
public void run() {
try {
final BufferedReader reader = new BufferedReader(
new InputStreamReader(is));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
}
catch (IOException e) {
e.printStackTrace();
}
latch.countDown();
}
}
}
Using the class is quite simple. We first ensure that our Activity implements the interface. We then create an instance, passing the Activity and our array of commands in the constructor, and call its start() method. In the following example, it's assumed that the Activity has a TextView named textOutput to display the returned output:
public class MainActivity extends Activity
implements ProcessCommandsSU.OnCommandsReturnListener {
...
#Override
public void onCommandsReturn(String output) {
textOutput.append(output + "\n");
}
private void runCommands() {
final String[] cmds = {
"ping -c 5 www.google.com",
"pm list packages android",
"chdir " + Environment.getExternalStorageDirectory(),
"ls"
};
new ProcessCommandsSU(MainActivity.this, cmds).start();
}
}
My device is not rooted, so this was tested with the commands you see in the code above. Simply replace those commands with your pm clear commands.
I'm currently learning about IO and Async but am having issues. I'm following a guide, and according to the guide this is supposed to work. I have created an activity with a simple EditText, TextView, and 2 Buttons(save and load). I am trying to have the save button take the text in the EditText and save to internal storage, and the load button take whatever is saved and set the TextView as that. Everything works flawlessly when I put all the code to run in the UI thread, but if I change the code to have the UI thread call the Async class for the loading, nothing seems to happen.
**Packages and imports have been removed to save space.
public class InternalData extends Activity implements OnClickListener {
EditText etSharedData;
TextView tvDataResults;
FileOutputStream fos;
String FILENAME = "InternalString";
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.sharedpreferences);
setupVariables();
}
private void setupVariables() {
Button bSave = (Button) findViewById(R.id.bSave);
Button bLoad = (Button) findViewById(R.id.bLoad);
etSharedData = (EditText) findViewById(R.id.etSharedPrefs);
tvDataResults = (TextView) findViewById(R.id.tvLoadSharedPrefs);
bSave.setOnClickListener(this);
bLoad.setOnClickListener(this);
try {
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.bSave:
String sData = etSharedData.getText().toString();
try {
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(sData.getBytes());
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case R.id.bLoad:
String sCollected = null;
FileInputStream fis = null;
try {
fis = openFileInput(FILENAME);
byte[] dataArray = new byte[fis.available()];
while(fis.read(dataArray) != -1){
sCollected = new String(dataArray);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
try {
fis.close();
tvDataResults.setText(sCollected);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
}
}
The previous code makes everything work, but the UI lags a bit when trying to load large strings. When I try to have an LoadSomeStuff(Async) class do the loading, it does absolutely nothing when I hit Load on my phone. Within the LoadSomeStuff class it has the doInBackground method open the file and read the data into a string then return that string, and the onPostExecute method set the TextView's text to the returned String. Here's the code:
The onClick method for load button has:
new LoadSomeStuff().execute(FILENAME);
LoadSomeStuff Class *Note: This class is declared within the InternalData class.
public class LoadSomeStuff extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
String sCollected = null;
FileInputStream fis = null;
try {
fis = openFileInput(FILENAME);
byte[] dataArray = new byte[fis.available()];
while(fis.read(dataArray) != -1){
sCollected = new String(dataArray);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
try {
fis.close();
return sCollected;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
protected void onPostExecute(String result){
tvDataResults.setText(result);
}
}
}
Any help is greatly appreciated, thanks!
It actually looks like I had an extra method or two(like onPreExecute) with no code in them and when I deleted them it starting working.
I follow one manual to upload images from Android to FTP. If I try to update a photo that have taken I can't see anything on the FTP file. It creates and the size is ok, but contains nothing. Then i try to upload one little image and this is the result:
(Random image to upload)
(Image uploaded)
The code: `class Sender extends AsyncTask
{
File photo;
public Sender(File photo){
this.photo=photo;
}
protected String doInBackground(String... params)
{
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(InetAddress.getByName("ftp.fercode.com"));
ftpClient.login(xxx","xxx");
Boolean result = ftpClient.changeWorkingDirectory("/img");
Log.e("existeix carpeta?",result.toString() );
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
InputStream srcFileStream=null;
try {
srcFileStream = new FileInputStream(photo.getAbsolutePath());
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//ftpClient.stor(photo.getAbsolutePath());
boolean status = ftpClient.storeFile("/img/imagePrueba.jpeg",
srcFileStream);
Log.e("Status", String.valueOf(status));
srcFileStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
return null;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected void onPostExecute(String result)
{
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}`
What I'm doing wrong? Thx a lot
That happens because I upload the image like ASCII and not binary. It's just a configuration parameter:
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
I am writing an application to download files from ftp server. The code exits with error - UnknownHostException. The site is valid and I have opened it in filezilla. The code follows -
public class Downloader extends AsyncTask<String, Integer, String> {
private FTPClient mFtp;
private FTPFile[] files;
public Downloader() {
mFtp=new FTPClient();
try {
mFtp.connect(InetAddress.getByName("fenils.in"));
// mFtp.connect("ftp://fenils.in");
mFtp.login("*****", "******");
mFtp.setFileType(FTP.BINARY_FILE_TYPE);
mFtp.enterLocalPassiveMode();
files=mFtp.listFiles("/pankaj/beta");
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected String doInBackground(String... arg0) {
FileOutputStream fos = null;
try {
for(FTPFile f:files){
fos=new FileOutputStream("alpha/"+f.getName());
mFtp.retrieveFile(f.getName(), fos);
}
fos.close();
mFtp.logout();
mFtp.disconnect();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Any help is appreciated. Thanks in advance.
Sorry. My mistake. I neglected to set the uses internet permission. I found the answer here Java ftpclient application doesn't connect
I have a class that contains 2 functions:
public class FileHandler extends Activity {
public void writeToFile(){
String fileName = "lastDevice.txt";
try {
FileOutputStream fos = openFileOutput(fileName, MODE_PRIVATE); //Exception thrown here
fos.write("some device id".getBytes());
fos.close();
Toast.makeText(this, "File updated", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String readFromFile(){
try {
String fileName = "lastDevice.txt";
FileInputStream fis = openFileInput(fileName); //Exception thrown here
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String sLine = null;
String data ="";
while ((sLine = br.readLine())!=null) {
data+= sLine;
}
return data;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "FileNotFoundException";
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "IOException";
} catch (NullPointerException e){
// TODO Auto-generated catch block
e.printStackTrace();
return "Null Pointer Exception";
}
}
these functions are called from my main activity as follows:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvDevices = (ListView)findViewById(R.id.ListViewDevices);
lastDeviceTxt = (TextView)findViewById(R.id.lastDeviceTxt);
//get last connected device
FileHandler fh = new FileHandler();
String last = fh.readFromFile();
lastDeviceTxt.setText(last);
}
but i keep getting a NullPointerException from both functions.
when running the functions from my MainActivity (I copied them to my main activity) they work fine.
What am I doing wrong? (please remember that I'm very new to android development).
You've defined FileHandler as an Activity. You can't instantiate an Activity yourself, which you are doing here:
FileHandler fh = new FileHandler();
Activities need to be instantiated by the Android framework (otherwise their context isn't set up correctly).
If you don't want these methods in your own Activity, then you can put them in another class. However, that class cannot inherit from Activity. You will then find that you need to pass your Activity's Context to these methods so that they can call methods like openFileInput()