If I click the button it works normally but when pressing more than 1 button the image view hangs for seconds before changing
My Code:
My Code:
ArrayList<Integer> ids = null;
ids=new ArrayList<Integer>();
ids.add(R.drawable.comp2);
ids.add(R.drawable.comp3);
ids.add(R.drawable.comp4);
ids.add(R.drawable.comp5);
ids.add(R.drawable.comp6);
ids.add(R.drawable.comp7);
ids.add(R.drawable.comp8);
ids.add(R.drawable.comp9);
ids.add(R.drawable.comp10);
button a = (Button)findViewById(R.id.button);
public void onclick{
name()
}
int i =o;
public void name() {
new Thread(new Runnable() {
public void run() {
imageview.post(new Runnable() {
public void run() {
if(i<ids.size()) {
imageview.setImageResource(ids.get(i));
i++;
}else i=0;
}
});
}
}).start();
They way you are doing is of no good. You are creating one thread and inside that thread you are changing ImageView src. I would suggest you to use transition.
You can define it in xml as well as in dynamically using code.
Related
So imagine that at first we load 10 items in our RecyclerView. Adding or removing one element gives us a nice animation (the adapter has stable ids).
The problem is, I have a search bar, I can look for something and then the result should replace the current items of the RecyclerView. If some item was already there, there is a nice "moving" animation. But if all items are new, there is a quite ugly fade-in transition that it's too fast and looks like a glitch. Is it possible to override that animation? I'd like to have a fade-out-fade-in one but slower.
By the way, when the query returns with results, I do this in the adapter:
mItems.clear();
mItems.addAll(resultItems);
notifyDataSetChanged();
Also, it's worth to say that if I make a search with no results, then I see the RecyclerView empty and then if I get some results again, the transition from empty state to some results looks ok.
You can batch remove and insert items in a RecyclerView.
adapter.notifyItemRangeRemoved(0, mItems.size());
mItems.clear();
mItems.addAll(resultItems);
adapter.notifyItemRangeInserted(0, mItems.size());
EDIT: After looking at your problem some more you probably don't want to do what I suggested above. Instead you should not clear your list and instead remove some items and then notify the adapter of the change with notifyItemRemove(index)
If you do range methods like RangeRemoved/RangeAdded, you loose out in the animation side. So, do it one by one in a loop to preserve the animation effect of one by one, including a delay in the loop. Here's how I have implemented:
MainActivity.java
clearItemsView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final List<LineItem> lineItemsCopy = new ArrayList<>(lineItems);
new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<lineItemsCopy.size(); i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
salesOrderItemListAdapter.removeItem(0);
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
Snackbar snackbar = Snackbar.make(coordinatorLayout, getString(R.string.items_cleared_message), Snackbar.LENGTH_LONG)
.setAction(getString(R.string.label_undo), new View.OnClickListener() {
#Override
public void onClick(View v) {
new Thread(new Runnable() {
#Override
public void run() {
for (int i=0; i<lineItemsCopy.size(); i++) {
final int finalI = i;
runOnUiThread(new Runnable() {
#Override
public void run() {
salesOrderItemListAdapter.restoreItem(lineItemsCopy.get(finalI), 0);
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}).setActionTextColor(Color.YELLOW);
snackbar.show();
}
});
RecyclerViewAdapter.java
//Only remove & restore functions are shown
public void removeItem(int position) {
lineItems.remove(position);
notifyItemRemoved(position);
}
public void restoreItem(LineItem item, int position) {
lineItems.add(position, item);
notifyItemInserted(position);
}
I am working on an android application, that fetches image from Internet and show in the user interface. I am using RecyclerView for showing the image. I am planning to download the image using a separate thread. and update RecyclerView via the handler. I dont know wether this concept is correct or not, (I know AsyncTask, but for learning purpose I am trying to implement Handler.)
So I coded for the same as below
private void loadNewsThumbnailImage(ArrayList<DataItem> dataList) {
for (DataItem item : DataList) { //DataItem is the model class
loadThumbnailFromInternet(item);
}
}
private void loadThumbnailFromInternet(final DataItem dataItem) {
Thread imageDowloaderThread = new Thread(new Runnable() {
#Override
public void run() {
Bitmap bitmap = null;
try {
bitmap = getDataItemBitmap(dataItem.getmImageUrl());
dataItem.setmThumbnail(bitmap);
new Handler().post(new Runnable() { // Tried new Handler(Looper.myLopper()) also
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
});
imageDowloaderThread.start();
}
I have executed this code but I am getting error, and application is terminated, I don't know why this is happening . please any one help me to sort it out. and explain what is the problem for the current code.
(Please do not suggest to use AsyncTask (I have tried that and it works fine))
UPDATE
Error getting :java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Your application is getting terminated because you are calling notifyDataSetChanged() from a non UI Thread.
Replace:
new Handler().post(new Runnable() { // Tried new Handler(Looper.myLopper()) also
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
With this:
new Handler(Looper.getMainLooper()).post(new Runnable() { // Tried new Handler(Looper.myLopper()) also
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
The thread you defined does not have a Looper, and no message queue,so you can not send message in this thread. AsyncTask has its own Looper which you can find it in its source code. This is handler defined in AsyncTask:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
#SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
#Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
Aim:
I'm looking for a way to append functionality to a button's onClickListener.
Illustration
Button trigger = new Button(getActivity());
trigger.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
method1();
}
});
Button runMethod2Button = new Button(getActivity());
runMethod2Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
method1();
method2();
}
});
Button runMethod3Button = new Button(getActivity());
runMethod3Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
method1();
method3();
method4();
}
});
I know we can do this with inheritance by calling
#Override
public void method(){
super.method();
// Do appended stuff
}
Or we can do it inline
new Object(){
#Override
public void method(){
super();
// Do appended stuff
}
}
Things I've Tried
Extending the button to contain a list of Runnable Objects.
Then set the on click listener to trigger all of the runnable objects.
Is there a different/more efficient way of doing this?
Since we don't no much about the background why you want to do so, it is hard to what is the best. If you want to have the original listener unchanged / untouched, you could use a decorator / wrapper pattern.
Wikipedia Decorator Pattern
In the concrete case this means, it is quite comparable to your Runnable approach, but you do not depend on another Interface. Everthing is handled via the View.OnClickListener, which has the following advantages:
It is a generic approach with which you can even "extend" listeners to which you have no source access or which you do not want to modify.
You can create the extension behaviour at runtime and you can extend already instantiated listeners (in contrast to the use of inheritance)
The extensions do not have to know that they are extensions, they are just normal OnClickListeners. In your Runnable approach the extensions are "special" and for example they do not get the View paramter of the onClick method passed.
public class OriginalOnClickListener implements View.OnClickListener{
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"Original Click Listener",Toast.LENGTH_LONG).show();
}
}
public class ExtensionOnClickListener implements View.OnClickListener{
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"Extension Click Listener",Toast.LENGTH_LONG).show();
}
}
public class DecoratorOnClickListener implements View.OnClickListener {
private final List<View.OnClickListener> listeners = new ArrayList<>();
public void add(View.OnClickListener l) {
listeners.add(l);
}
#Override
public void onClick(View v) {
for(View.OnClickListener l : listeners){
l.onClick(v);
}
}
}
And the usage is like this:
DecoratorOnClickListener dl = new DecoratorOnClickListener();
dl.add(new OriginalOnClickListener());
dl.add(new ExtensionOnClickListener());
editText.setOnClickListener(dl);
I think the Runnable idea is okay, based on what you've said here. Seeing as I don't really know why you need dynamic click handlers, I think a possible solution would look something like this:
private class DynamicOnClickListener implements View.OnClickListener {
private final List<Runnable> mRunnables = new ArrayList<>();
public void add(Runnable r) {
mRunnables.add(r);
}
#Override
public void onClick(View v) {
for (Runnable r : mRunnables) {
r.run();
}
}
}
And you'd use it like this:
DynamicOnClickListener listener = new DynamicOnClickListener();
listener.add(new Runnable() {
#Override
public void run() {
doSomething();
}
});
listener.add(new Runnable() {
#Override
public void run() {
doSomethingElse();
}
});
mButton.setOnClickListener(listener);
what about something like
Button trigger = new Button(getActivity());
trigger.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
method1();
if (someVar) method2();
if (someVar2) method3();
}
})
I have three fragments, Play, Dropbox and Settings inside a tab host.
Inside the Dropbox fragment, I have a class variable, 'progressBar'. I allocate it in the onActivityCreated.
if(progressBar == null)
{
progressBar = (ProgressBar) getActivity().findViewById(R.id.progressbar_Horizontal);
}
I update it with this:
DropboxAPI.DropboxFileInfo info = mDBApi.getFile(directoryOfFile, null, outputStream, new ProgressListener() {
#Override
public long progressInterval() { return 2000; }
public void onProgress(long downloadedSoFar, long totalSize) {
final double dProgress = ((double)downloadedSoFar / totalSize)*100.0;
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
System.out.println(dProgress);
progressBar.setProgress((int) dProgress);
}
});
}
This works perfectly, however, when I move to another fragment and come back it stays stuck on where it was left. It's annoying because I can still see my System.out.println(dProgress) working. Nothing I seem to do allows me to reallocate the progress bar and it work. Is there any way I can do this? Anyone just point me in the right direction as to how this achieved? I had a look at a few apps as to how they do it ( I'm an iOS guy ) and they all just prompted the user with a progress screen open, but I want users to be able to do something while downloading.
p.s I've tried this without the null condition.
Replace this ..
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
System.out.println(dProgress);
progressBar.setProgress((int) dProgress);
}
});
with this..
Thread thread = new Thread() {
#Override
public void run() {
System.out.println(dProgress);
progressBar.setProgress((int) dProgress);
}
};
thread.start();
I'm looking for a way to speed up the creation of a TableLayout with over 1000 rows. Is there a way to create a TableLayout entirely on a separate thread or a way to speed it up?
Here is my method that is creating the table:
private void setTable()
{
final Activity activity = this;
final Handler handler = new Handler();
new Thread(new Runnable()
{
#Override
public void run()
{
for (int x = 0; x < rooms.size(); x++)
{
final int inx = x;
handler.post(new Runnable()
{
#Override
public void run()
{
Methods.createRow(table, rooms.get(inx), null, activity);
TableRow row = (TableRow)table.getChildAt(inx);
row.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
if (arg0.getTag() != null && arg0.getTag().getClass() == Integer.class)
select((Integer)arg0.getTag());
}
});
}
});
}
}
}).start();
}
I was hoping that using a Handler would at least allow the new Activity to appear before the table was created. The application seems to freeze up for a few seconds when creating tables with a lot of rows. setTable() is being run in my Activity's onStart() method.
Methods.createRow adds a row to the end of the TableView that is passed in.
Edit:
After deciding to try out a ListView, I got much better results with a lot less code.
private void setTable()
{
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, roomNames);
table.setAdapter(adapter);
table.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3)
{
select(arg2);
}
});
}
First things first.
Why your app freezes:
Handler works like a queue, it queues every post you made and than execute it serially in your main thread.
But the main problem is the amount of data you are trying to show at once, but it is easily solved with an Adapter, you probably can use some default Component for solve this, like ListView or GridView, you can make your custom rows to work around the columns maybe.
Just from guessing on the method name, it seems this line may be slow to run on the main/UI thread:
Methods.createRow(table, rooms.get(inx), null, activity);
I would suggest separating all the heavy database work and UI work with AsyncTask, so it might look something like this:
private OnClickListener rowClickListener = new OnClickListener()
{
#Override
public void onClick(View arg0)
{
if (arg0.getTag() != null && arg0.getTag().getClass() == Integer.class)
select((Integer)arg0.getTag());
}
};
private void setTable()
{
final Activity activity = this;
final Handler handler = new Handler();
new AsyncTask<Void, Void, List<TableRow>>() {
#Override
protected List<TableRow> doInBackground(Void... params) {
// Do all heavy work here
final List<TableRow> rows = new ArrayList<TableRow>(rooms.size());
for (int x = 0; x < rooms.size(); x++)
{
Methods.createRow(table, rooms.get(x), null, activity);
rows.add((TableRow)table.getChildAt(x));
}
return rows;
}
#Override
protected void onPreExecute() {
// maybe show progress indication
}
#Override
protected void onPostExecute(List<TableRow> result) {
// Do all UI related actions here (maybe hide progress indication)
for (final TableRow row : result) {
row.setOnClickListener(rowClickListener);
}
}
};
}
Since I can't tell what is in some methods, you'll just need to ensure you've tried to optimize as best as possible in Methods.createRow(...) and move all the UI related work to the onPostExecute(...) method.
You are stacking the post with all the actions at once. So it same as not using a thread at all as your main thread doing all the work. Try changing to postDelay, and for each room index give it 1 millisecond or more.