Initializing a Loader in an Activity - android

I am currently trying to learn how to use Loaders and am having trouble starting a Loader in my activity.
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
public class ASwitchActivity extends Activity implements
LoaderManager.LoaderCallbacks<SampleLoader.SampleLoaderResult> {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getLoaderManager().initLoader(0, null, this);
}
public Loader<SampleLoader.SampleLoaderResult> onCreateLoader(int id, Bundle args) {
return new SampleLoader(getBaseContext(), account, "dog");
}
public void onLoadFinished(Loader<SampleLoader.SampleLoaderResult> loader, SampleLoader.SampleLoaderResult out)
{
TextView t=(TextView)findViewById(R.id.testTV);
t.setText("yay");
}
public void onLoaderReset(Loader<SampleLoader.SampleLoaderResult> loader){
}
}
However Eclipse gives an error stating:
The method initLoader(int, Bundle, LoaderManager.LoaderCallbacks)
in the type LoaderManager is not applicable for the arguments (int,
null, ActivitySwitchActivity)
Can anyone help with where I am going wrong?

As I can see you use supportV4 library.
So to implement Loader you should do some things:
extend your activity from FragmentActivity class
Use getSupportLoaderManager method instead of getLoaderManager
here is sample code:
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.widget.Toast;
public class MyActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Object> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getSupportLoaderManager().initLoader(0, null, this);
}
#Override
public Loader<Object> onCreateLoader(int i, Bundle bundle){
return null; // TODO
}
#Override
public void onLoadFinished(Loader loader, Object o) {
Toast.makeText(this, "onLoadFinished", Toast.LENGTH_SHORT).show();
}
#Override
public void onLoaderReset(Loader loader) {
Toast.makeText(this, "onLoaderReset", Toast.LENGTH_SHORT).show();
}
}

When using loaders with fragments use:
getLoaderManager().initLoader(0,null,this);
And when using loaders with Activity use:
getSupportLoaderManager().initLoader(0,null,this);

The third parameter for getLoaderManager().initLoader(0, null, this); should be a instance that implement interface LoaderManager.LoaderCallbacks
So you should implement the interface first.

For AppCompatActivity use getSupportLoaderManager().initLoader(0,null,this); for initializing the loader.

Related

Fragment Interface in fragment not working

I'm facing some problems in Android development. Environment is set to run in min API 23.
This is what I try to achieve :
I have a MainActivity with a BottomNavigationView. When an item in the BottomNavigationView is clicked it launches a Fragment. This works very well,I can send data to a fragment and have an interface to dialog with my activity.
The problem is :
On my Last fragment (ProgramFragment), I would like to make a Form Wizard. So, I would like to launch other fragments from the ProgramFragment. I used the same method I used in the MainActivity and I can launch the first fragment (RecStartFragment) where there is a button in the Layout. I want that when the button is clicked, the next fragment (RecDataPatientFragment) is shown. I get an error when I click on the button, saying that :
java.lang.NullPointerException: Attempt to invoke interface method
'void x.RecStartFragment$OnRecStartFragmentListener.startRecProg()'
on a null object reference at
x.RecStartFragment$1.onClick(RecStartFragment.java:30)
Is there a way to achieve that ? Why is that working from an activity but not from a fragment ?
Here is the code of the fragment RecStartFragment
package x;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class RecStartFragment extends Fragment {
private static final String TAG = RecStartFragment.class.getName();
private View v;
OnRecStartFragmentListener onRecStartFragmentListener;
private Button btnStartRec;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
if(v != null) {
return v;
}
v = inflater.inflate(R.layout.fragment_rec_start, null);
btnStartRec = v.findViewById(R.id.btn_start_rec);
btnStartRec.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onRecStartFragmentListener.startRecProg();
}
});
return v;
}
public interface OnRecStartFragmentListener
{
public void startRecProg();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onRecStartFragmentListener = (OnRecStartFragmentListener) context;
} catch (Exception e)
{
}
}
Thank you in advance !
You have a Null Pointer Exception (NPE) indicating that the field OnRecStartFragmentListener onRecStartFragmentListener has not been initialised.
From your code, you are trying to initialise the field in onAttach() and catching exceptions, but not doing anything with them:
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onRecStartFragmentListener = (OnRecStartFragmentListener) context;
} catch (Exception e)
{
}
}
Try printing the stacktrace of any exceptions:
e.printStackTrace()
The context passed in onAttach is your MainActivity ? If so, is it implementing OnRecStartFragmentListener ?
You should implement the interface in your activity:
Activity implementation:
public class MainActivity extends AppCompatActivity implements RecStartFragment.OnRecStartFragmentListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment();
}
#Override
public void startRecProg() {
//Do whatever you need do here.
Log.e("Calback:","Interface is working");
}
}

Can anyone explain me the meaning of this part of the code "((MainActivity)getActivity()).someMethod()"?

