I have an edit text i need to hook to textchanged event to to do a task.I had defined the overrdiimg for edittext first but after adding the text extraction code in the text chnaged event the IDE Flagged an error and auto corrected it by adding a final modifier in the line
like this
final EditText et1=(EditText)findViewById(R.id.editText1);
After chnaging the text the app crahses so i tried to retrive the edittext 2 times first for hooking to the event then for fetching the text,then also the app crashes.
The IDE had prompted me to add the final modifier in similar cases before but it had crashed the app so i had added the fetchbyID at the point where the object was needed
EditText et1=(EditText)findViewById(R.id.editText1);
et1.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
new Thread(new Runnable() {
public void run() {
ImageView img=(ImageView)findViewById(R.id.imageView1);
EditText et=(EditText)findViewById(R.id.editText1);
img.setImageBitmap(thumbnail);
Bitmap b = workwithtext(thumbnail,et.getText().toString(),10);
img.setImageBitmap(b);
}
}).start();
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
Please help me solve this issue
It crashes because you are trying to modify a UI component from a non UI thread.
new Thread(new Runnable() {
public void run() {
ImageView img=(ImageView)findViewById(R.id.imageView1);
//...
img.setImageBitmap(thumbnail);
//...
}
}).start();
Have the EditText et1 as a field in your class rather than a local variable.
You are updating ui from a background therad which is not possible. Also move your view intialization to onCreate.
img.setImageBitmap(b); // updating ui from thread not possible
Use runOnUiThread to update ui
runOnUiThread(new Runnable() {
public void run() {
// update ui here
}
});
Note you are starting a new thread everytime your onTextChanged is called which is not good. Also you initialize imageview and editext everytime in the threads run method which is not required.
Related
In a Fragment I have this Thread that have to refresh the text of a
TextView. The problem is that after setText() (the text is set in fact if I log TextView.getText() it returns the text changed) the screen the text is always the same. It change only if a add a view to the Fragment's view.
This is the code,
Thread time = new Thread() {
public void run() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
while(true) {
TextView.setText("some text");
// i tried also to use TextView.invalidate()
}
});
}
};
}
Remove while(true), you are blocking the UI thread with that
I'm working on an editText and a recyclerView.
My recyclerView is updated when I write letters in my EditText.
I put a Timer inside my textWatcher in order to avoid sending requests each time user write a letter.
searchDestinationEt.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
//There is nothing to do here
}
#Override
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
if (timer != null) {
timer.cancel();
}
}
#Override
public void afterTextChanged(final Editable s) {
timer = new Timer();
//we schedule this in order to avoid sending useless request.
//We wait the user is finishing writing before sending requests
timer.schedule(new TimerTask() {
#Override
public void run() {
((Activity) context).runOnUiThread(new Runnable() {
#Override
public void run() {
actionsListener.onDestinationSearch(s.toString());
}
});
}
}, DELAY_SEND_REQUEST);
}
});
It works well but leakcanary says that I have a leak in this part of code.
Any idea ?
Sorry for being late with the response, but did you try separating textwatcher like this ?:
TextWatcher for more than one EditText
Why do you use Timer and TimerTask for delayed, not recurring action? The easiest and the common way is to use just a regular Handler with postDelayed():
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//do somthing here
}
}, DELAY_SEND_REQUEST);
The leak occurs because you're starting a thread which has a reference to your context (fragment or activity). And until your thread is done - it won't be garbage collected.
That means, for example, if a user types something and you're waiting for a time to start requesting and meanwhile the user turns the phone and orientation change occurs - your activity/fragment will be recreated - but the old one (which started a thread and should be used when thread is done) is not gone and still present in memory.
Why are doing a request on the UI Thread? It blocks the UI, you know that right? I assume an AsyncTask may fit better.
What should you do?
Replace Timer with Handler and do the requests in a worker thread. Regarding the leak you have 2 options:
a) do nothing since the time for which your activity/fragment will be preserved is very small and it will be GCed after the request is done. (not recommended)
b) Utilize the AsyncTask and in the constructor of the AsyncTask pass the context (your listener) and store it as a weak reference object, like this:
private static class SomeWorkTask extends AsyncTask<Void,Void,Void>{
private WeakReference<ActionsListenerWithContext> weakListener;
public SomeWorkTask(ActionsListenerWithContext listener){
this.weakListener = new WeakReference<>(listener);
}
#Override
protected Void doInBackground(Void... voids) {
//do some work here
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
if(weakListener.get() != null){
weakListener.get().callYourCallbacks();
}
}
}
and then you call it
new SomeWorkTask(listener).execute();
Utilizing WeakReference wrapper is a common and recommended practice.
I have an auto complete feature which means every time the user types a letter, there is a network call to the server, the user can type very quickly and a lot
I usually use thirdparty libraries for network calls but this time they wouldn't work, I need to use AsyncTask by the looks of it.
I read that you can only execute an AsyncTask once. My question is, do I need to create an object of my AsyncTask everytime the user types a letter? is this the best approach?
I am aware of implementing Filterable in my adapter but I need to know about this without Filterable.
Instead of making network call when user type you can make a network call when user stops typing.
I was implement it for same case as yours.I have a AutocompleteextView and when user type i have to show him list of suggestions, but I call webservice when user stops typing.Below is my example -
private final static int DELAY_BEFOR_SEARCH = 2000;
Here is Autocomplete TextView Listener -
myAutocompleteTV.addTextChangedListener(new SearchListener ());
and here is Listener Class -
public class SearchListener implements TextWatcher{
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
try{
mMessageHandler.removeCallbacks(mSearchRunnable);
if(s.length()>0){
if(Utility.isNetworkAvailable(mContext)){
mMessageHandler.postDelayed(mSearchRunnable, DELAY_BEFOR_SEARCH);
}
else{
Toast.makeText(mContext, getResources().getString(R.string.no_network_message),Toast.LENGTH_SHORT).show();
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
and here is Runnable -
Runnable mSearchRunnable = new Runnable() {
public void run() {
//TODO call your webservice here
}
}
for example if user type want to search 'Android' and he types 'Andr' ans stops typing for 2000 ms then my network call execute.
I'm very new to Android. I've used Java before but not for around a year and a half. I'm having problems getting the screen to update, or rather the TextView. I have looked around the net for hours for solutions and I sort of know why its not working, but I don't know how to fix it.
public class PreliminaryActivity extends Activity {
//private static final int MENU_QUIT = Menu.FIRST;
int i = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getWindow().setBackgroundDrawableResource(R.drawable.background);
mainComputations();
}
public void mainComputations(){
runOnUiThread(new Runnable(){
//#Override
public void run(){
TextView tv = (TextView) findViewById(R.id.time_display);
tv.setText(new Integer(i).toString());
i++;
}
});
}
I've cut my program down so it should just increment an int value on the screen for testing and it still will not work. Instead it just displays '0'. If I add a for loop before the runOnUiThread() method, it will increment the i value but I have a feeling it is simply increasing the value then displaying it rather than it updating in real time. Any help would be greatly appreciated.
Go for TextSwitcher
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/TextSwitcher1.html
If you want your textview to update with some delay.
use something like this.
final int length = 10;
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for(int i=0 ; i<length; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
tv.setText(new Integer(i).toString());
}
}) ;
i++;
Thread.sleep(500);
}
}
});
t.start();
In android, You can not update the UI from another thread. This is the restriction (which I consider a feature to remove unncecessary bugs) in android development. You can use AsyncTask for this...
In use, you can perform long task inside donInBackground() and than UI can be updated using onProgressUpdate()... see the AsyncTask example here
EDIT
see this similar question for more information...
Your problem is because you call the mainComputations() only once. You should take a look at AsyncTask and the Android Developer resource Updating the UI from a Timer
You can not Update Main UI Thread from another thread for that you need to use Handler. Refer this link for more details
http://www.vogella.com/articles/AndroidPerformance/article.html
What I see is that you call mainComputations only one time, so it is 0.
I'm trying to implement an auto-suggest like functionality for a part of my application. As a part of this, as a user types into a text field, I ping a web service for the results, parse the xml and update the listview with a list of returned results.
Here's the basic flow for my program. My question is if I'm stopping the thread the right way. Does calling thread.interrupt() suffice?
init() {
// <snip>
searchTxt.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable arg0) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
FetchResults();
}});
}
private void FetchResults()
{
if(mCurrentNetworkThread != null)
{
mCurrentNetworkThread.interrupt();
mCurrentNetworkThread = null;
}
mCurrentNetworkThread = new Thread(
new Runnable() {
public void run() {
List<NameValuePair> paramTable = new ArrayList<NameValuePair>(1);
paramTable.add(new BasicNameValuePair("searchText", searchTxt.getText().toString()));
String methodName = "GetSearchResults";
NetworkAccessClass nac = new NetworkAccessClass(paramTable, IP_ADDR, methodName, 0, this);
nac.startRequest();
}
});
mCurrentNetworkThread.start();
}
#Override
public void requestSucceeded(String responseMessage, int callID) {
parseResponseFromNetwork(responseMessage);
}
#Override
public void requestFailed(String responseCode, int callID) {
}
If that code is executed from an Activity you will most likely run into concurrency problems modifying something in the GUI thread from another thread without use of a Handler. The easy way around this i recommend using an AsyncTask. It solves any of the problems you will have in Android. These tasks can be canceled via the cancel() function and will be safe as far as any Threading exceptions in Android are concerned.
[Edit]
Make sure you check out Jon's comment below about using Loaders, a 3.0 function I wasn't aware of.
Since android 3.0, AsyncTasks will largely be replaced by Loaders
They can even be used down to Android 1.6 with the new compatibility library.
These links should help you along:
android-3-0-what-are-the-advantages-of-using-loadermanager-instances-exactly
Android Loader - Dev Guide
Try this Where to stop/destroy threads in Android Service class?