I'm trying to pass params into a AsyncTaskLoader. How do I do that?
Currently, I'm putting what I need to pass in in a separate static class. Anyway around this?
public class NewsAsyncTaskLoader extends AsyncTaskLoader<List<Content>> {
private static final DbHelper dbHelper = DbHelperFactory.getDbHelper();
public FeedAsyncTaskLoader(Context context) {
super(context);
}
#Override
public List<Content> loadInBackground() {
List<Content> contents = DbHelper.getStream(FeedSections.getInstance().getCurrentSection());
feed.setContents(contents);
return feed;
}
}
Pass additional parameters into your constructor:
public FeedAsyncTaskLoader(Context context, String moreInfo) {
super(context);
// Do something with moreInfo
}
Related
I'm using an app which contain viewPager and TapLayout. And a fragment which showed on ViewPager has Bluetooth connecting function. When I tab a button on a fragment, Ble Started.
But in that process, I got an
interface ClassCastException Error
A fragment implement interface which in BluetoothController. BluetoothController need context, so I passed context(getContext) which got in Fragment.
When I implement interface and pass context in MainActivity, it works well. But I do that in fragment, Android studio occurs 'interface ClassCastException Error'.
I should implement interface in fragment, because interface pass Bluetooth state like Connecting, DisConnecting, Start etc.
How can I set interface in fragment?
When MainActivity implement interface, Bluetooth interface works well. But that case, Bluetooth state is not passed in fragment. It pass state in MainActivity. I think when I got state in MainActivity, pass the state to fragment is one of the solution for this problem. But I think it is not good method.
here is BluetoothContoller code
public class BluetoothController extends BluetoothPacketController
{
public static final String TAG = BluetoothController.class.getSimpleName() +"_Debug";
private static Context context;
private static final int SCAN_PERIOD = 1000*10;
private int BLE_STATE = BLUETOOTH_STATE.IDLE;
private BleInterface mListener;
public class BLUETOOTH_STATE {
public static final int IDLE = 0;
public static final int SCANNING = 1;
public static final int CONNECTION_TRY = 2;
public static final int CONNECTION_ERR = 3;
public static final int CONNECTION_SUCC = 4;
public static final int DISCONNECTION = 5;
}
public interface BleInterface{
void bleScanTimeOut();
void bleScanStart();
void bleScanStop();
void bleConnectTry();
void bleDisConnectTry();
void bleErrDisConnectTry();
void bleDisConnected();
void bleResult(boolean ret);
void bleResult(String ret);
}
private static BluetoothController instance = null;
#Override
public void setContext(Context context) {
super.setContext(context);
this.context = context;
}
public static BluetoothController getInstance() {
if (instance == null) {
instance = new BluetoothController();
}
return instance;
}
#Override
public void init(Context context) {
super.init(context);
setContext(context);
mListener = (BluetoothController.BleInterface) context;//listener;//(BluetoothController.BleInterface) context;
}
...
}
And here is fragment code
public class RegistrationFragment extends Fragment implements BluetoothController.BleInterface{
private View view;
public static final String TAG = RegistrationFragment.class.getSimpleName() + "_Debug";
private static RegistrationFragment instance = null;
public static RegistrationFragment getInstance() {
if (instance == null) {
instance = new RegistrationFragment();
}
return instance;
}
public void setContext(Context context) {
this.context = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.register_view, container, false);
BluetoothScanUpperAPI21.getInstance().init(getContext());
BluetoothScanUnderAPI21.getInstance().init(getContext());
BluetoothController.getInstance().init(getContext());
startUi_init();
return view;
}
...
}
I want to get Bluetooth state through BleInterface in fragment.
Why are you casting context in BleInterface? Can't you pass this from fragment to BluetoothController where this referes BleInterface which is implemented in fragment?
In Fragment
BluetoothController.getInstance().init(this);
BleController's Init:
#Override
public void init(BluetoothController.BleInterface ble) {
super.init(context);
setContext(context);
mListener = ble;
}
Reason for the behaviour that you are facing:
Fragment doesn't have their own context. They always refers to activity context. So, when you pass getContext(), it refers to activity context and compiler tries to find BleInterface in activity which does not exists. That's why you are facing ClassCastException.
I'm trying to adapt Mortar&Flow in my app and faced with an issue, that I can't make PageAdapter works with Screens, instead of Fragments.
Anyone managed to get it right?
I didn't succeed but, probably someone can guide me from this point:
The initial Dagger Registration:
#Module(
injects = {
MainActivity.class,
},
library = true,
complete = false
)
public class DaggerConfig {
#SuppressWarnings("unused")
#Provides #Singleton Gson provideGson() {
return new GsonBuilder().create();
}
}
MainScreen, whose View is hosting ViewPager:
#Layout(R.layout.screen_main) #WithModule(MainScreen.Module.class)
public class MainScreen extends Path {
#dagger.Module(injects = MainView.class, addsTo = DaggerConfig.class)
public static class Module {}
#Singleton
public static class Presenter extends ViewPresenter<MainView> {
#Inject
public Presenter() {}
}
}
MainView:
...........
#Inject
MainScreen.Presenter presenter;
...........
#Override protected void onFinishInflate() {
super.onFinishInflate();
ButterKnife.inject(this);
final Path[] screens = {
new SubScreen("1"),
new SubScreen("2"),
new SubScreen("3"),
};
CustomPagerAdapter customPagerAdapter = new CustomPagerAdapter(getContext(), screens );
customPagerAdapter .setAdapter(firstRunPagerAdapter);
}
.....
Now, the main part, SubScreen (3 similar screens, that differs only by the parameters we are passing into them => they should adjust views according these parameters)
#Layout(R.layout.screen_subscreen) #WithModule(SubScreen.Module.class)
public class SubScreen extends Path {
private final String title;
public SubScreen(String titleParam) {
title = titleParam;
}
#dagger.Module(injects = SubView.class, addsTo = DaggerConfig.class)
public class Module {
#Provides
SubViewMetadata provideSubViewMetadata() {
return new SubViewMetadata(backgroundColor, title);
}
}
#Singleton
public static class Presenter extends ViewPresenter<SubView> {
private String title;
#Inject
public Presenter(String title) {
this.title= title;
}
#Override
protected void onLoad(Bundle savedInstanceState) {
super.onLoad(savedInstanceState);
if (!hasView()) {
return;
}
getView().setTitle(subViewMetadata.title);
}
}
}
and it's view
public class SubView extends FrameLayout {
#InjectView(R.id.subViewTitleTextView)
TextView subViewTitleTextView;
#Inject
SubScreen.Presenter presenter;
public SubView(Context context, AttributeSet attrs) {
super(context, attrs);
ObjectGraphService.inject(context, this);
}
public void setTitle(String title) {
subViewTitleTextView.setText(title);
}
#Override protected void onAttachedToWindow() {....}
#Override protected void onDetachedFromWindow() {....}
......
}
Custom Pager adapter:
public class CustomPagerAdapter extends PagerAdapter {
private final Context context;
private final Path[] screens;
public CustomPagerAdapter(Context context, Path[] screens) {
this.context = context;
this.screens = screens;
}
#Override
public int getCount() {
return (screens == null)? 0 : screens.length;
}
#Override
public boolean isViewFromObject(View view, Object o) {
return view.equals(o);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Path screen = screens[position];
MortarScope originalScope = MortarScope.getScope(context);
MortarScope newChildScope = originalScope.buildChild().build("tutorialpage" + position);
Context childContext = newChildScope.createContext(context);
View newChild = Layouts.createView(childContext, screen);
container.addView(newChild);
return newChild;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = ((View) object);
container.removeView(view);
MortarScope.getScope(view.getContext()).destroy();
}
}
The problem statement: it's crashing, as SubView class hasn't been added into list of Injections at the "Layouts.createView(childContext, screen);" moment in the Adapter, and I can't add it by default, because I want to have a #provider of data from SubScreen to SubScreen.Presenter. (I'm using local variable.
If I add SubView.class into list of injections and convert local Screen's variables into static, then I'll have 3 identical pages inside the ViewPager (which is logical, as every next call of the constructor - overrides old static variables).
Any help/ideas?
Thanks for your help,
Konstantin
Ok, I figured out.
First of all, adding SubView into list of globally injected classes
Then modifying SubScreen class:
#Layout(R.layout.screen_subscreen)
public class SubScreen extends Path {
private static String titleStatic; // Introducing static variable
private final String title;
public SubScreen(String titleParam) {
title = titleParam;
}
public void refreshPresenter() {
titleStatic = title;
}
#Singleton
public static class Presenter extends ViewPresenter<SubView> {
private String title;
#Inject
public Presenter() {
}
#Override
protected void onLoad(Bundle savedInstanceState) {
super.onLoad(savedInstanceState);
if (!hasView()) {
return;
}
getView().setTitle(titleStatic);
}
}
}
and then in Custom adapter do this changes:
public class CustomPagerAdapter extends PagerAdapter {
private final Context context;
private final SubScreen[] screens;
public CustomPagerAdapter(Context context, SubScreen[] screens) {
this.context = context;
this.screens = screens;
}
......
#Override
public Object instantiateItem(ViewGroup container, int position) {
SubScreen screen = screens[position];
MortarScope originalScope = MortarScope.getScope(context);
MortarScope newChildScope = originalScope.buildChild().build("tutorialpage" + position);
Context childContext = newChildScope.createContext(context);
screen.refreshPresenter(); // updating the static var with local one!
View newChild = Layouts.createView(childContext, screen);
container.addView(newChild);
return newChild;
}
....
}
I.e. the solution is to keep the local AND static variables in the Screen, if the same screen is going to be reused. And when we inflate the view it - just setting the right value to the static one (that would be used in the Presenter).
I am not sure, that it is the best possible solution, but it works. It would be nice to hear, if it can be improved.
I'm trying to use statuc variable in my app to be used to keep tracking a certain variable, my service code, I've only pasted what's necessary
public class TestService extends Service {
public static HashMap<Long, Integer> testMap;
#Override
public void onCreate() {
registerReceiver();
testMap = new HashMap<Long, Integer>();
}
private final BroadcastReceiver testReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(UPDATE)) {
long key = intent.getLongExtra("key", -1);
int value = intent.getIntExtra("value", -1);
//Make sure I insert it once for testing purposes
if (testMap.get(key) == null)
testMap.put(key, value);
//This one prints the value fine
Log.i(TAG,testMap.get(key));
}
}
};
}
And then I try to access it inside my cursor adapter but I'm always getting null,
private static class MyCursorAdapter extends CursorAdapter {
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.test_layout, parent, false);
}
#Override
public void bindView(View view, final Context context, Cursor cursor) {
Integer value = TestService.testMap.get(key);
//When I check value here, it's always null
if (value != null)
Log.i(TAG, value)
else
Log.i(TAG, "Key value is NULL")
}
}
What am I doing wrong?
Make sure you are not finishing your service, because everytime it calls onCreate() you are reinitializing your static variable. By the way, this is not a good approach, besides, static global variables are not good idea. You should communicate with your service via Intents or binding to it instead of sharing a static variable.
I have a class I use for managing bitmaps in my application.
It needs to have a context passed to it to be able to use getResources().
Problem is I believe you can't use Context inside of a Parcelable class.
Anyone have any ideas for a solution?
Below is my code:
public class ImageManager implements Parcelable {
private static final long serialVersionUID = 66;
private HashMap<Integer, Bitmap> mBitmaps;
private HashMap<Integer, Drawable> mDrawables;
//private Context mContext;
private boolean mActive = true;
public ImageManager(Context c) {
mBitmaps = new HashMap<Integer, Bitmap>();
mDrawables = new HashMap<Integer, Drawable>();
//mContext = c;
}
public ImageManager(Parcel in) {
// TODO Auto-generated constructor stub
}
public Bitmap getBitmap(int resource) {
if (mActive) {
if (!mBitmaps.containsKey(resource)) {
mBitmaps.put(resource,
BitmapFactory.decodeResource(mContext.getResources(), resource));
}
return mBitmaps.get(resource);
}
return null;
}
public Drawable getDrawable(int resource) {
if (mActive) {
if (!mDrawables.containsKey(resource)) {
mDrawables.put(resource, mContext.getResources().getDrawable(resource));
}
return mDrawables.get(resource);
}
return null;
}
public void recycleBitmaps() {
Iterator itr = mBitmaps.entrySet().iterator();
while (itr.hasNext()) {
Map.Entry e = (Map.Entry)itr.next();
((Bitmap) e.getValue()).recycle();
}
mBitmaps.clear();
}
public ImageManager setActive(boolean b) {
mActive = b;
return this;
}
public boolean isActive() {
return mActive;
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeValue(mBitmaps);
dest.writeValue(mDrawables);
//dest.writeValue(mContext);
dest.writeByte((byte) (mActive ? 0x01 : 0x00));
}
public static final Parcelable.Creator<ImageManager> CREATOR = new Parcelable.Creator<ImageManager>() {
public ImageManager createFromParcel(Parcel in) {
return new ImageManager(in);
}
public ImageManager[] newArray(int size) {
return new ImageManager[size];
}
};
}
A "manager" normally can't be Parcelable or Serializable.
Parcelable or Serializable objects are kind of objects that just hold some data and don't perform any operations on it and don't need to reference Context.
When you pass objects as a Parcelable, the object received will be recreated so this way you can't preserve the same instance.
To solve your task, make ImageManager a singleton.
public final class ImageManager {
public static synchronized ImageManager getInstance(final Context context) {
if (sInstance == null) {
sInstance = new ImageManager(context.getApplicationContext());
}
return sInstance;
}
private static ImageManager sInstance;
private final Context mContext;
private ImageManager(Context c) {
mBitmaps = new HashMap<Integer, Bitmap>();
mDrawables = new HashMap<Integer, Drawable>();
}
And whenever you need it in Activity, call
ImageManager imageManager = ImageManager.getInstance(this);
This way the same ImageManager will be accessible in all Activities.
You can create your own Application implementation and add static getter.
public class Application extends android.app.Application {
private static Context context;
#Override
public void onCreate() {
super.onCreate();
context = this;
}
public static Context getContext(){
return context;
}
}
And use it everywhere you need:
Application.getContext();
But in general I thing it's not the best idea.
I suggest turning your class into a helper class by making the methods you need static and then passing Context as a parameter as well, like so:
public Bitmap getBitmap(int resource, Context context) { ... }
Don't store that reference to Context in your helper class, if you do you will most likely be leaking it.
I use an ArrayAdapter to show items in a ListView. Every row in this ListView owns a button.
Whenever the user clicks on one of these buttons I start an AsyncTask to do some processing in the background.
This is working so far.
Now I want to show a custom ProgressDialog during this time. What puzzles me here is the first parameter of the static convinience method ProgressDialog.show(). Within an activity I usually use "Activityname.this" here. But what should I use in an adapter. I tried context from the adapter (that crashed), context.getApplicationContext and several more. Nothing worked - either crashed or is refused from the compiler.
So my question today: What should I put into this parameter?
Here's a stripped down part of my code:
public class MyAdapter extends ArrayAdapter<MyContainer> {
private class MyAsyncTask extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute () {
if (!isRunning) {
progressDialog = MyProgressDialog.show(?????,
null,
null,
true,
false);
}
}
#Override
protected Boolean doInBackground(final String... strings) {
boolean rc = false;
if (!isRunning) {
isRunning = true;
//
rc = true;
}
return rc;
}
#Override
protected void onPostExecute(final Boolean result) {
if (progressDialog != null) {
progressDialog.cancel();
}
progressDialog = null;
//
}
}
private class MyOnClickListener implements OnClickListener {
private MyContainer container;
public MyOnClickListener(final MyContainer container) {
this.container = container;
}
public void onClick(final View view) {
if (container != null) {
new MyAsyncTask().execute(container.getUrl());
}
}
private String appName = "";
private ArrayList<MyContainer> containers;
private Context context;
private boolean isRunning;
private int layout;
private MyProgressDialog progressDialog;
private Resources resources;
public MyAdapter(final Context context, final int layout, final ArrayList<MyContainer> containers, final long link_id) {
super(context, layout, containers);
this.context = context;
this.layout = layout;
this.containers = containers;
resources = context.getResources();
appName = resources.getString(R.string.txt_appname);
}
#Override
public View getView(final int position, final View contentView, final ViewGroup viewGroup) {
//
}
}
Thanks in advance.
EDIT: Using the instance variable context from the adapter worked after cleaning the project. Arg! Thanks for your answers.
Hi :D well if you see your constructor of adapter
public MyAdapter(final Context context, final int layout, final ArrayList<MyContainer> containers, final long link_id) {
super(context, layout, containers);
this.context = context;
you pass context so in side of adapter you use context :D to build progress dialog