Ayrat Badykov
Ayrat Badykov

Reputation: 33

Asynctask inside Adapterview class

I'm trying to change fonts of listview items. Without AsyncTasc it takes too much time. Using AsyncTask activity with that listview emerges fast and then after instance application crashes. I know that I can't change UI from AsyncTasc directly.What could I use? Thanks in advance

import ru.ayratbadykov.feedhandler.FEED;
import ru.ayratbadykov.feedhandler.RssMessage;
import android.content.Context;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class CustomAdapter extends BaseAdapter {
    private FEED _data;
    Context _c;

    CustomAdapter(FEED data, Context c) {
        _data = data;
        _c = c;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        Log.w("here","here");
        View v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater) _c
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.customadapter, null);
        }

        TextView fromView = (TextView) v.findViewById(R.id.textView1);
        TextView subView = (TextView) v.findViewById(R.id.textView2);
        TextView View = (TextView) v.findViewById(R.id.textView3);

        RssMessage msg = _data.getMessages().get(position);
        new Font().execute(fromView,subView,View);





        fromView.setText(msg.getTitle());
        subView.setText(msg.getPUBDATE());
        View.setText(_data.getTitle());

        return v;
    }
    public class Font extends AsyncTask<TextView, Void, Boolean> {

        @Override
        protected Boolean doInBackground(TextView... params) {
            // TODO Auto-generated method stub
            String fontPath = "fonts/Qlassik_TB.ttf";
            Typeface tf = Typeface.createFromAsset(_c.getAssets(), fontPath);
            params[0].setTypeface(tf);
            fontPath="fonts/damase.ttf";

            tf = Typeface.createFromAsset(_c.getAssets(), fontPath);
            params[1].setTypeface(tf);

            tf = Typeface.createFromAsset(_c.getAssets(), fontPath);
            params[3].setTypeface(tf);
            return true;

        }

    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return _data.getMessages().size();

    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return _data.getMessages().get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }
}

log

05-31 22:32:27.602: E/AndroidRuntime(2803): FATAL EXCEPTION: AsyncTask #1
    05-31 22:32:27.602: E/AndroidRuntime(2803): java.lang.RuntimeException: An error occured while executing doInBackground()
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.lang.Thread.run(Thread.java:1019)
    05-31 22:32:27.602: E/AndroidRuntime(2803): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at android.os.Handler.<init>(Handler.java:121)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at ru.ayratbadykov.rssunion.CustomAdapter$Font$1.<init>(CustomAdapter.java:63)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at ru.ayratbadykov.rssunion.CustomAdapter$Font.doInBackground(CustomAdapter.java:63)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at ru.ayratbadykov.rssunion.CustomAdapter$Font.doInBackground(CustomAdapter.java:1)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
    05-31 22:32:27.602: E/AndroidRuntime(2803):     ... 4 more

Upvotes: 0

Views: 1477

Answers (4)

Rodion Altshuler
Rodion Altshuler

Reputation: 1783

Conisder solution not to create font from asset for every field. Make static method returning Typeface, for example. I'm setting fonts for list elements with no performance problems in UI thread.

for example:

public class CustomAdapter extends BaseAdapter {

static Typeface mFont = YourClass.getDefaultTypeFace();

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   ...
   TextView tv;
   ... 
   tv.setTypeface(mFont);
   ...
  }
}

Also, there are some issues with memory allocation for font assets, don't create multiply instances of Typeface. Check this, works perfect for me: To use or not to use Custom Fonts on Android

Upvotes: 0

Raghunandan
Raghunandan

Reputation: 133560

You cannot update ui on the background thread. doInBackground is invoked on the background thread. You should update ui on the ui thread.

You are trying to update textview in doInBackground. Use runOnUiThread if you need to update ui inside doInBackground().

I am also not sure why you require a asynctask for what you are doing.

      runOnUiThread(new Runnable(){

          @Override
          public void run(){
            //update ui here
          }
       });

onPreExecute(),onPostExecute(Result), are invoked on the ui thread. So you can update ui here.

onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). can be used to animate a progress bar or show logs in a text field.

The result of doInbackground() computation is a parameter to onPostExecute(Result) so return the result in doinBackground() and show your toast in onPostExecute(Result)

For clarity check the link below under the topic The 4 steps.

http://developer.android.com/reference/android/os/AsyncTask.html

You can also use a handler for this purpose.

http://developer.android.com/reference/android/os/Handler.html

Upvotes: 0

Jarvis
Jarvis

Reputation: 1547

An AsyncTask allows you both to start a long process and access UI via the UIThread methods:

  • onPreExecute(): to update the UI before the start of your treatment (the thread in doInBackground)
  • onProgressUpdate(): to refresh UI during treatment
  • onPostExecute(): to update UI at the end process.

You have everything you need to do if you understand the operation of an Asynctask

Upvotes: 0

codeMagic
codeMagic

Reputation: 44571

You can update UI in AsyncTask just not from doInBackground(). But any other methods are fine. And since it is an inner class of your Adapter class which holds a reference to the Context then it is fine to do. Just move the code that uses Context or needs to update the UI to any other method.

For example, you could return an ArrayList of the params to onPostExecute() and update there or you could use publishProgress() and update them in onProgressUpdate()

onPostExecute

onProogressUpdate

So also has a lot of good examples of using each

Upvotes: 1

Related Questions