I created a ListDialog extending a DialogFragment class and I have a problem with understanding of this code in the DijalogX class
((MainActivity)getActivity()).setTextField(selectedItem);
I understand that with this code above I put selected String variable to the setTextField method as an argument and after that this variable is showed in TextView on MainActivity class.
My questions:
Why I need a cast from getActivity() to the MainActivity and how I get access from DijalogX(fragment) to the method setTextField in MainActivity? Please explain a little about this process.
I also tried instead of ((MainActivity)getActivity()).setTextField(selectedItem)
use an Interface and everything works nice and I got the same resoult but I am wondering what is better solution here Interface or ((MainActivity)getActivity()).setTextField(selectedItem)?
MainActivity
package com.example.dezox.dijaloglist;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity{
private Button btnStartDialog;
private TextView tvSelectedOption;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidgets();
setupListener();
}
private void initWidgets() {
btnStartDialog = findViewById(R.id.btnDialog);
tvSelectedOption = findViewById(R.id.tvselectedOption);
}
private void setupListener() {
btnStartDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DijalogX dijalogX = new DijalogX();
dijalogX.show(getSupportFragmentManager(), "dx");
tvSelectedOption.setText("");
}
});
}
public void setTextField(String odabrano){
tvSelectedOption.setText(odabrano);
}
public String getTextField(){
return tvSelectedOption.getText().toString();
}
}
DijalogX
package com.example.dezox.dijaloglist;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
public class DijalogX extends DialogFragment {
private String[] languageList;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initListResource();
}
private void initListResource() {
languageList = getResources().getStringArray(R.array.language_list);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
android.R.style.Theme_Material_Dialog_Alert)
.setTitle("Select Language: ")
.setItems(languageList, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String selectedItem = languageList[which];
//THIS PART OF THE CODE I DONT UNDERSTAND:
((MainActivity)getActivity()).setTextField(selectedItem);
}
});
return builder.create();
}
}
You have declared a method in MainActivity called setTextField. If you called
Activity a = getActivity();
you would not be able to call your custom method (it is on your derived class, not the base Activity class).
a.setTextField(selectedIte); // WON'T WORK - NO SUCH METHOD
If instead you call
MainActivity ma = (MainActivity)getActivity();
it is now cast as your derived class and you can then call
ma.setTextField(selectedItem);
Doing it in two lines like this is the same as calling the one-liner in your code
((MainActivity)getActivity()).setTextField(selectedItem);
As far as casting vs. an interface, an interface is a bit more flexible of an approach. If you tried to use this fragment in a different activity (not MainActivity) the casting approach would fail. If you are only ever going to use the fragment in this Activity then either would work.

Using LoaderCallbacks without Fragment

I am doing some hands-on reading on AsyncTaskLoader so I can use the technique to load the contact list. The only time the code works is when I implement the callbacks from a class that extends Fragment as in MyLoader extends Fragment implements LoaderCallbacks<ArrayList<Contact>>. Is there another way? All I really need is the contact list (name, phone, thumbnail), to send to my backend. When, for example, I try to use Context, since I can get that from any activity by simply doing (Context)this, the code fails to even compile. By context I mean
context.getLoaderManager().initLoader(1, null, this);
//I already changed to Fragment so don't really remember the exact ".context" line.
//But someone who has done this will understand the snippet.
BTW: I am using multiple references. One is http://developer.android.com/reference/android/content/AsyncTaskLoader.html.
QUESTION (again): Can I use AsyncTaskLoader without Fragment or FragmentActivity?
THE CODE THAT WORKS WITH THE FRAGMENT:
package com.example.contactpreload.utils;
import java.util.ArrayList;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
public class LoadingContacts extends Fragment implements LoaderCallbacks<ArrayList<Contact>> {
ArrayList<Contact> loadedContacts;
static Fragment fragmentActivity;
public static LoadingContacts newInstance(int arg) {
LoadingContacts f = new LoadingContacts();
Bundle bundle = new Bundle();
bundle.putInt("index", arg);
f.setArguments(bundle);
fragmentActivity = new Fragment();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("onCreate()");
int mIndex = getArguments().getInt("index");
System.out.println(mIndex);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println("onActivityCreated()");
getLoaderManager().initLoader(1, null, this);
}
#Override
public Loader<ArrayList<Contact>> onCreateLoader(int arg0, Bundle arg1) {
System.out.println("onCreateLoader()");
return new ContactsLoader(getActivity());
}
#Override
public void onLoadFinished(Loader<ArrayList<Contact>> loader, ArrayList<Contact> data) {
loadedContacts = data;
System.out.println("AND THE CONTACTS ARE: ");
for (Contact c : loadedContacts) {
System.out.println("NAME: " + c.getName());
System.out.println("getPhoneNumberHome: " + c.getPhoneNumber());
}
}
#Override
public void onLoaderReset(Loader<ArrayList<Contact>> arg0) {
System.out.println("onLoaderReset()");
// TODO Auto-generated method stub
}
}
package com.example.contactpreload;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import com.example.contactpreload.utils.LoadingContacts;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoadingContacts fragment = LoadingContacts.newInstance(1);
fragment.setRetainInstance(true);
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, fragment).commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
MANIFEST:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
AsyncTaskLoader has nothing to do with whether you are using a Fragment or an Activity.
To give you an example, consider a list activity:
public class ExampleActivity extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.todo_list);
//to start the loader:
getLoaderManager().initLoader(0, null, this);
}
//override the loader callback methods as usual
// Creates a new loader after the initLoader () call
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader = new CursorLoader(this,
uri, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// data is not available anymore, delete reference
adapter.swapCursor(null);
}
}
Obviously you need to create corresponding adapter for the list view and layout, but the example just shows you how a simple loader for cursor would work for an Activity.
Also, make sure all your import are consistent, either using the support.v4 library, or the regular library:
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
Another question that is asked, is that if the LoaderCallback interface can be used standalone. This is not recommended if you consider that the LoaderCallback is for.
The LoaderManager.LoaderCallbacks<D> interface is a simple contract that the LoaderManager uses to report data back to the client. What that means, is its only job is to load some data in the background requested by a client, which is effectively, an activity.
If you create a standalone class, you could extend the class definition to implement LoaderManager.LoaderCallbacks<D>, but you will need to report the loaded data back to the original activity through some kind of mechanism, which would complicated a simple task.
Now if you are really fixed on doing this, you could create your standalone class as so:
public class LoadingContacts implements LoaderManager.LoaderCallbacks<Cursor> {
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return null;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}
In your onLoadFinished method, you will need to send the loaded Cursor back through either a broadcast, or some kind of message bus:
LocalBroadcastManager
Otto
Messenger
After you send this information to the MainActivity, you can load it to the adapter and continue as is.

