I recently created an activity in my app. Now I wanted the user to download a .pdf file when he/she wants to view the guidelines. I wanted to implement this on a button. Any idea how to do this properly?
Heres my code below:
public class Exhibitor_Registration_Activity extends AppCompatActivity {
Button buttonDownload;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exhibitor_registration_);
this.setTitle("Buyer Registration");
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
myToolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);
final Button buttonDownload = (Button) findViewById(R.id.buttonDownload);
buttonDownload.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
try {
//this is the file you want to download from the remote server
String path ="http://www.manilafame.com/website-assets/downloads/exhibitor-application-kit/local/201704/1-Summary-of-Participation-Details-April-2017_MN_002.pdfp";
//this is the name of the local file you will create
String targetFileName = null;
boolean eof = false;
URL u = new URL(path);
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
FileOutputStream f = new FileOutputStream(new File("c:\\junk\\"+targetFileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
f.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
}
I also got the source code from here and here.
if you want resumable, speed of download ...
follow this steps
create a class DownloadManager.java
public class DownloadManager extends AsyncTask<String,String,String>{
String downloadlink,fileDestination;
public static final int ON_INIT=100,ON_ERROR=102,ON_PROGRASS=103,ON_COMPLETED=104,STATUS_DOWNLOADED=1500,STATUS_NOT_YET=1501;
private onUpdateListener onUpdateListener;
private String downloadedPath="";
private long downloaded=0;
private File file;
private String returnData=null;
private File cacheDownloadFile;
public DownloadManager(String downloadlink,String fileDestinationPath){
this.downloadlink=downloadlink;
this.fileDestination=fileDestinationPath;
file=new File(fileDestination, Tools.getFileName(downloadlink));
cacheDownloadFile=new File(AppCostants.CHACHE_PATH+Tools.getFileName(downloadlink));
try {
if(cacheDownloadFile.isFile())
downloaded=Tools.getFileSize(cacheDownloadFile);
else
downloaded=0;
Log.d("FILE_DOWNLOAD_TAG_p",downloaded+" <- "+cacheDownloadFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
fireOnUpdate(ON_INIT,"init ...");
}
#Override
protected String doInBackground(String... params) {
try {
File dir=new File(fileDestination);
File chacheDir=new File(AppCostants.CHACHE_PATH);
if(!chacheDir.isDirectory())
chacheDir.mkdirs();
if(!dir.isDirectory()){
dir.mkdirs();
}
if(file.exists()) {
Log.d("FILE_DOWNLOAD_TAG","File exist return complete");
return "COMPLETED";//file exist
}
if(!cacheDownloadFile.exists()){
cacheDownloadFile.createNewFile();
}
Log.d("FILE_DOWNLOAD_TAG","LINK "+downloadlink);
URL url=new URL(downloadlink);
HttpURLConnection urlConnection= (HttpURLConnection) url.openConnection();
if(downloaded>0)
urlConnection.setRequestProperty("Range","byte="+downloaded);
urlConnection.connect();
int status = urlConnection.getResponseCode();
InputStream inputStream=urlConnection.getInputStream();
int totalSize=urlConnection.getContentLength();
if(totalSize<=downloaded){
returnData= "COMPLETED";
publishProgress("File checked "+Tools.getFileName(file.getAbsolutePath()));
return returnData;
}
this.downloadedPath=cacheDownloadFile.getAbsolutePath();
byte[] buffer=new byte[1024];
int bufferLength=0;
FileOutputStream fileOutput=new FileOutputStream(cacheDownloadFile);
long d=0;
long starttime=System.currentTimeMillis();
while ((bufferLength=inputStream.read(buffer))>0){
fileOutput.write(buffer,0,bufferLength);
downloaded+=bufferLength;
d+=bufferLength;
//String l=" "+Tools.getFileName(file.getAbsolutePath())+" ( "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" )";
String l=" "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" ( "+getDownloadSpeed(starttime,d)+" )";
publishProgress(l);
if(downloaded>=totalSize){
break;
}
}
Log.d("FILE_DOWNLOAD_TAG","DWONLOADED TO "+downloadedPath+" ("+cacheDownloadFile.length()+")");
fileOutput.close();
if(Tools.fileCopy(file,cacheDownloadFile)){
Log.d("FILE_DOWNLOAD_TAG","file Copied, delete cache");
cacheDownloadFile.delete();
}
returnData="COMPLETED";
} catch (MalformedURLException e) {
returnData=null;
e.printStackTrace();
publishProgress(e.toString());
Log.d("###################",e+"");
} catch (IOException e) {
returnData=null;
e.printStackTrace();
publishProgress(e.toString());
}
return returnData;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
fireOnUpdate(ON_PROGRASS,values[0]);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if(s!=null){
fireOnUpdate(ON_COMPLETED,downloadedPath);
}else{
fireOnUpdate(ON_ERROR,"Download failed");
}
}
public interface onUpdateListener{
void onUpdate(int code,String message);
}
public void setOnUpdateListener(onUpdateListener onUpdateListener){
this.onUpdateListener=onUpdateListener;
}
private void fireOnUpdate(int code,String message){
if(onUpdateListener!=null)
onUpdateListener.onUpdate(code,message);
}
private String getDownloadSpeed(long starttime,float totalDownloaded) {
long elapsedTime = System.currentTimeMillis() - starttime;
//byte :
float speed=1000f * totalDownloaded / elapsedTime;
return convert(speed);
}
private String convert(float value){
long kb=1024
,mb=kb*1024
,gb=mb*1024;
if(value<kb){
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.')+2);
return speed+" B/s";
}else if(value<mb){
value=value/kb;
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.'));
return (speed)+" KB/s";
}else if(value<gb){
value=(value/mb);
String speed=(value+"");
speed=speed.substring(0,speed.indexOf('.'));
return speed+" MB/s";
}
return "";
}
}
use this code in onClick()
DownloadManager downloadManager = new DownloadManager(url,filepath);
set event
downloadManager.setOnUpdateListener(new DownloadManager.onUpdateListener() {
#Override
public void onUpdate(int code, String message) {
if (code == DownloadManager.ON_COMPLETED) {
}
if(DownloadManager.ON_PROGRASS==code){}
}
});
start download by
downloadManager.execute();
lib setup
compile "commons-io:commons-io:+"
Tools.java
public static long getFileSize(File file) throws IOException {
FileOutputStream fileOutputStream=new FileOutputStream(file);
fileOutputStream.close();
return file.length();
}
public static boolean fileCopy(File dest,File source){
try {
FileUtils.copyFile(source,dest);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
It is really bad idea to download file in main thread.
Use separate Thread for this
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
//your downloading here
}
});
thread.start();
it`s better, but still not so good. There are some problems with it:
1) User know nothing about downloading
So better to show additional layout which overlays screen with progress bar, probably indeterminate if you want to write less code. Then after downloading is finished you just hide your layout.
You can use runOnUiThread inside run method in thread for it.
runOnUiThread(new Runnable() {
#Override
public void run() {
//just hide some popup
//or do what you want after downloading is finished
popupLayout.serVisibility(View.GONE);
}
});
2) If user will do action which re-creates activity/fragment (like changing screen orientaion) with running thread you will get memory leak and probably activity will not know about end of download.
There are few ways to solve this problem:
You can block screen orientation at this screen, at least while downloading. Probably easiest way in your case.
You can use downloading in foreground service. Its really good
practice, but you will have to learn about services.
You can try to interrupt downloading by calling thread.interrupt()
method in onDestroy of your Activity/Fragment
You can use something like rxJava/rxAndroid (so you don not use threads at all, but you need some time for learn rxJava)
UPD
About threads
Not so bad tutorial about threads in android
You can use AsyncTask instead of Thread, but I highly recommend to use threads especially for long operations.
Related
Background:
I am using three fragments and one activity in my application. Two fragments use recyclerViews and the other uses an expandableListView.
Problem:
I am trying to properly program the onPause(), onResume(), onStop(), and onRestart() methods to save the state of my application when the home, back, or switch views buttons are pressed.
To save the state of the program and load it when it comes back I have created the save() and load() methods in my one and only activity.
//from the end of onCreate
load();
}
#Override
protected void onStart() {
super.onStart();
mRef = new Firebase("https://sure-7856d.firebaseio.com/");
}
#Override
protected void onStop(){
super.onStop();
save();
}
#Override
protected void onPause(){
super.onPause();
save();
}
#Override
protected void onResume(){
super.onResume();
load();
}
#Override
protected void onRestart(){
super.onRestart();
load();
}
In the save method I get the adapters from my 2 recyclerViews and my expandableListView`s ArrayList that keeps track of which checkboxes are checked.
After that I put them each into a temporary Arraylist then I add each of those ArrayLists to a single arraylist that will be saved to the file.
private void save(){
//saved_data = new File("saved_data");
/*try {
if(saved_data.exists()==false){
//saved_data.createNewFile();
saved_data.setWritable(true);
}
} catch (IOException e) {
e.printStackTrace();
}*/
File myFile;
try{
myFile = new File(getFilesDir().getAbsolutePath(), "dir/save_data.bin");
myFile.mkdirs();
myFile.createNewFile();
FILENAME = myFile.getName();
}catch (IOException e){
e.printStackTrace();
}
OneFragment f20 = (OneFragment) frags.get(0);
TwoFragment f21 = (TwoFragment) frags.get(1);
ThreeFragment f22 = (ThreeFragment) frags.get(2);
ArrayList saveTasks = f20.adapter.getList();
ArrayList saveReqs = f21.adapter.getList();
ArrayList saveMap = new ArrayList<String>();
if(f22.listAdapter!=null) {
if (f22.listAdapter.getExport() != null) {
saveMap = f22.listAdapter.getExport();
}
}
ArrayList results = new ArrayList();
results.add(saveTasks);
results.add(saveReqs);
results.add(saveMap);
ObjectOutputStream oos1 = null;
FileOutputStream fos1 = null;
try {
fos1 = openFileOutput(FILENAME, Context.MODE_PRIVATE);
oos1 = new ObjectOutputStream(fos1);
oos1.writeObject(results);
oos1.close();
fos1.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(oos1 != null){
try {
oos1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
In the load code I get the object from the file and update the adapters to their previous state.
private void load(){
//saved_data = new File("saved_data");
ArrayList results = new ArrayList();
FileInputStream fis = null;
ObjectInputStream ois = null;
if(FILENAME==null){
return;
}
try {
fis = new FileInputStream(FILENAME);
ois = new ObjectInputStream(fis);
}catch (FileNotFoundException e) {
e.printStackTrace();
return;
}catch (IOException e) {
e.printStackTrace();
}
try {
while (true) {
results = (ArrayList)(ois.readObject());
}
} catch (OptionalDataException e) {
if (!e.eof) try {
throw e;
} catch (OptionalDataException e1) {
e1.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ois.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
for(int i = 0; i < results.size();i++){
if(i == 0){
frags.set(0,results.get(i));
}
else if(i == 1){
frags.set(1,results.get(i));
}
else if(i == 2){
frags.set(2,results.get(i));
}
else{
}
}
}
When I press the square button at the bottom of the emulator and go back to it one of a few things happen
It crashes saying the file could not be found
W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
And this error points to the load method as the point of failure specifically
FileInputStream fis = null;
When I hit the triangle button nothing happens in logcat, everything is gone upon returning, and the app loses its functions of adding strings to lists on both recyclerViews and displaying both lists in the expandableListView.
Hitting the center circle button and going back to the app is fine nothing breaks.
Since Im getting a file not found error I think that the file isnt getting written
I have searched Stack for a solution and I am new to File IO and fragments, so I have no idea where to go from here.
I want my program to download many images (around 500) from the internet and store them in my external storage. Currently when I download a single image, it shows a progressBar and downloads the image properly. However when I am trying to replicate w/ two images, it gives the Toast for "Download complete" for both images being downloaded, however no progressBar for either image is shown and only the first image is properly downloaded.
Here is the code for my onCreate method for activity.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Remove Title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//force portrait orientation. (No landscape orientation).
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_quran);
//Instantiate ProgressDialog (Used for downloading quran pages).
myProgressDialog = new ProgressDialog(QuranActivity.this);
myProgressDialog.setMessage("Downloading Quran");
myProgressDialog.setIndeterminate(true);
myProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
myProgressDialog.setCancelable(true);
//execute when the downloader must be fired.
final DownloadTask downloadTask = new DownloadTask(QuranActivity.this);
DownloadTask second = new DownloadTask(getApplicationContext());
myHTTPURL = "https://ia601608.us.archive.org/BookReader/BookReaderImages.php?zip=/10/items/05Quran15LineWhitePageWithVioletBorderWww.Momeen.blogspot.com/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2.zip&file=05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_0001.jp2&scale=1&rotate=0";
myHTTPURL2 = "https://ia601608.us.archive.org/BookReader/BookReaderImages.php?zip=/10/items/05Quran15LineWhitePageWithVioletBorderWww.Momeen.blogspot.com/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2.zip&file=05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_jp2/05%20Quran%2015%20Line%20[White%20page%20with%20Violet%20border]%20-%20www.Momeen.blogspot.com_0002.jp2&scale=1&rotate=0";
//First check if the file has already been created. (Only need to download 1ce, or
//in the case where the user deleted the files, we reinstall them again).
if (isExternalStorageWritable()) {
File makeDirectory = getQuranStorageDir(QuranActivity.this, "Quran_Pages");
for (int i = 0; i < 2; i++) {
Bundle myBundle = new Bundle();
myBundle.putInt("i", i);
if (i == 0) {
downloadTask.execute(myHTTPURL);
try {
downloadTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
myProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
downloadTask.cancel(true);
}
});
} else {
/*if (downloadTask.getStatus() == AsyncTask.Status.FINISHED) {
downloadTask.execute(myHTTPURL2);
} else if (downloadTask.getStatus() == AsyncTask.Status.RUNNING) {
try {
downloadTask.execute(myHTTPURL2).wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} */
second.execute(myHTTPURL2);
try {
second.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// downloadTask.execute(myHTTPURL2);
}
}
}
and this is the code for my AsynTask Class.
#TargetApi(Build.VERSION_CODES.FROYO)
private class DownloadTask extends AsyncTask {
private Context context;
private PowerManager.WakeLock myWakeLock;
public DownloadTask(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... sUrl) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
try {
URL url = new URL(sUrl[0]);
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return "Server returned HTTP " + connection.getResponseCode()
+ " " + connection.getResponseMessage();
}
//Display download percentage.
int fileLength = connection.getContentLength();
//create folder to place the downloaded file in.
// File Path:E:\Android\data\com.syedabdullah.syed.quran_memorization_application
// \files\Quran Memorization Application\Quran_Pictures
//So first create a root folder Quran Memorization Application then inside that
//folder we create another folder named Quran Pictures.
/* File rootFolder = new File(getExternalFilesDir("Quran Memorization Application"),
"Quran_Pages"); */
//Here we insert inside the Quran_Pictures folder the quran_pages.
//String myFileName = "quran_01.jpg";
Bundle y = new Bundle();
int retrievePos = y.getInt("i");
String quranFilePageName = "_" + retrievePos + ".jpg";
// String fileName = "justwork.jpg";
File sup = new File(getExternalFilesDir("Quran Memorization Application"), "Quran_Pages");
File myFile = new File(sup, quranFilePageName);
myFile.createNewFile();
//downlaod the file.
input = connection.getInputStream();
output = new FileOutputStream(myFile);
byte data[] = new byte[4096];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
//allow cancel with back button.
if (isCancelled()) {
input.close();
return null;
}
total += count;
//publish the progress.
if (fileLength > 0) {
publishProgress((int) (total * 100 / fileLength));
}
output.write(data, 0, count);
}
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(myFile));
QuranActivity.this.sendBroadcast(intent);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (output != null) {
output.close();
}
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (connection != null) {
connection.disconnect();
}
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//Take CPU lock to prevent CPU from going off if the user presses the power button.
//during download.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
myWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
myWakeLock.acquire();
myProgressDialog.show();
}
#Override
protected void onProgressUpdate(Integer... progress) {
super.onProgressUpdate(progress);
//If we get here length is known, so setIndertimante to false.
myProgressDialog.setIndeterminate(false);
myProgressDialog.setMax(100);
myProgressDialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
myWakeLock.release();
myProgressDialog.dismiss();
if (result != null) {
Toast.makeText(context, "Download error: " + result, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "Download Complete", Toast.LENGTH_SHORT).show();
}
}
} }
I was hoping to have a for loop that would create hundreds of downloadTasks and download all the images I need, and then I would call the get method. However in order for that to work, I first need too know why when I try for 2 images only the first one gets downloaded and why no progressbar shows up. Also if possible if I could get a hint as to how I can make my progressBar update for all the images and not be designed for just 1. Thanks in advance. (Note all URLs are currect.)
Thank you so much! figured out that my loops were suppose to go inside doInBackground. Also to anyone else having a similar issue. To download multiple files and display a decent progressBar, here is a very great tutorial: http://theopentutorials.com/tutorials/android/dialog/android-download-multiple-files-showing-progress-bar/
I'm not that much experienced in Android, so every piece of code I have written so far was very simple. Now I need to implement a localization and navigation application, so I need to break my code into modules so that I can change each component alone. I have some variables that I need to share them between different classes. I used static variables but I read in some posts here that static variables are not preferred. Then I found some other posts talking about Context. So I created a class named Globals and I added the following lines in my Manifest file:
<application android:name="com.example.smartnav.Globals"
package="com.example.smartnav"
android:icon="#drawable/ic_launcher"
android:allowBackup="true"
android:label="#string/app_name"/>
And here is the Globals Class :
package com.example.smartnav;
import java.util.List;
import android.net.wifi.ScanResult;
import android.app.Application;
public class Globals extends Application {
private Boolean Scanning=false;
private String Logname;
private int interval;
private int numOfScans;
private List<ScanResult> result;
//getters
public Boolean getScannig(){
return Scanning;
}
public int getInterval()
{
return interval;
}
public int getScans()
{
return numOfScans;
}
public List<ScanResult> getRes()
{
return result;
}
public String getLog()
{
return Logname;
}
//setter
public void setScanning(Boolean s){
Scanning= s;
}
public void setRes(List<ScanResult> res)
{
result =res;
}
public void setInterval(int I)
{
interval = I;
}
public void setScans(int S)
{
numOfScans=S;
}
public void setLog(String s)
{
Logname= s;
}
}
Now I have two questions, the first one is that my application keeps crashing whenever I try to use the Globals class, here is the code: Did I use context incorrectly?
public class MainActivity extends Activity {
private Context context;
public WifiManager Wifi;
private WifiReceiver receiverWifi;
private IntentFilter filter;
private List<ScanResult> result;
private File AppDir;
private static String filename;
private File file;
private FileWriter writer;
private Globals AppState ;
private int Interval;
private int numOfScans;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("Main ","activity created");
//
AppState = ((Globals)getApplicationContext());
context= this;
Wifi=(WifiManager) getSystemService(Context.WIFI_SERVICE);
receiverWifi = new WifiReceiver();
filter= new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
registerReceiver(receiverWifi, filter);
Log.d("Main ","wifi registered");
// create the application directory
AppDir = new File(Environment.getExternalStorageDirectory()+"/SmartNavi/Log");
if(AppDir.isDirectory())
{
filename=Environment.getExternalStorageDirectory()+"/SmartNavi/Log/log.txt";
file = new File(filename);
if(!file.exists())
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
else
{
Date d= new Date();
filename=Environment.getExternalStorageDirectory()+"/SmartNavi/Log/log"+d.getTime()+".txt";
file = new File(filename);
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
else
{
AppDir.mkdirs();
filename=Environment.getExternalStorageDirectory()+"/SmartNavi/Log/log.txt";
file = new File(filename);
if(!file.exists())
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
else
{
Date d= new Date();
filename=Environment.getExternalStorageDirectory()+"/SmartNavi/Log/log"+d.getTime()+".txt";
file = new File(filename);
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//setting pars
Interval=250;
numOfScans=4;
AppState.setInterval(Interval);
AppState.setScans(numOfScans);
AppState.setLog(filename);
Wifi.startScan();
try {
writer = new FileWriter(file, true);
writer.append("Smart Navigation. \n");
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// AsyncScanning.AsyncScan();
}//on create
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
class WifiReceiver extends BroadcastReceiver {
public void onReceive(Context c, Intent intent) {
result=Wifi.getScanResults();
// AppState.setRes(result);
try {
writer = new FileWriter(file, true);
writer.append(result.size()+" s \n");
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//end of on receive
}// end of class
} // end of smartNav
My last question is this : I have read on some answers here that if my application becomes a background process then all the data in the context will be set to null, and I will lose my context. Is there is any method to overcome this point? or should I switch to SharedPreferences ?
Edit :Here is the output of Logcat
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.smartnav/com.example.smartnav.MainActivity}: java.lang.ClassCastException: android.app.Application cannot be cast to com.example.smartnav.Globals
Now I have two questions, the first one is that my application keeps crashing whenever I try to use the Globals class, here is the code: Did I use context incorrectly?
you should use getApplication() method for that, or make your application class singleton, so you would call Globals.getInstance().getMyVariable() etc.
My last question is this : I have read on some answers here that if my application becomes a background process then all the data in the context will be set to null, and I will lose my context. Is there is any method to overcome this point? or should I switch to SharedPreferences ?
if your app becomes background then Android is more likely to kill your app, and this way also destroy all your static objects. Inside your Globals class you should not store your data in static variables but rather in some persistant storage - if its small then use SharedPreferences, if its large then you can store it in json and save to application memory, or use sqlite db.
I have the following problem. I am using the DropBox SDK to upload a file to dropbox which works fine. When the file is being uploaded (inside an AsyncTask) a ProgressDialog is being shown with a cancel button, still fine here. What is not working fine is, when the cancel button gets pressed a NetworkOnMainThreadException is being raised. I am new to Android programming but I am suspecting it has something to do with the ProgressDialog which is in the constructor. Since it is not in the "doInBackground" part.
Tried to fix it with implementing the OnDismissListener and doing the abortion onDismiss but still no luck. I am getting the error when "mRequest.abort()" is called.
Thanks in advance for any answers!
So here is my code
public class DropBoxUpload extends AsyncTask<Void, Long, Boolean> implements OnDismissListener {
private DropboxAPI<?> mApi;
private String mPath;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private final ProgressDialog mDialog;
private String mErrorMsg;
public DropBoxUpload(Context context, DropboxAPI<?> api, String dropboxPath, File file) {
// We set the context this way so we don't accidentally leak activities
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mPath = dropboxPath;
mFile = file;
mDialog = new ProgressDialog(context);
mDialog.setMax(100);
mDialog.setMessage("Uploading " + file.getName());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setProgress(0);
mDialog.setButton("Cancel", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// This will cancel the putFile operation
mDialog.dismiss();
}
});
mDialog.setCancelable(true);
mDialog.setOnDismissListener(this);
mDialog.show();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
// By creating a request, we get a handle to the putFile operation,
// so we can cancel it later if we want to
FileInputStream fis = new FileInputStream(mFile);
String path = mPath + mFile.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
#Override
public long progressInterval() {
// Update the progress bar every half-second or so
return 500;
}
#Override
public void onProgress(long bytes, long total) {
publishProgress(bytes);
}
});
if (mRequest != null) {
mRequest.upload();
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
}
return false;
}
#Override
protected void onProgressUpdate(Long... progress) {
int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
mDialog.setProgress(percent);
}
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
}
#Override
public void onDismiss(DialogInterface arg0) {
// TODO Auto-generated method stub
mRequest.abort();
}
}
You cannot access the mRequest object from the main UI thread as this is what is responsible for the network operation. That is why you get a NetworkOnMainThreadException when you call mRequest.abort().
You should modify your code such that you use AsyncTask.cancel on dialog dismissal and check for isCancelled periodically in your doInBackground and call mRequest.abort() when the task is cancelled.
you should call the cancel method to stop your uploading process.
ast.cancel(true);
where ast is your asynctask object
I have a service that extracting html code from an URL, converting it to text only (with Jsoup) and then checks something on the string, and if some conditions are true it launches a notification and writes something to a file.
As far as I know, this kind of service shouldn't take much memory, and in Watchdog, it takes ~65 MB, and it is way too much. It takes more than any other process (even more than tw launcher and Android System).
I would like you to tell me what have I done wrong.
Heres my service class:
public class NotifyService extends Service
{
private int number=0;
private Timer timer=new Timer();
private long INTERVAL=1*1000*60*60;//1 hour
public static String Oldhtml;
public static String Newhtml;
public static String currHtml;
// hooks main activity here
/*
* not using ipc...but if we use in future
*/
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate()
{
super.onCreate();
_startService();
Log.w("myApp", "START");
}
#Override
public void onDestroy()
{
super.onDestroy();
_shutdownService();
Log.w("myApp", "STOPPED");
}
/*
* starting the service
*/
private void _startService()
{
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
try {
doServiceWork();
} catch (ClientProtocolException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},0,INTERVAL);
;
}
/*
* start the processing, the actual work, getting config params, get data from network etc
*/
private void doServiceWork() throws ClientProtocolException, IOException
{
String FILENAME="blichData";
String info=null;
String classLetter = null,classNum1=null;
int classNum = 0;
try{
FileInputStream fis=openFileInput(FILENAME);
byte[] dataArray = new byte[fis.available()];
while(fis.read(dataArray)!=-1)
{
info = new String(dataArray);
}
classLetter = info.substring(0, info.lastIndexOf(" "));
classNum1 =info.substring(info.lastIndexOf(" ")+1);
classNum=Integer.parseInt(classNum1);
fis.close();
}catch (Exception e){
}
if (classLetter!=null && classNum1!=null) {
Oldhtml=readHTMLfromFile();
if (GetHTML.isHavingChanges(classLetter,classNum))
{
myNotify();
writeHTMLtoFile(currHtml);
/*
try {
String data= "false";
FileOutputStream fos = openFileOutput("blichService", Context.MODE_PRIVATE);
fos = openFileOutput("blichService",Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
}
catch (Exception e) {}
*/
}
}
;
}
/*
* shutting down the service
*/
private void _shutdownService()
{
if (timer != null) timer.cancel();
Log.i(getClass().getSimpleName(), "Timer stopped...");
}
public void writeHTMLtoFile(String html) {
try {
String FILENAME = "blichNotifyData";
String data= html;
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos = openFileOutput(FILENAME,Context.MODE_PRIVATE);
fos.write(data.getBytes());
fos.close();
}
catch (Exception e){}
}
public String readHTMLfromFile() {
String FILENAME = "blichNotifyData";
String info="";
try{
FileInputStream fis=openFileInput(FILENAME);
if (fis.available()>0)
{
byte[] dataArray = new byte[fis.available()];
while(fis.read(dataArray)!=-1)
{
info = new String(dataArray);
}
fis.close();
}
else {
Oldhtml="null";
}
}
catch (Exception e) {}
return info;
}
public void myNotify()
{
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent= new Intent (this,SchoolBlichActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
String body = " בליך";
String title = "ישנם שינויים חדשים!";
Notification n =new Notification(R.drawable.table, body, System.currentTimeMillis());
n.flags |=Notification.FLAG_AUTO_CANCEL;
n.setLatestEventInfo(getApplicationContext(), title, body, pi);
n.defaults = Notification.DEFAULT_ALL;
number++;
n.number=number;
nm.notify(0,n);
}
}
And if it is needed, the HTML extracting class:
public class GetHTML {
public static boolean isHavingChanges(String classLetter,int classNum) throws ClientProtocolException, IOException {
int classLetterCode = 0;
int timeTableCode=1;
if (classLetter.equals("ט"))
classLetterCode=0;
else if (classLetter.equals("י"))
classLetterCode=1;
else if (classLetter.equals("יא"))
classLetterCode=2;
else if (classLetter.equals("יב"))
classLetterCode=3;
switch(classLetterCode)
{
case 0:
if (classNum>=1 && classNum<=7)
timeTableCode=1;
else if (classNum>7 && classNum<=14)
timeTableCode=2;
break;
case 1:
if (classNum>=1 && classNum<=7)
timeTableCode=3;
else if (classNum>7 && classNum<=14)
timeTableCode=4;
break;
case 2:
if (classNum>=1 && classNum<=7)
timeTableCode=5;
else if (classNum>7 && classNum<=14)
timeTableCode=6;
break;
case 3:
if (classNum>=1 && classNum<=7)
timeTableCode=7;
else if (classNum>7 && classNum<=14)
timeTableCode=8;
break;
}
String url = "http://blich.iscool.co.il/DesktopModules/IS.TimeTable/MainScreen.aspx?pid=17&mid=6264&page="+timeTableCode+"&msgof=0&static=1";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
String html = "";
InputStream in = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder str = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null)
{
str.append(line);
}
in.close();
html = str.toString();
html = Jsoup.parse(html).text();
if (NotifyService.Oldhtml.equalsIgnoreCase(html)) {
return false;
}
if (timeTableCode%2!=0){
for (int i=0;i<8;i++) {
if (!html.contains(i+" "+i)) {
NotifyService.currHtml=html;
return true;
}
}
}
if (timeTableCode%2==0) {
for (int i=8;i<15;i++) {
if (!html.contains(i+" "+i)) {
NotifyService.currHtml=html;
return true;
}
}
}
return false;
}
}
Ignore the foreign language. xD
I just want to understand what have I done wrong?
Thanks
While I cannot tell out-of-the-box what portion of your code is problematic, you may try to analyze the memory usage through a heap dump taken with DDMS using Eclipse MAT. You will need to use the hprofconv tool to convert your Android heap dump into a format that MAT understands.
To get the HPROF Heap Dump, open the Dalvik Debug Monitor (DDMS), connect it you your emulator, select the process of your application and hit the "Dump HPROF file" icon.