I'm having trouble starting a task after it has been cancelled the first time. It will run when entering the view, and starting the task, then cancel works when the fragment is first destroyed. But when re-entering the view, the AsyncTask will no longer run.
Is it possible some class state that needs to be cleaned up? Or do I need to remove the Fragment with the AsyncTask from the back stack?
Here is my code below:
package com.emijit.lighteningtalktimer;
import android.content.ContentUris;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.emijit.lighteningtalktimer.data.Timer;
import com.emijit.lighteningtalktimer.data.TimerContract.TimerEntry;
public class RunTimerFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
private static final String LOG_TAG = RunTimerFragment.class.getSimpleName();
private View rootView;
private Uri mUri;
private long mTimerId = 0;
private Timer mTimer;
private RunTimerTask mRunTimerTask;
private static final int DETAIL_LOADER = 0;
public static String URI = "URI";
public RunTimerFragment() {
}
static class ViewHolder {
TextView intervals;
TextView timerSeconds;
TextView timerMinutes;
TextView timerHours;
public ViewHolder(View view) {
intervals = (TextView) view.findViewById(R.id.run_timer_intervals);
timerSeconds = (TextView) view.findViewById(R.id.timer_seconds);
timerMinutes = (TextView) view.findViewById(R.id.timer_minutes);
timerHours = (TextView) view.findViewById(R.id.timer_hours);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_run_timer, container, false);
ViewHolder viewHolder = new ViewHolder(rootView);
rootView.setTag(viewHolder);
Bundle arguments = getArguments();
if (arguments != null) {
mUri = arguments.getParcelable(URI);
if (mUri != null) {
mTimerId = ContentUris.parseId(mUri);
Log.d(LOG_TAG, "mTimerId: " + mTimerId);
}
}
return rootView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(DETAIL_LOADER, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (mTimerId != 0) {
return new CursorLoader(
getActivity(),
TimerEntry.CONTENT_URI,
null,
TimerEntry._ID + " = ?",
new String[] { Long.toString(mTimerId) },
null
);
}
return null;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (cursor != null && cursor.moveToFirst()) {
mTimer = new Timer(cursor);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
public void startTimer() {
mRunTimerTask = new RunTimerTask();
mRunTimerTask.execute(mTimer);
}
#Override
public void onPause() {
super.onPause();
mRunTimerTask.cancel(true);
}
private class RunTimerTask extends AsyncTask<Timer, Integer, Long> {
private final String LOG_TAG = RunTimerTask.class.getSimpleName();
Timer mTimer;
int mCurrentSeconds = 0;
int mCurrentIntervals = 0;
#Override
protected Long doInBackground(Timer... params) {
Log.d(LOG_TAG, "doInBackground");
mTimer = params[0];
while (mTimer.getIntervals() > mCurrentIntervals) {
try {
Thread.sleep(1000);
mCurrentSeconds++;
publishProgress(mCurrentSeconds);
} catch (InterruptedException e) {
Log.d(LOG_TAG, e.toString());
}
}
return (long) mCurrentIntervals;
}
#Override
protected void onProgressUpdate(Integer... values) {
// do stuff
}
#Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
Log.d(LOG_TAG, "onPostExecute");
}
}
}
I think the issue might be in the catch block. Not sure about the mTimer.getIntervals() because it's from third party.
When you cancel the task. The InterruptedException will be caught in the task thread. Then your loop will still keep going because you didn't return or break the loop.
Since all AsyncTask will be queued up in one thread pool of size 1, even if you start another AsyncTask, it will still be blocked.
In your sample, I cannot see any call to startTimer(). Should you be overiding onResume() and calling startTimer() in there?
Related
When app is started it works fine i can swipe left and right without any problem. But as soon as app is been minimized and resumed it again calls the loader and data is been fetched again it results into more no of dots in bottom.
ps: The loader is been called again as dots are in onLoadfinshed.
At first launch
Intial launch
After minimizing and resuming the app
after resuming
package com.example.kaushal.slider;
/**
* Created by kaushal on 25-09-2017.
*/
import android.app.LoaderManager;
import android.content.Loader;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import java.util.List;
public class MainActivity1 extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<video1>> {
customadap adap;
ViewPager viewPager;
private List<video1> videolist;
int LoaderId = 1;
LinearLayout slidedotepanel;
int dotscount;
ImageView[] dots;
String jsonurl = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main1);
viewPager =(ViewPager)findViewById(R.id.viewpager);
slidedotepanel = (LinearLayout)findViewById(R.id.SliderDots);
LoaderManager lm = getLoaderManager();
lm.initLoader(LoaderId,null,this);
}
#Override
public Loader<List<video1>> onCreateLoader(int i, Bundle bundle) {
return new videoLoader1(this,jsonurl);
}
#Override
public void onLoadFinished(Loader<List<video1>> loader, List<video1> videos) {
adap = new customadap(videos,this);
viewPager.setAdapter(adap);
dotscount = adap.getCount();
dots = new ImageView[dotscount];
for(int i = 0;i<dotscount;i++) {
dots[i] = new ImageView(this);
dots[i].setImageDrawable(ContextCompat.getDrawable(this, R.drawable.nonactive_dot));
LinearLayout.LayoutParams layout_linear = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layout_linear.setMargins(8, 0, 8, 0);
slidedotepanel.addView(dots[i], layout_linear);
}
dots[0].setImageDrawable(ContextCompat.getDrawable(this,R.drawable.active_dot));
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
for(int i =0; i<dotscount;i++){
dots[i].setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.nonactive_dot));
}
dots[position].setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.active_dot));
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
#Override
public void onLoaderReset(Loader<List<video1>> loader) {
}
/*
public void getlib(){
StringRequest stringRequest = new StringRequest(jsonurl, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
JSONObject jsonObject = jsonArray.getJSONObject(0);
JSONArray jarray = jsonObject.getJSONArray("videolist");
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
}*/
}
Updated: currently i am handling it via deleting the loader on LoadFinished in last line it works fine but won't able to handle orientation changes any better approach appreciated.
In the Activity's onCreate, we should check with the load manager if an existing thread already exists. If it does, we should not call initLoader. I've provided a simple example of how to use AsyncTaskLoader.
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import java.lang.ref.WeakReference;
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Integer> {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int TASK_LOADER_ID = 10;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate. Entered function.");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoaderManager loaderManager = getSupportLoaderManager();
Loader<Integer> myLoader = loaderManager.getLoader(TASK_LOADER_ID);
if (myLoader != null && MyAsyncTask.isRunning()) {
Log.d(TAG, "onCreate --> Existing loader exists and is running. Re-using it.");
// We use initLoader instead of restartLoader as callbacks
// must be replaced with those from this new activity
loaderManager.initLoader(TASK_LOADER_ID, null, this);
MyAsyncTask.setActivity(new WeakReference<>(this));
showProcess( true);
} else {
Log.d(TAG, "onCreate --> Loader is not active.");
showProcess( false);
}
}
private void showProcess(boolean pShowProcess) {
SeekBar seekBar = (SeekBar) findViewById(R.id.sb_progress);
Button btnStart = (Button) findViewById(R.id.btn_start);
Button btnCancel = (Button) findViewById(R.id.btn_cancel);
if (pShowProcess) {
seekBar.setVisibility(View.VISIBLE);
btnStart.setEnabled(false);
btnCancel.setEnabled(true);
}
else {
seekBar.setVisibility(View.INVISIBLE);
seekBar.setProgress(0);
btnStart.setEnabled(true);
btnCancel.setEnabled(false);
}
}
public void clickStart(View view) {
LoaderManager loaderManager = getSupportLoaderManager();
// Restart existing loader if it exists, otherwise a new one (initLoader) is auto created
loaderManager.restartLoader(TASK_LOADER_ID, null, this);
}
// A graceful attempt to stop the loader
public void clickCancel(View view) {
Loader<Integer> myLoader = getSupportLoaderManager().getLoader(TASK_LOADER_ID);
if (myLoader != null) {
MyAsyncTask.cancelled(true);
}
}
#Override
public Loader<Integer> onCreateLoader(int pID, Bundle pArgs) {
Log.d(TAG, "onCreateLoader. Entered function.");
showProcess(true);
return new MyAsyncTask(this);
}
#Override
public void onLoadFinished(Loader<Integer> pLoader, Integer pResult) {
Log.d(TAG, "onLoadFinished --> Number of items processed = " + pResult);
showProcess( false);
getLoaderManager().destroyLoader(TASK_LOADER_ID);
}
#Override
public void onLoaderReset(Loader<Integer> pLoader) { }
private static class MyAsyncTask extends AsyncTaskLoader<Integer> {
private final static int SLEEP_TIME = 10 * 10; // 100 milliseconds
static WeakReference<MainActivity> aActivity;
private static boolean isRunning = false, cancelled = true;
private Integer aResult; // Holds the results once the task is finished or cancelled
MyAsyncTask(MainActivity pActivity) {
super(pActivity);
aActivity = new WeakReference<>(pActivity);
}
synchronized static void setActivity(WeakReference<MainActivity> pActivity) {
aActivity = pActivity;
}
synchronized static void cancelled(boolean pCancelled) {
cancelled = pCancelled;
}
static boolean isRunning() {
return isRunning;
}
#Override
protected void onStartLoading() {
Log.d(TAG, "onStartLoading. Entered function. cancelled = " + cancelled);
super.onStartLoading();
if (aResult != null) {
deliverResult(aResult);
return;
}
if (!isRunning) { // Don't start a new process unless explicitly initiated by clickStart
Log.d(TAG, "onStartLoading --> No existing process running, so we can start a new one.");
forceLoad();
}
}
#Override
public Integer loadInBackground() {
Log.d(TAG, "loadInBackground. Entered function.");
isRunning = true;
cancelled = false;
int i;
for (i = 1; i < 100 && !cancelled; i++) {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
if (aActivity.get() != null) {
SeekBar seekBar = (SeekBar) aActivity.get().findViewById(R.id.sb_progress);
seekBar.setProgress(i);
}
if (i % 15 == 0) {
Log.d(TAG, "Process running with i = " + i);
}
}
isRunning = false;
aResult = i;
return aResult;
}
}
}
activity_main.xml is given below.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.snoopy.loadertest.MainActivity">
<SeekBar
android:id="#+id/sb_progress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickStart"
android:text="Start Process"
app:layout_constraintBottom_toTopOf="#id/sb_progress"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
When the 'Start Button' is clicked, it makes the SeekBar visible and starts the AsyncTaskLoader in a separate thread. While the task is running, you can rotate the device and send it to the background. On restarting the app, onCreate checks if the task exists. If so, it updates the new Activity object to the task so that the new progress bar can be updated by the task. I've tested this and it works. This should give you a better idea on how to use AsyncTaskLoader and manage resume.
I am trying to implement and autocomplete function for an edittext in a fragment but having trouble passing the context of the fragment to the listener/textwatcher. In the constructor, it accepts the context as a parameter but brings an "inconvertable types" error when trying to link the context to the fragment.
`EmpAddFragment mainActivity = ((EmpAddFragment)context);`
Below is the code for the listener and the fragment where it is called.
CustomAutoCompleteTextChangedListener.java:
import android.content.Context;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
public class CustomAutoCompleteTextChangedListener implements TextWatcher {
public static final String TAG = "CustomAutoCompleteTextChangedListener.java";
Context context;
View view;
Fragment fragment;
public CustomAutoCompleteTextChangedListener(Context context){
this.context = context;
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence userInput, int start, int before, int count) {
EmpAddFragment mainActivity = ((EmpAddFragment)context);
// query the database based on the user input
mainActivity.item = mainActivity.getItemsFromDb(userInput.toString());
// update the adapater
mainActivity.myAdapter.notifyDataSetChanged();
mainActivity.myAdapter = new ArrayAdapter<String>(mainActivity.getActivity(), android.R.layout.simple_dropdown_item_1line, mainActivity.item);
mainActivity.myAutoComplete.setAdapter(mainActivity.myAdapter);
}
}
EmpAddFragment:
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.*;
public class EmpAddFragment extends Fragment implements OnClickListener {
// UI references
private EditText empNameEtxt;
private Button addButton;
private Button resetButton;
/*
* Change to type CustomAutoCompleteView instead of AutoCompleteTextView
* since we are extending to customize the view and disable filter
* The same with the XML view, type will be CustomAutoCompleteView
*/
CustomAutoCompleteView myAutoComplete;
// adapter for auto-complete
ArrayAdapter<String> myAdapter;
// for database operations
DataBaseHelper databaseH;
// just to add some initial value
String[] item = new String[] {"Please search..."};
private static final SimpleDateFormat formatter = new SimpleDateFormat(
"yyyy-MM-dd", Locale.ENGLISH);
DatePickerDialog datePickerDialog;
Calendar dateCalendar;
Employee employee = null;
private EmployeeDAO employeeDAO;
private AddEmpTask task;
public static final String ARG_ITEM_ID = "emp_add_fragment";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
employeeDAO = new EmployeeDAO(getActivity());
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_add_emp, container,
false);
findViewsById(rootView);
setListeners();
try{
// instantiate database handler
databaseH = new DataBaseHelper(getActivity());
// autocompletetextview is in activity_main.xml
myAutoComplete = (CustomAutoCompleteView) rootView.findViewById(R.id.myautocomplete);
// add the listener so it will tries to suggest while the user types
myAutoComplete.addTextChangedListener(new CustomAutoCompleteTextChangedListener(this.getActivity()));
// set our adapter
myAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_dropdown_item_1line, item);
myAutoComplete.setAdapter(myAdapter);
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
//For orientation change.
if (savedInstanceState != null) {
dateCalendar = Calendar.getInstance();
if (savedInstanceState.getLong("dateCalendar") != 0)
dateCalendar.setTime(new Date(savedInstanceState
.getLong("dateCalendar")));
}
return rootView;
}
private void setListeners() {
Calendar newCalendar = Calendar.getInstance();
datePickerDialog = new DatePickerDialog(getActivity(),
new OnDateSetListener() {
public void onDateSet(DatePicker view, int year,
int monthOfYear, int dayOfMonth) {
dateCalendar = Calendar.getInstance();
dateCalendar.set(year, monthOfYear, dayOfMonth);
}
}, newCalendar.get(Calendar.YEAR),
newCalendar.get(Calendar.MONTH),
newCalendar.get(Calendar.DAY_OF_MONTH));
addButton.setOnClickListener(this);
resetButton.setOnClickListener(this);
}
protected void resetAllFields() {
empNameEtxt.setText("");
}
private void setEmployee() {
employee = new Employee();
employee.setName(empNameEtxt.getText().toString());
}
#Override
public void onResume() {
getActivity().setTitle(R.string.add_emp);
getActivity().getActionBar().setTitle(R.string.add_emp);
super.onResume();
}
#Override
public void onSaveInstanceState(Bundle outState) {
if (dateCalendar != null)
outState.putLong("dateCalendar", dateCalendar.getTime().getTime());
}
private void findViewsById(View rootView) {
empNameEtxt = (EditText) rootView.findViewById(R.id.etxt_name);
addButton = (Button) rootView.findViewById(R.id.button_add);
resetButton = (Button) rootView.findViewById(R.id.button_reset);
}
#Override
public void onClick(View view) {
if (view == null) {
} else if (view == addButton) {
setEmployee();
task = new AddEmpTask(getActivity());
task.execute((Void) null);
} else if (view == resetButton) {
resetAllFields();
}
}
public class AddEmpTask extends AsyncTask<Void, Void, Long> {
private final WeakReference<Activity> activityWeakRef;
public AddEmpTask(Activity context) {
this.activityWeakRef = new WeakReference<Activity>(context);
}
#Override
protected Long doInBackground(Void... arg0) {
long result = employeeDAO.save(employee);
return result;
}
#Override
protected void onPostExecute(Long result) {
if (activityWeakRef.get() != null
&& !activityWeakRef.get().isFinishing()) {
if (result != -1)
Toast.makeText(activityWeakRef.get(), "Employee Saved",
Toast.LENGTH_LONG).show();
}
}
}
// this function is used in CustomAutoCompleteTextChangedListener.java
public String[] getItemsFromDb(String searchTerm){
// add items on the array dynamically
List<MyObject> products = databaseH.read(searchTerm);
int rowCount = products.size();
String[] item = new String[rowCount];
int x = 0;
for (MyObject record : products) {
item[x] = record.objectName;
x++;
}
return item;
}
}
This is the logcat when i used
`EmpAddFragment mainActivity = new EmpAddFragment;
All other attempts output the inconvertable types error
LogCat:
07-23 06:49:17.828 2017-2017/com.example.autoFill E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.autoFill, PID: 2017
java.lang.NullPointerException
at com.example.autoFill.EmpAddFragment.getItemsFromDb(EmpAddFragment.java:209)
at com.example.autoFill.CustomAutoCompleteTextChangedListener.onTextChanged(CustomAutoCompleteTextChangedListener.java:42)
at android.widget.TextView.sendOnTextChanged(TextView.java:7408)
at android.widget.TextView.handleTextChanged(TextView.java:7467)
at android.widget.TextView$ChangeWatcher.onTextChanged(TextView.java:9187)
at android.text.SpannableStringBuilder.sendTextChanged(SpannableStringBuilder.java:962)
at android.text.SpannableStringBuilder.replace(SpannableStringBuilder.java:496)
at android.text.SpannableStringBuilder.delete(SpannableStringBuilder.java:212)
at android.text.SpannableStringBuilder.delete(SpannableStringBuilder.java:30)
at android.view.inputmethod.BaseInputConnection.deleteSurroundingText(BaseInputConnection.java:243)
at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:382)
at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:77)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
UPDATE:
Changed my listener constructor to:
public CustomAutoCompleteTextChangedListener(EmpAddFragment frag){
frag = fragment;
context = fragment.getActivity();
}
and the call to:
myAutoComplete.addTextChangedListener(new CustomAutoCompleteTextChangedListener(this));
But register a NullPointerException in the logcat pointing to:
myAutoComplete.addTextChangedListener(new CustomAutoCompleteTextChangedListener(this));
AND:
context = fragment.getActivity();
Change the constructor of your listener class
public class CustomAutoCompleteTextChangedListener implements TextWatcher {
public static final String TAG = "CustomAutoCompleteTextChangedListener.java";
Context context;
View view;
Fragment fragment;
public CustomAutoCompleteTextChangedListener(EmpAddFragment fragment){
this.fragment = fragment;
this.context = fragment.getActivity();
}
//.... rest of your listener class implementation
}
Use the calling method as follows where you face "inconvertible types"
EmpAddFragment mainFragment = ((EmpAddFragment)fragment);
Hope it works!
myAutoComplete.addTextChangedListener(new CustomAutoCompleteTextChangedListener(this.getActivity()));
with the line above you are not passing the fragment but the activity from where it is called so when you call:
EmpAddFragment mainActivity = ((EmpAddFragment)context);
it can't work because you are casting to EmpAddFragment an Activity instance.
so if you want to have the fragment instance change the listener constructor and pass the fragment.
if you want to have the activity then cast the context to the activity
Been trying to load data from sqlite and display it on viewpager without much success.
I have a viewpager with two tabs which should hold data based on the tag_id passed as a parameter of newInstance. There is also an action bar navigation spinner with a list of counties that is used for filter data displayed based on the county_id.
Am able to fetch data from server and save it in the sqlite db but displaying it is the problem. Data is not dispalyed on the first page of the viewpager but it exists in the sqlite. Data for the second is the only one laoded.
Below is my implementation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.OnNavigationListener;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkError;
import com.android.volley.NoConnectionError;
import com.android.volley.ParseError;
import com.android.volley.Response;
import com.android.volley.ServerError;
import com.android.volley.TimeoutError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.app.adapter.CustomCountySpinnerAdapter;
import com.app.adapter.TendersAdapter;
import com.app.database.DBFunctions;
import com.app.externallib.AppController;
import com.app.model.CountyModel;
import com.app.model.PostsModel;
import com.app.utils.AppConstants;
import com.app.utils.PostsListLoader;
import com.nhaarman.listviewanimations.appearance.simple.SwingBottomInAnimationAdapter;
import com.viewpagerindicator.TabPageIndicator;
public class PublicTendersFragment extends Fragment{
private static List<PubliTenders> public_tenders;
public PublicTendersFragment newInstance(String text) {
PublicTendersFragment mFragment = new PublicTendersFragment();
Bundle mBundle = new Bundle();
mBundle.putString(AppConstants.TEXT_FRAGMENT, text);
mFragment.setArguments(mBundle);
return mFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public_tenders = new ArrayList<PubliTenders>();
public_tenders.add(new PubliTenders(14, "County"));
public_tenders.add(new PubliTenders(15, "National"));
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final Context contextThemeWrapper = new ContextThemeWrapper(
getActivity(), R.style.StyledIndicators);
LayoutInflater localInflater = inflater
.cloneInContext(contextThemeWrapper);
View v = localInflater.inflate(R.layout.fragment_tenders, container,
false);
FragmentPagerAdapter adapter = new TendersVPAdapter(
getFragmentManager());
ViewPager pager = (ViewPager) v.findViewById(R.id.pager);
pager.setAdapter(adapter);
TabPageIndicator indicator = (TabPageIndicator) v
.findViewById(R.id.indicator);
indicator.setViewPager(pager);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
class TendersVPAdapter extends FragmentPagerAdapter{
public TendersVPAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return Tenders.newInstance(public_tenders.get(position).tag_id);
case 1:
return Tenders.newInstance(public_tenders.get(position).tag_id);
default:
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
return public_tenders.get(position).tender_type.toUpperCase(Locale
.getDefault());
}
#Override
public int getCount() {
return public_tenders.size();
}
}
public class PubliTenders {
public int tag_id;
public String tender_type;
public PubliTenders(int tag_id, String tender_type) {
this.tag_id = tag_id;
this.tender_type = tender_type;
}
}
public static class Tenders extends ListFragment implements
OnNavigationListener, LoaderCallbacks<ArrayList<PostsModel>> {
boolean mDualPane;
int mCurCheckPosition = 0;
// private static View rootView;
private SwipeRefreshLayout swipeContainer;
private ListView lv;
private View rootView;
private DBFunctions mapper;
private CustomCountySpinnerAdapter spinadapter;
private TendersAdapter mTendersAdapter;
private static final String ARG_TAG_ID = "tag_id";
private int tag_id;
private int mycounty;
private static final int INITIAL_DELAY_MILLIS = 500;
private static final String DEBUG_TAG = "BlogsFragment";
private final String TAG_REQUEST = "BLOG_TAG";
private JsonArrayRequest jsonArrTendersRequest;
// private OnItemSelectedListener listener;
public static Tenders newInstance(int tag_id) {
Tenders fragment = new Tenders();
Bundle b = new Bundle();
b.putInt(ARG_TAG_ID, tag_id);
fragment.setArguments(b);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tag_id = getArguments().getInt(ARG_TAG_ID);
}
#Override
public void onStart() {
super.onStart();
getLoaderManager().initLoader(0, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_headlines_blog,
container, false);
swipeContainer = (SwipeRefreshLayout) rootView
.findViewById(R.id.swipeProjectsContainer);
lv = (ListView) rootView.findViewById(android.R.id.list);
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view,
int scrollState) {
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int topRowVerticalPosition = (lv == null || lv
.getChildCount() == 0) ? 0 : lv.getChildAt(0)
.getTop();
swipeContainer.setEnabled(topRowVerticalPosition >= 0);
}
});
swipeContainer.setOnRefreshListener(new OnRefreshListener() {
#Override
public void onRefresh() {
fetchPublicTenders(mycounty);
}
});
swipeContainer.setColorSchemeResources(R.color.blue_dark,
R.color.irdac_green, R.color.red_light,
R.color.holo_red_light);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
mapper = new DBFunctions(getActivity());
mapper.open();
// initialize AB Spinner
populateSpinner();
fetchPublicTenders(mycounty);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
private void populateSpinner() {
try {
List<CountyModel> counties = new ArrayList<CountyModel>();
counties = mapper.getAllCounties();
ActionBar actBar = ((ActionBarActivity) getActivity())
.getSupportActionBar();
actBar.setDisplayShowTitleEnabled(true);
actBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
spinadapter = new CustomCountySpinnerAdapter(getActivity(),
android.R.layout.simple_spinner_dropdown_item, counties);
actBar.setListNavigationCallbacks(spinadapter, this);
} catch (NullPointerException exp) {
}
}
#Override
public Loader<ArrayList<PostsModel>> onCreateLoader(int arg0,
Bundle arg1) {
Log.v(DEBUG_TAG, "On Create Loader");
return new PostsListLoader(getActivity(), mycounty, tag_id);
}
#Override
public void onLoadFinished(Loader<ArrayList<PostsModel>> arg0,
ArrayList<PostsModel> data) {
// System.out.println("results " + data.size());
addToAdapter(data);
}
#Override
public void onLoaderReset(Loader<ArrayList<PostsModel>> arg0) {
lv.setAdapter(null);
}
#Override
public boolean onNavigationItemSelected(int pos, long arg1) {
CountyModel mo = spinadapter.getItem(pos);
this.mycounty = mo.getId();
refresh(mo.getId());
return false;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
TextView txtTitle = (TextView) v.findViewById(R.id.tender_title);
TextView txtRefNo = (TextView) v.findViewById(R.id.ref_no);
TextView txtExpiryDate = (TextView) v
.findViewById(R.id.expiry_date);
TextView txtOrg = (TextView) v.findViewById(R.id.dept_or_org);
Intent intTenderFullDetails = new Intent(getActivity(),
TenderDetailsActivity.class);
intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_TITLE,
txtTitle.getText().toString().trim());
intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_REF_NO,
txtRefNo.getText().toString().trim());
intTenderFullDetails.putExtra(
TenderDetailsActivity.TENDER_EXPIRY_DATE, txtExpiryDate
.getText().toString().trim());
intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_ORG,
txtOrg.getText().toString().trim());
// intTenderFullDetails.putExtra(TenderDetailsActivity.TENDER_DESC,
// Lorem);
startActivity(intTenderFullDetails);
}
private void fetchPublicTenders(final int county_id) {
swipeContainer.setRefreshing(true);
Uri.Builder builder = Uri.parse(AppConstants.postsUrl).buildUpon();
builder.appendQueryParameter("tag_id", Integer.toString(tag_id));
System.out.println("fetchPublicTenders with tag_id " + tag_id
+ " and county_id " + county_id);
jsonArrTendersRequest = new JsonArrayRequest(builder.toString(),
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
if (response.length() > 0) {
for (int i = 0; i < response.length(); i++) {
try {
JSONObject tender_item = response
.getJSONObject(i);
mapper.createPost(
tender_item.getInt("id"),
tender_item.getInt("tag_id"),
tender_item.getInt("county_id"),
tender_item.getInt("sector_id"),
tender_item.getString("title"),
tender_item.getString("slug"),
tender_item.getString("content"),
tender_item
.getString("reference_no"),
tender_item
.getString("expiry_date"),
tender_item
.getString("organization"),
tender_item
.getString("image_url"),
tender_item
.getString("created_at"));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
swipeContainer.setRefreshing(false);
refresh(county_id);
}
} else {
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
try {
Toast.makeText(getActivity(),
"Sorry! No results found",
Toast.LENGTH_LONG).show();
} catch (NullPointerException npe) {
System.out.println(npe);
}
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error instanceof NetworkError) {
try {
Toast.makeText(
getActivity(),
"Network Error. Cannot refresh list",
Toast.LENGTH_SHORT).show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
refresh(county_id);
} else if (error instanceof ServerError) {
try {
Toast.makeText(
getActivity(),
"Problem Connecting to Server. Try Again Later",
Toast.LENGTH_SHORT).show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
} else if (error instanceof AuthFailureError) {
} else if (error instanceof ParseError) {
} else if (error instanceof NoConnectionError) {
try {
Toast.makeText(getActivity(),
"No Connection", Toast.LENGTH_SHORT)
.show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
} else if (error instanceof TimeoutError) {
try {
Toast.makeText(
getActivity()
.getApplicationContext(),
"Timeout Error. Try Again Later",
Toast.LENGTH_SHORT).show();
} catch (NullPointerException npe) {
System.err.println(npe);
}
}
if (swipeContainer.isShown()) {
swipeContainer.setRefreshing(false);
}
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Accept", "application/json");
return headers;
}
};
// Set a retry policy in case of SocketTimeout & ConnectionTimeout
// Exceptions. Volley does retry for you if you have specified the
// policy.
jsonArrTendersRequest.setRetryPolicy(new DefaultRetryPolicy(
(int) TimeUnit.SECONDS.toMillis(20),
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
jsonArrTendersRequest.setTag(TAG_REQUEST);
AppController.getInstance().addToRequestQueue(jsonArrTendersRequest);
}
public void refresh(int county_id) {
Bundle b = new Bundle();
b.putInt("myconty", county_id);
if (isAdded()) {
getLoaderManager().restartLoader(0, b, this);
}
}
private void addToAdapter(ArrayList<PostsModel> plist) {
mTendersAdapter = new TendersAdapter(rootView.getContext(), plist);
SwingBottomInAnimationAdapter swingBottomInAnimationAdapter = new SwingBottomInAnimationAdapter(
mTendersAdapter);
swingBottomInAnimationAdapter.setAbsListView(lv);
assert swingBottomInAnimationAdapter.getViewAnimator() != null;
swingBottomInAnimationAdapter.getViewAnimator()
.setInitialDelayMillis(INITIAL_DELAY_MILLIS);
setListAdapter(swingBottomInAnimationAdapter);
mTendersAdapter.notifyDataSetChanged();
}
}
}
And this is the PostsListLoader class
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import com.app.database.DBFunctions;
import com.app.model.PostsModel;
public class PostsListLoader extends AsyncTaskLoader<ArrayList<PostsModel>> {
private DBFunctions mapper;
private ArrayList<PostsModel> myPostsModel;
private int county_id;
private int tag_id;
public PostsListLoader(Context context, int county_id, int tag_id) {
super(context);
mapper = new DBFunctions(getContext());
mapper.open();
this.county_id = county_id;
this.tag_id = tag_id;
}
#Override
public ArrayList<PostsModel> loadInBackground() {
String query_string = AppConstants.KEY_COUNTY_ID + " = " + county_id
+ " AND " + AppConstants.KEY_TAG_ID + " = " + tag_id;
myPostsModel = mapper.getPosts(query_string);
return myPostsModel;
}
#Override
public void deliverResult(ArrayList<PostsModel> data) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (data != null) {
onReleaseResources(data);
}
}
List<PostsModel> oldNews = data;
myPostsModel = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(data);
}
// At this point we can release the resources associated with
// 'oldNews' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldNews != null) {
onReleaseResources(oldNews);
}
}
/**
* Handles a request to start the Loader.
*/
#Override
protected void onStartLoading() {
if (myPostsModel != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(myPostsModel);
}
if (takeContentChanged() || myPostsModel == null) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
#Override
public void onCanceled(ArrayList<PostsModel> news) {
super.onCanceled(news);
// At this point we can release the resources associated with 'news'
// if needed.
onReleaseResources(news);
}
/**
* Handles a request to completely reset the Loader.
*/
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (myPostsModel != null) {
onReleaseResources(myPostsModel);
myPostsModel = null;
}
}
/**
* Helper function to take care of releasing resources associated with an
* actively loaded data set.
*/
protected void onReleaseResources(List<PostsModel> news) {
}
}
What could I be doing wrong?
Any help will be appreciated.
Thanks
The issue I am having is that I have created a simple count down timer, using AsyncTasks and using the SetRetainInstance(true) to ensure that even with orientation change the counter updates on the ui.
The issue is that I have an editText that gives me the values for the timer and then should pass them on to the Task to count Down. I must be missing something somewhere because, I cannot seem to get the new value.
This is the code that I am using as the Fragment:
package com.example.app;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.Fragment;
import android.util.Log;
public class TaskFragment extends Fragment {
private static final String TAG = TaskFragment.class.getSimpleName();
String i;
int counter;
Bundle bundle;
static interface TaskCallbacks {
public void onPreExecute();
public void onProgressUpdate(int timer);
public void onCancelled();
public void onPostExecute();
}
private TaskCallbacks mCallbacks;
private DummyTask mTask;
private boolean mRunning;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof TaskCallbacks)) {
throw new IllegalStateException("Activity must implement the TaskCallbacks interface.");
}
mCallbacks = (TaskCallbacks) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
bundle=getArguments();
i = bundle.getString("SecValue");
Log.i("VertygoEclypse - TaskFragment-onCreate", i);
counter=Integer.parseInt(i);
}
#Override
public void onDestroy() {
super.onDestroy();
cancel();
}
public void start() {
if (!mRunning) {
bundle=getArguments();
i=bundle.getString("SecValue");
mTask = new DummyTask();
Log.i("VertygoEclypse - TaskFragment - start", i);
mTask.execute();
mRunning = true;
} else{
mTask.cancel(true);
}
}
public void cancel() {
if (mRunning) {
mTask.cancel(true);
mTask = null;
mRunning = false;
}
}
public boolean isRunning() {
return mRunning;
}
private class DummyTask extends AsyncTask<Void, Integer, Void> {
#Override
protected void onPreExecute() {
mCallbacks.onPreExecute();
mRunning = true;
counter=Integer.parseInt(i);
Log.i("Vertygo Eclypse - AsyncTask - onPreExecute", i);
}
#Override
protected Void doInBackground(Void... ignore) {
do {
publishProgress(counter);
SystemClock.sleep(1000);
counter=counter-1;
if(isCancelled()){
mTask.cancel(true);
break;
}
} while (counter>0);
return null;
}
#Override
protected void onProgressUpdate(Integer... timer) {
mCallbacks.onProgressUpdate(timer[0]);
}
#Override
protected void onCancelled() {
mCallbacks.onCancelled();
mRunning = false;
}
#Override
protected void onPostExecute(Void ignore) {
mCallbacks.onPostExecute();
mRunning = false;
}
}
}
That being said I have Log.i set up at a number of spots the onCreate, the start, the pre-execute and the post-execute.
The following excerpt from the logcat shows that some of the values show the entered text, but the start and preexecute are holding the old values:
01-17 17:37:12.383 10261-10261/com.example.app I/VertygoEclypse - replaceFrag﹕ 35
01-17 17:37:12.383 10261-10261/com.example.app I/VertygoEclypse - replaceFrag﹕ 35
01-17 17:37:12.383 10261-10261/com.example.app I/Vertygo Eclypse - MainActivity - replaceFrag﹕ 35
01-17 17:37:12.403 10261-10261/com.example.app I/VertygoEclypse - TaskFragment-onCreate﹕ 35
01-17 17:37:17.247 10261-10261/com.example.app I/VertygoEclypse - TaskFragment - start﹕ 15
01-17 17:37:17.259 10261-10261/com.example.app I/Vertygo Eclypse - AsyncTask - onPreExecute﹕ 15
I am also using Bundle to transfer the text from an EditText to the fragment and using getString() to get the value based on a key.
Below is the MainActivity so far.
package com.example.app;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.util.concurrent.TimeUnit;
public class MainActivity extends FragmentActivity implements TaskFragment.TaskCallbacks {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String KEY_CURRENT_PROGRESS = "current_progress";
private static final String KEY_PERCENT_PROGRESS = "percent_progress";
private static final String TIME_COUNT = "time_count";
private TaskFragment mTaskFragment;
private ProgressBar mProgressBar;
private TextView mPercent, tv1;
private Button mButton;
private EditText secentered;
public String sample;
Bundle bundl;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv1 = (TextView) findViewById(R.id.textView1);
secentered = (EditText) findViewById(R.id.valueentered);
mButton = (Button) findViewById(R.id.task_button);
initialfrag();
mButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (mTaskFragment.isRunning()) {
mButton.setText("Start");
mTaskFragment.cancel();
replaceFrag();
} else {
mButton.setText("Cancel");
mTaskFragment.start();
}
}
});
if (savedInstanceState != null) {
tv1.setText(savedInstanceState.getString(TIME_COUNT));
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(TIME_COUNT, tv1.getText().toString());
}
#Override
public void onPreExecute() {
mButton.setText(getString(R.string.cancel));
Toast.makeText(this, R.string.task_started_msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onProgressUpdate(int timer) {
long timelong = timer*1000;
String tval = getDurationBreakdown(timelong);
tv1.setText(tval);
}
#Override
public void onCancelled() {
mButton.setText(getString(R.string.start));
tv1.setText("0 seconds");
mTaskFragment.cancel();
replaceFrag();
Toast.makeText(this, R.string.task_cancelled_msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onPostExecute() {
mButton.setText(getString(R.string.start));
tv1.setText("Completed");
mTaskFragment.cancel();
replaceFrag();
Toast.makeText(this, R.string.task_complete_msg, Toast.LENGTH_SHORT).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_trigger_config_change:
recreate();
return true;
}
return super.onOptionsItemSelected(item);
}
public static String getDurationBreakdown(long secondstobreak) {
if(secondstobreak < 0)
{
throw new IllegalArgumentException("Duration must be greater than zero!");
}
long hours = TimeUnit.MILLISECONDS.toHours(secondstobreak);
secondstobreak-=TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(secondstobreak);
secondstobreak-=TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(secondstobreak);
secondstobreak-=TimeUnit.SECONDS.toMillis(seconds);
StringBuilder sb = new StringBuilder(64);
if(hours<10){
sb.append("0"+hours);
}else {
sb.append(hours);
}
sb.append(" : ");
if(minutes<10){
sb.append("0"+minutes);
}else{
sb.append(minutes);
}
sb.append(" : ");
if(seconds<10){
sb.append("0"+seconds);
} else {
sb.append(seconds);
}
sb.append(" remaining");
return (sb.toString());
}
public void replaceFrag(){
Bundle bundle = new Bundle();
String tester2 = secentered.getText().toString();
Log.i("VertygoEclypse - replaceFrag", tester2);
if(tester2.matches("")){
bundle.putString("SecValue", "15");
} else {
Log.i("VertygoEclypse - replaceFrag", tester2);
bundle.putString("SecValue", tester2);
}
FragmentTransaction rfm = getSupportFragmentManager().beginTransaction();
rfm.remove(mTaskFragment);
rfm.detach(mTaskFragment);
TaskFragment mTaskFragment = new TaskFragment();
Log.i("Vertygo Eclypse - MainActivity - replaceFrag", tester2);
mTaskFragment.setArguments(bundle);
rfm.add(mTaskFragment, "task").commit();
}
public void initialfrag(){
bundl = new Bundle();
String tester = secentered.getText().toString();
Log.i("VertygoEclypse - initialFrag", tester);
if(tester.matches("")){
bundl.putString("SecValue", "15");
} else{
Log.i("VertygoEclypse - initialFrag", tester);
bundl.putString("SecValue", tester);
}
FragmentManager fm = getSupportFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag("task");
if (mTaskFragment == null) {
mTaskFragment = new TaskFragment();
mTaskFragment.setArguments(bundl);
fm.beginTransaction().add(mTaskFragment, "task").commit();
}
}
}
I know that the value is being passed to the fragment, however I am not certain if the AsyncTask or the Fragment is being replaced or refreshed. What I would like Ideally is to have the AsyncTask killed and a new one created using the new value from the Bundle.
Any help would be greatly appreciated.
Ok all it seems that I have stumbled upon the answer. the issue was th int counter, validcounter; it seems that without the static in front of it, the variable creates it's own instance of it. so with the following static int counter, validcounter; the issue is resolved.
thanks for the sounding board.
regards
cchinchoy
I am setting up to use the Loader pattern and had issues using the cursor approach, so I have refactored my code because my tables do not use _id as the primary key because of the use of association tables and I setup my code to use the same basic structure as the LoaderCustomSupport.java example from the android developer site. All of the code works without errors and I can see that I have the proper data back and ready for the ListFragment to display but after the onLoadFinished call back completes the setData on the adapter the getView is never called. My getView looks like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PhoneNumberListHolder holder;
if (row == null) {
row = mInflater.inflate(R.layout.phonenumber_row, parent, false);
holder=new PhoneNumberListHolder(row);
row.setTag(holder);
} else {
holder = (PhoneNumberListHolder)row.getTag();
}
holder.populateForm(this.phoneNumbers.get(position));
return row;
}
I am trying to use the holder pattern, but I am thinking that maybe it is part of my issue. Any ideas where I might be going wrong?
Here is the loader code (Like I said I followed the Google example for my first run changing what I thought I would need)
The Abstract Loader for my Class
/*
* Custom version of CommonsWare, LLC, AbstractCursorLoader
*
*/
package myApp.service.data;
import java.util.List;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
abstract public class AbstractPhoneNumberLoader extends AsyncTaskLoader<List<PhoneNumber>> {
abstract protected List<PhoneNumber> buildPhoneNumber();
List<PhoneNumber> lastPhoneNumber=null;
public AbstractPhoneNumberLoader(Context context) {
super(context);
}
#Override
public List<PhoneNumber> loadInBackground() {
List<PhoneNumber> data=buildPhoneNumber();
if (data!=null) {
// Make sure we fill the person
data.size();
}
return (data);
}
/**
* This will run on the UI thread, routing the results from the
* background to the consumer of the Person object
* (e.g., a PhoneNumberListAdapter).
*/
#Override
public void deliverResult(List<PhoneNumber> data) {
if (isReset()) {
// An async query attempted a call while the loader is stopped
if (data!=null) {
data.clear();
data=null;
//not sure the best option here since we cannot close the List object
}
return;
}
List<PhoneNumber> oldPhoneNumber=lastPhoneNumber;
lastPhoneNumber=data;
if (isStarted()) {
super.deliverResult(data);
}
if (oldPhoneNumber!=null && oldPhoneNumber!=data && oldPhoneNumber.isEmpty()) {
oldPhoneNumber.clear();
oldPhoneNumber=null;
}
}
/**
* Start an asynchronous load of the requested data.
* When the result is ready the callbacks will be called
* on the UI thread. If a previous load has completed
* and is still valid the result may be passed back to the
* caller immediately.
*
* Note: Must be called from the UI thread
*/
#Override
protected void onStartLoading() {
if (lastPhoneNumber!=null) {
deliverResult(lastPhoneNumber);
}
if (takeContentChanged() || lastPhoneNumber==null) {
forceLoad();
}
}
/**
* Must be called from the UI thread, triggered by
* a call to stopLoading().
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task
cancelLoad();
}
/**
* Must be called from the UI thread, triggered by a
* call to cancel(). Here, we make sure our Person
* is null, if it still exists and is not already empty.
*/
#Override
public void onCanceled(List<PhoneNumber> data) {
if (data!=null && !data.isEmpty()) {
data.clear();
}
}
/**
* Must be called from the UI thread, triggered by a
* call to reset(). Here, we make sure our Person
* is empty, if it still exists and is not already empty.
*/
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (lastPhoneNumber!=null && !lastPhoneNumber.isEmpty()) {
lastPhoneNumber.clear();
}
lastPhoneNumber=null;
}
}
The Data Loader
/*
* Custom version of CommonsWare, LLC, SQLiteCursorLoader
*
*/
package myApp.service.data;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.List;
import myApp.service.data.ActorDbAdapter;
import android.content.Context;
public class PhoneNumberDataLoader extends AbstractPhoneNumberLoader {
ActorDbAdapter db=null;
protected final String actorId;
protected final String _PHONENUMBERID = "PhoneNumberId";
protected SimpleDateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* #param ctx the Context within which to work
*/
public PhoneNumberDataLoader(Context ctx, String actorId) {
super(ctx);
this.actorId = actorId;
getHelper(ctx);
}
// Get a database connection
private void getHelper(Context ctx) {
if (db==null) {
db=new ActorDbAdapter(ctx);
}
db.open();
}
// Loader Methods
/**
* Runs on a worker thread and performs the actual
* database query to retrieve the PhoneNumber List.
*/
#Override
protected List<PhoneNumber> buildPhoneNumber() {
return(db.readPhoneById(actorId));
}
/**
* Writes a semi-user-readable roster of contents to
* supplied output.
*/
#Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.print(prefix);
writer.print("actorId=");
writer.println(actorId);
}
public void insert(PhoneNumber data, String actorId) {
new InsertTask(this).execute(db, data, actorId);
}
// Saved for Later, get Reads and Writes working first
// public void update(PhoneNumber data, String actorId, String whereClause, String[] whereArgs) {
// new UpdateTask(this).execute(db, data, actorId, whereClause, whereArgs);
// }
//
// public void delete(String actorId, String phoneNumberId, String whereClause, String[] whereArgs) {
// new DeleteTask(this).execute(db, actorId, phoneNumberId, whereClause, whereArgs);
// }
public void execSQL(String actorId) {
new ExecSQLTask(this).execute(db, actorId);
}
private class InsertTask extends ContentChangingTask<Object, Void, Void> {
InsertTask(PhoneNumberDataLoader loader) {
super(loader);
}
#Override
protected Void doInBackground(Object... params) {
ActorDbAdapter db=(ActorDbAdapter)params[0];
PhoneNumber data=(PhoneNumber)params[1];
int actorId=Integer.parseInt((String)params[2]);
db.createPhoneNumber(data, actorId);
return(null);
}
}
// Saved for Later, get Reads and Writes working first
// private class UpdateTask extends
// ContentChangingTask<Object, Void, Void> {
// UpdateTask(PhoneNumberDataLoader loader) {
// super(loader);
// }
//
// #Override
// protected Void doInBackground(Object... params) {
// ActorDbAdapter db=(ActorDbAdapter)params[0];
// String table=(String)params[1];
// int actorId=Integer.parseInt((String)params[2]);
// String where=(String)params[3];
// String[] whereParams=(String[])params[4];
//
// db.updatePhoneNumber(table, values, where, whereParams);
//
// return(null);
// }
// }
//
// private class DeleteTask extends
// ContentChangingTask<Object, Void, Void> {
// DeleteTask(PhoneNumberDataLoader loader) {
// super(loader);
// }
//
// #Override
// protected Void doInBackground(Object... params) {
// ActorDbAdapter db=(ActorDbAdapter)params[0];
// int actorId=Integer.parseInt((String)params[1]);
// int phoneNumberId=Integer.parseInt((String)params[2]);
// String where=(String)params[3];
// String[] whereParams=(String[])params[3];
//
// db.deletePhoneNumber(table, where, whereParams);
//
// return(null);
// }
// }
private class ExecSQLTask extends
ContentChangingTask<Object, Void, Void> {
ExecSQLTask(PhoneNumberDataLoader loader) {
super(loader);
}
#Override
protected Void doInBackground(Object... params) {
ActorDbAdapter db=(ActorDbAdapter)params[0];
String actorId=(String)params[1];
db.readPhoneById(actorId);
return(null);
}
}
}
Here is my full ListAdapter
package myApp.planner.utilities;
import java.util.ArrayList;
import java.util.List;
import myApp.planner.R;
import myApp.planner.codes.PhoneOrAddressTypeCode;
import myApp.service.data.PhoneNumber;
import myApp.service.data.PhoneNumberListData;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.TextView;
public class PhoneNumberListAdapter extends ArrayAdapter<PhoneNumber> {
private List<PhoneNumber> phoneNumbers;
private final LayoutInflater mInflater;
private Activity activity;
public PhoneNumberListAdapter(Activity a, int textViewResourceId) {
super(a, textViewResourceId);
activity = a;
mInflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void setData(List<PhoneNumber> data) {
if (this.phoneNumbers==null) {
this.phoneNumbers = new ArrayList<PhoneNumber>();
}
this.phoneNumbers.clear();
if (data != null) {
for (PhoneNumber phoneNumber : data) {
this.phoneNumbers.add(phoneNumber);
}
}
}
public static class PhoneNumberListHolder {
private TextView actorid=null;
private TextView phonenumberid=null;
private TextView phonetype=null;
private TextView phonenumber=null;
private CheckBox isprimary=null;
PhoneNumberListHolder(View row) {
actorid=(TextView)row.findViewById(R.id.actorid);
phonenumberid=(TextView)row.findViewById(R.id.phonenumberid);
phonetype=(TextView)row.findViewById(R.id.txtphonetype);
phonenumber=(TextView)row.findViewById(R.id.txtphonenumber);
isprimary=(CheckBox)row.findViewById(R.id.isprimary);
}
//void populateForm(ArrayList<PhoneNumberListData> c, int position) {
void populateForm(PhoneNumber data) {
//PhoneNumberListData data = c.get(position);
// Attempt to add the Actor ID
if (actorid != null){
actorid.setText(data.getActor().get(0).getActorId()==0 ? "0": Integer.toString(data.getActor().get(0).getActorId()));
}
// Attempt to add the Phone Number Item ID
if (phonenumberid != null){
phonenumberid.setText(data.getPhoneNumberId()==0 ? "0": Integer.toString(data.getPhoneNumberId()));
}
// Attempt to add the Phone Number Type
if (phonetype != null){
phonetype.setText(data.getPhoneType()==null ? "": PhoneOrAddressTypeCode.valueOf(data.getPhoneType()).toString());
}
// Attempt to add the Phone Number
if (phonenumber != null){
phonenumber.setText(data.getPhoneNumber1()==null ? "": data.getPhoneNumber1());
}
// Attempt to add the is Primary Flag
if (isprimary != null){
isprimary.setChecked(data.getIsPrimary()==0 ? Boolean.FALSE: Boolean.TRUE);
}
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
PhoneNumberListHolder holder;
if (row == null) {
row = mInflater.inflate(R.layout.phonenumber_row, parent, false);
holder=new PhoneNumberListHolder(row);
row.setTag(holder);
} else {
holder = (PhoneNumberListHolder)row.getTag();
}
holder.populateForm(this.phoneNumbers.get(position));
return row;
}
}
The ListFragment:
package myApp.planner;
import java.util.ArrayList;
import java.util.List;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SearchViewCompat;
import android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat;
import android.text.TextUtils;
import android.content.Intent;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.view.ContextMenu;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import myApp.planner.R;
import myApp.planner.utilities.PhoneNumberListAdapter;
import myApp.service.data.PhoneNumber;
import myApp.service.data.PhoneNumberDataLoader;
public class ActorPhoneNumberListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<PhoneNumber>> {
public final static String ID_EXTRA="myapp.planner.actorid";
protected final static String TAG = "ActorPhoneNumberListFragment";
private static final int ADD_ID=Menu.FIRST + 1;
private static final int DELETE_ID=Menu.FIRST + 3;
private PhoneNumberListAdapter mAdapter=null;
private PhoneNumberDataLoader loader=null;
private String mCurFilter;
private String actorId = "0";
//private SharedPreferences prefs=null;
OnActorPhoneNumberListListener listener=null;
OnQueryTextListenerCompat mOnQueryTextListenerCompat;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.actorId = getActivity().getIntent().getExtras().getString(ID_EXTRA).toString();
}
#Override
public void onResume() {
super.onResume();
Bundle args=getArguments();
if (args!=null) {
loadPhoneNumbers(args.getString(ID_EXTRA));
}
// init Empty Test for no Phone numbers Found
// Add the menu options that we need to manage the list
setHasOptionsMenu(true);
// Hookup the dbAdapter and create a blank adapter
initList();
}
#Override
public void onPause() {
super.onPause();
}
#Override
public void onListItemClick(ListView list, View view, int position, long id) {
if (listener!=null) {
//We will actually want the PhoneNumber Id here for the popup edit screen
String mId = actorId;
listener.onActorPhoneNumberListSelected(mId);
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.phonenumber_opton, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()==R.id.addNewPhone) {
//add();
return(true);
} else if (item.getItemId()==R.id.help) {
startActivity(new Intent(getActivity(), HelpPage.class));
return(true);
} else if (item.getItemId()==R.id.phoneRefresh) {
//startActivity(new Intent(getActivity(), ActorPhoneNumberListFragment.class));
//We may just need to refresh the loader
return(true);
} else
return(super.onOptionsItemSelected(item));
}
public void setOnActorPhoneNumberListListener(OnActorPhoneNumberListListener listener) {
this.listener=listener;
}
public void loadPhoneNumbers(String actorId) {
this.actorId=actorId;
}
private void initList() {
mAdapter=new PhoneNumberListAdapter(getActivity(), R.layout.phonenumber_row);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
getActivity().getSupportLoaderManager().initLoader(0, null, this);
}
public interface OnActorPhoneNumberListListener {
void onActorPhoneNumberListSelected(String actorId);
}
#Override
public Loader<List<PhoneNumber>> onCreateLoader(int loaderId, Bundle args) {
loader= new PhoneNumberDataLoader(getActivity(), actorId);
return(loader);
}
#Override
public void onLoadFinished(Loader<List<PhoneNumber>> loader, List<PhoneNumber> data) {
// Now give the data to the adapter
mAdapter.setData(data);
mAdapter.notifyDataSetChanged();
//setListAdapter(mAdapter);
// Show the list
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
#Override
public void onLoaderReset(Loader<List<PhoneNumber>> arg0) {
// TODO Auto-generated method stub
mAdapter.setData(null);
}
}