SimpleCursorLoader onCreateLoader error, return type mismatch

I am using an SQLite database and wish to load it without using a ContentProvider.
I am having trouble getting my subclassed SimpleCursorLoader (taken from CursorLoader usage without ContentProvider) to work with the LoaderManager.
In the overwritten method
#Override
public Loader<Cursor> onCreateLoader(int ID, Bundle args) {
return new ListCursorLoader(this, dBHelper);
}
I get a type mismatch saying that it cannot convert from ListCursorLoader to Loader<Cursor>. I have tried creating the ListCursorLoader on the fly (that is, in the method), but this does not work either.
Here is the code for my ListCursorLoader:
package utilities;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
public class ListCursorLoader extends SimpleCursorLoader {
private DBAdapter dBAdapter;
public ListCursorLoader(Context context, DBAdapter adapter) {
super(context);
dBAdapter = adapter;
}
#Override
public Cursor loadInBackground() {
Cursor cursor = null;
dBAdapter.open();
try {
cursor = dBAdapter.getAllQueries();
} catch (SQLException e) {
e.printStackTrace();
}
if (cursor != null) {
cursor.getCount();
}
return cursor;
}
}
As you can see I have only overwritten the loadInBackground() method, and I simply cannot see what I am doing wrong.
Hope you guys can help!
I just tried your code and it worked without an issue.
You should double-check your imports. The SimpleCursorLoader you linked to is using the support library. You didn't provide the code, but I think you may be using the default LoaderManager, not the one provided by the support library.
So for you to be able to use this class you need to reference android.support.v4.content.Loader and load it using the SupportLoaderManager in your Fragment.
Here is the code from my Fragment that worked:
(Note the use of the support library.)
import android.database.Cursor;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
...
public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor>{
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.getSupportLoaderManager().initLoader(0, null, this);
}
...
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
return new ListCursorLoader(this);
}
...
}

SuperNotCalledException running unit test

I am trying to run this Android unit test, following this tutorial ::
http://developer.android.com/resources/tutorials/testing/helloandroid_test.html
and in doing so get a SuperNotCalledException
Here's the test class code ::
package com.example.helloandroid2.test;
import android.test.ActivityInstrumentationTestCase2;
import android.widget.TextView;
import com.example.helloandroid2.HelloAndroid2Activity;
public class HelloAndroid2Test extends ActivityInstrumentationTestCase2<HelloAndroid2Activity>
{
private HelloAndroid2Activity mActivity;
private TextView mView;
private String resourceString;
public HelloAndroid2Test()
{
super("com.example.helloandroid2", HelloAndroid2Activity.class);
}
#Override
protected void setUp() throws Exception
{
super.setUp();
mActivity = this.getActivity();
mView = (TextView) mActivity.findViewById(com.example.helloandroid2.R.id.textview);
resourceString = mActivity.getString(com.example.helloandroid2.R.string.hello);
}
public void testPreconditions()
{
assertNotNull(mView);
}
public void testText()
{
assertEquals(resourceString,(String)mView.getText());
}
}
The class I'm actually testing ::
package com.example.helloandroid2;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloAndroid2Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
}
}
I've set the project API levels at 2_3_1 and am using an avd set at the same.
Am running Eclipse with ADT on Windows Vista.
All wisdom greatfully recieved. Thanks in advance.
Chris
Your onCreate() method in HelloAndroid2Activity needs to call super.onCreate(savedInstanceState);
public class HelloAndroid2Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

Categories

Resources