I am creating an app that involves reading data from text files that are in the Assets folder. For each file, it stores the data in a separate ArrayList. The files are read in one after another in the onCreate() method of the activity. All of the text files combined total 1.8 MB and on the emulator it currently takes 12 seconds for the activity to load. The app does not crash on the emulator (it just takes approx 12 seconds).
I have read about asynchronous threads, but I have never had a need for them in the past. I was planning on having some sort of message or progress bar to notify the user that the activity is in fact loading and has not crashed.
So my question is: even though the app does not crash when loading the activity, should I still put the reading of the files on an asynchronous or different thread? If so, how would I go about doing it properly? (I have never done it before.)
Here is sample code with the reading of the text files:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_name);
populateArrayLists();
}
public void populateArrayLists() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text1.txt")));
String text;
while ((word = br.readLine()) != null) {
ArrayList1.add(text);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close(); // stop reading
} catch (IOException ex) {
ex.printStackTrace();
}
}
br = null;
try {
br = new BufferedReader(new InputStreamReader(getAssets().open(
"text2.txt")));
// the same process is duplicated for 1-15
// it may not be the best or most efficient way but it works
Any help would be appreciated.
Yes, you'll need a background thread for this. The Loader api may be your easiest bet.
This will allow you at least display a notice and offer some content while the files load. Maybe even load them and incrementally displaying the data, if that's what you're doing.
Edit: Loaders are a 3.0 feature available in the compatibility library. If you're not willing to add the dependency, you can always fall back to AsyncTask, in which case you could take a look at this.
Related
I've got a thread in a for loop to download some files from a http server reading the file names in an array list.
I need to launch several times the thread to get all the files, it seems that some threads don't achieve but with no rules at all.
I would like to launch the threads in order to see if each task works fine and optionally do something if not.
here's my code
for(String object:stringArrayList_dwlfromex){
try {
//String result = stringArrayList_dwlfromex.get(k);
String result = String.valueOf(object);
String[]row=result.split(";");
imei = row[4].toString();
dir = row[1].toString();
filename = row[2].toString();
compteur++;
//Toast.makeText(getApplicationContext(),dir+"&"+filename,Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),compteur+" "+result,Toast.LENGTH_SHORT).show();
new Thread(new Runnable() {
public void run() {
DownloadFiles(imei,dir,filename);
}
}).start();
}catch (Exception e) {
e.printStackTrace();
}
}
any idea?
I never see any workaround like you did.
You will have to make a service with AsyncTask. You will not use for loop.
Solution is to download another file when one is downloaded. You have to set a interface callback when a file is downloaded. and execute next download after this. Also destroy service when executed files size is equal to your list.
I'm developing an Android app that has to update it's UI depending on receiving and processing some server responses, I'm using runOnUiThread for that. I have like five activities in that app, all is working very well but one requires me to relaunch the Activity(like going to another one and then returning to it) or interacting with it in order to that update takes place, and that is the way i'm using with all the Activities including the infected one:
runOnUiThread(new Runnable() {
public void run() {
try {
response_received(response);
} catch (Exception e) {
e.printStackTrace(); // never catch any Exceptions
}
}
});
private static void response_received(JSONObject response) throws Exception{
try {
int volume_setted = response.getInt(volume);
Normal_Activity.volume_value.setText(String.valueOf(volume_setted)); // the Volume TextView updated efficiently
Infected_Activity.volume_value.setText(String.valueOf(volume_setted)); // has the problem mentioned above
} catch (JSONException ex) {
}
}
I'm pretty sure the problem is not in the TextView as all the Activity UI has this problem but i just posted an example.
Do not directly set values in a Activity from another Activity. If you want to pass data to Another activity always use Intents. check the below link
pass data from intent to an other intent
If you want to start another activity and get result back check the below link
http://developer.android.com/training/basics/intents/result.html
This question already has answers here:
How can I avoid concurrency problems when using SQLite on Android?
(10 answers)
Closed 9 years ago.
I'm confused a little bit when tried to establish a multithreading work with my SQLite db, so I have a service which periodically load a data from server and insert it in different db tables, also any user in any time can store his own data in db when pressed "save button" in app windows, so based on the rules that only one thread at time can write a data in db I'd'd like to make a thread-cooperation. At first I have created a singleton which have only one db instance, and all goes pretty good with my read-db methods, cause all threads can read data in the same time, but what about writing? I use a thread inside write-function, and don't give a start another until previous thread has finished it work.(also I do it for calls from ui thread when user press save button)
Question: All I want to do is consider two situations - first is when threads call's same function to write data then I used synchronized, second - when threads call different write functions I should use a lock, right? So now I came to decision, but is it correct and right to do like that?
Code (Updated):
// Sync method for processing 1st situation
public synchronized void addPoints(final ArrayList<Point> points, final OnDBOperationListener listener) {
if (listener != null) {
// Lock for others write-threads in 2nd situaton
synchronized (mWriteLock) {
while (mWriteWait) {
try {
mWriteLock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mWriteWait = true;
try {
SQLiteDatabase db = getDatabase();
// write a data
listener.onSuccess();
} catch (Exception e) {
e.printStackTrace();
listener.onError();
} finally {
closeDatabase();
synchronized (mWriteLock) {
mWriteWait = false;
mWriteLock.notifyAll();
}
}
}
}
}
After a long search i finally found a gret answer for my broblem, so anyone who want to creat e multithreading acess to db should read this first What are the best practices for SQLite on Android?
I think this is not an easy question.
I'll be brief and give a little example of what is happening.
Let's say we have a source of data in file Byron.txt:
SHE walks in beauty, like the night
Of cloudless climes and starry skies;
And all that 's best of dark and bright
Meet in her aspect and her eyes:
Thus mellow'd to that tender light
Which heaven to gaudy day denies.
And this code execute inside an AsyncTask:
final ArrayList<Record> poem = new ArrayList<Record>();
final Object objectLock = new Object();
private Record rec = new Record();
#Override
protected Void doInBackground(Void... args) {
String line = null;
int i;
int last;
try {
process = Runtime.getRuntime().exec("cat Byron.txt");
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()), 8192);
synchronized (objectLock) {
poem.clear();
last = i = poem.size() - 1;
}
while(line = bufferedReader.readLine()) != null) {
rec.setString(line);
synchronized (objectLock) {
last++;
poem.add(last, rec);
}
while(!bPause && i < last) {
i++;
publishProgress(poem.get(i));
}
}
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected synchronized void onProgressUpdate(Record... m) {
if(m.length > 0) {
mContext.mTable.appendRow(m[0]);
}
}
where there is a TableLayout in the UI and each time we get a new line we add a new TableRow to it.
And this is the output we see in the UI:
SHE walks in beauty, like the night
Of cloudless climes and starry skies;
Of cloudless climes and starry skies;
Of cloudless climes and starry skies;
Thus mellow'd to that tender light
Thus mellow'd to that tender light
And we go into the debugger and we see why it happens.
Sometimes the synchronized (objectLock) is skipped and the loop continues.
There is no publishing because i already catched last.
Later the block is executed as many times as it was skipped,
, but the original line is lost and the current line is added instead to poem several times
Then, all the new lines are published until i catches last again.
So you see that I followed the code and I can explain what's happening, the question here is: Why the block is skipped?, Why?
I expected the synchronized block to stall until it can be executed.
At least this how I understood the function of synchronized (objectLock)
even without using wait() and notify()
I don't pretend to open a discussion here (although if you want we can open one in the chat area)
If you see some fault in the code, then, answer the question to let me know.
NOTES:
synchronized is needed because somewhere else in the app, the user may want to email the lines he got so far.
The user may pause the publishing (bpause); that's the while loop and i follows last only when bPause is false.
I decided to publish the answer. Even though I feel very embarrassed by its simplicity.
I discovered it only after I had already dug deep into AsyncTask class and message handling and whatnot.
I publish it in hope it will help people to check the basic things before jumping to
conclusions, and that someone out there will save himself half a day debugging because of
this post.
The Record rec was the same one each time. The poem ArrayList had the same element id for each entry. And the content changed on all of them at once, since they were all the same.
When the progress was published immediately it printed the right string, the last one. But if some delay cause the progress to publish later, then retrieving the poem.get(i) records retrieved a different entry but with the same pointer, thus, the same content.
The solution was to create a new Record each loop.
Do the synchronization for last object.
synchronized (last) {
last++;
poem.add(last, line);
}
Is there any way that I can increase the speed of setting the image? What I am trying to say is suppose I have some hundreds of images and each of those images can be changed automatically or by pressing forward/rewind buttons. (Think of the media player situation where you can forward or rewind as many files, same I am doing with images and some audio behind).
Now, if I continuously keep pressing RW/FW buttons, the layout appears to be black for some time or asks for force close or wait of the application.
Any one know how to increase this speed of reading the bitmap and setting it to the imageview?
Here is a part of my code,
private void playAudio() {
msg = new Message();
msg.obj = (filepath);
imageHandler.sendMessage(msg);
}
private Handler imageHandler = new Handler() {
public void handleMessage(Message msg) {
try {
path = (String) msg.obj;
imagePath = RaconTours.PATH + path;
imagenamearray = imagePath.split("/");
currentImagename = imagenamearray[8];
i++;
if (!imagePath.equalsIgnoreCase(staticpath)) {
isSeekBarChangedManually = false;
staticpath = imagePath;
Bitmap snoop = readBitmap(Uri.fromFile(new File(filepath)));
image.setImageBitmap(snoop);
image.setMaxZoom(4f);
} catch (Exception e) {
e.printStackTrace();
}
}
};
Hope you get some idea with this code, this is just a small piece of the big cake.
I am not getting the method to solve this. I tried disabling the button also until some action is being performed but that is also of no use.
Any help, cheers
I think the only way to make this process "faster" is to load and cache the bitmaps in a buffer before you actually need them. When you need a bitmap, you check this forward-cache to see if it's already loaded. If it is, then it means it's already in memory -> you just need to set it for the proper ImageView (or whatever you use). If not, then you load it from the disk.
Of course, you need to know that which bitmaps you'll need most likely in the near future for this to work.
You can't really make disk I/O work any faster you see.