Teovald
Teovald

Reputation: 4389

adapter-like pattern for not AdapterView class

I need to transmit data from my activity layer to a view (or at least its fragment) that is not a child of AdapterView.
For a ListView, I could do this very easily with its adapter, but I am stuck on how to reproduce this behavior for a non AdapterView widget (for clarity, let's say a TextView).
I don't want to keep a reference to my fragment (or worse, the view) at Activity level.
Any ideas ?

Upvotes: 0

Views: 118

Answers (1)

Teovald
Teovald

Reputation: 4389

One way to do this is to use java.util.Observable/Observer :

import java.util.Observable;
import java.util.Observer;


public class MyTextView extends View implements Observer{



    @Override
    public void update(Observable observable, Object data) {
        this.setText((String)data);
    }

}

Then, you need an Observable class :

import java.util.Observable;

public class MyObservable extends Observable {


    public void setText(String text){

            notifyObservers(text);
    }

}

Activity :

public class MainActivity extends Activity {
TextView tv;

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    MyObservable mtv = new MyTextView(getApplicationContext());
    MyTextViewModel mm = new MyTextViewModel(10);
    mm.addObserver(mtv);
    mm.setText("test");
    // demonstrated in an activity to shorten the sample, but ideally you would
    // keep the observer at activity level and manage the view in the fragment
    }
}

------------------------------------------------

Another way to do this is through android.database.DataSetObservable to implement a more traditional Adapter like object :

public class CustomAdapter extends DataSetObservable {
   String mText;

   public String getText() {
      return mText;
   }

   public void setText(String text) {
      mText = text;
   }
}

You manipulate it like any other adapter at Activity level :
public class MyActivity extends Activity { private CustomAdapter mCustomAdapter;

@Override protected void onCreate() { ... mCustomAdapter = new CustomAdapter(); }

private void initializeFragment (Fragment fragment) {
// this or whatever method you use to setup your fragments
((MyFragment) fragment).setCustomAdapter(mCustomAdapter);
}

private void onDataLoaded (Stg data) {
// callback method invoked when the network thread has finished loading data
mCustomAdapter.setText(data.text);
mCustomAdapter.notifyChanged();
}

Finally, the only thing missing is the link between your fragment and the view :

public class MyFragment extends Fragment {
private CustomAdapter mCustomAdapter;  

public setCustomAdapter(CustomAdapter adapter) {
    // this method allows to setup the adapter at startup
    mCustomAdapter = adapter;
}

protected DataSetObserver mMyViewObserver = new MyObserver();

private class MyObserver extends DataSetObserver {

    @Override
    public void onChanged() {
     mUpdateHandler.sendEmptyMessage(0);
     }
}

private Handler mUpdateHandler = new Handler() {

    @Override
    public void handleMessage(Message msg) {
        updateMyView();
        }
    };

    private void updateMyView() {
       if (mView == null) {
           return;
       }
       mView.setMainTextViewText(mCustomAdapter.getText());
    }

}

And here you have it. Each time you call notifyChanged(), your observer gets called. In return, he invokes the handler that update the view. Here you have it, leak free, thread safe custom adapter for any kind of view.

Upvotes: 3

Related Questions