How to refresh Android ListView after SyncAdapter completes a Sync - android

I have extended an AbstractThreadedSyncAdapter and got it to automatically sync data with my server every x minutes or when I manually request a sync via code. It works perfectly.
So now the next step is automatically updating a ListView containing messages and another containing assigned jobs.
The samples I've found all assume you're changing your dataset from within the same Activity or you otherwise have access to the database cursor the ListView is bound to. Unfortunately for the Android Sync Adapter, this is not the case. It runs in the background and has no reference to anything useful as far as I can tell.
My SyncAdapter:
public class VttSyncAdapter extends AbstractThreadedSyncAdapter {
private final AccountManager mAccountManager;
public VttSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
mAccountManager = AccountManager.get(context);
}
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
Log.d("Vtt", "onPerformSync for account[" + account.name + "]");
try
{
//GET SOME DATA FROM WEBSERVICE AND INSERT INTO SQLITE DB
} catch (IOException e) {
e.printStackTrace();
}
//WHAT WOULD ONE DO HERE TO ALERT THE LISTVIEW THAT IT SHOULD REFRESH?
} catch (Exception e) {
e.printStackTrace();
}
public String getsharedresourcestring(String key)
{
Context context = getContext();
SharedPreferences sharedPref = context.getSharedPreferences(context.getString(R.string.preference_file_key), MODE_PRIVATE);
return sharedPref.getString(key,null);
}
}
My Schedule fragment code:
public class ScheduleFragment extends Fragment {
private ListView listView;
private List<DeliveryScheduleEntryModel> schedules;
public ScheduleFragment() {
// Required empty public constructor
}
public static ScheduleFragment newInstance(String param1, String param2) {
ScheduleFragment fragment = new ScheduleFragment();
Bundle args = new Bundle();
//args.putString(ARG_PARAM1, param1);
//args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
//mParam1 = getArguments().getString(ARG_PARAM1);
//mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View ret = inflater.inflate(R.layout.fragment_schedule, container, false);
listView = (ListView) ret.findViewById(R.id.listViewSchedule);
//GET OUR DATA
Activity activity = this.getActivity();
ContentResolver contentResolver = activity.getContentResolver();
schedules = getSchedule(contentResolver);
DeliveryScheduleEntryModelList customList = new DeliveryScheduleEntryModelList(activity, schedules);
listView.setAdapter(customList);
return ret;
}
public List<DeliveryScheduleEntryModel> getSchedule(ContentResolver cr)
{
Context context = getContext();
VttDataSource db = new VttDataSource(context);
db.open();
List<DeliveryScheduleEntryModel> ret = db.getAllDeliveryScheduleEntryModel();
db.close();
return ret;
}
}

//WHAT WOULD ONE DO HERE TO ALERT THE LISTVIEW THAT IT SHOULD REFRESH?
Send a local Broadcast like this:
Intent intent = new Intent();
intent.setAction("com.your_package.name.REFRESH_LIST");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Let the Fragment with the ListView declare a BroadcastReceiver:
private BroadcastReceiver myReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String sAction = intent.getAction();
if ("com.your_package.name.REFRESH_LIST".equals(sAction) )
{
// update the ListView here
}
}
}
Register the BroadcastReceiver e.g. in onAttach():
IntentFilter myFilter = new IntentFilter();
myFilter.addAction("com.your_package.name.REFRESH_LIST");
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, myFilter);
And don't forget to unregister e.g. in onDetach()
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
This way, the Fragment will get the update messages as long as it is attached to the Activity.
Another option is using some type of Event Bus (greenrobot, Otto...).

Related

Update Data from Broadcast receiver to fragment list view in the background

I'm new to android development, I was making this app that receives messages, onReceive. I want to update those data in the ListView that is in a fragment and the update should happen in the background. Broadcast Receiver is registered globally
#Override
public void onReceive(Context context, Intent intent) {
Hover.initialize(context);
/* IncomingSMSReceiver incomingSMSReceiver = new IncomingSMSReceiver();
incomingSMSReceiver.onReceive(context,intent);*/
String uuid = intent.getStringExtra("response_message");
Log.d(TAG, " " + uuid);
if (intent.hasExtra("transaction_extras")) {
HashMap t_extras = (HashMap) intent.getSerializableExtra("transaction_extras");
/*if (t_extras.containsKey("confirmCode")) {
String confirmationCode = t_extras.get("confirmCode").toString();
Log.d(TAG, " "+confirmationCode);
}*/
if (t_extras.containsKey("Tsh")) {
String balance = t_extras.get("Tsh").toString();
Log.d(TAG," "+balance);
Bundle bundle = new Bundle();
bundle.putString("id", uuid);
bundle.putString("message", balance);
FragmentHistory fragmentHistory = new FragmentHistory();
fragmentHistory.setArguments(bundle);
}
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// return inflater.inflate(R.layout.fragment_history, container,false);
View view = inflater.inflate(R.layout.fragment_history, container, false);
/* mRecyclerView =(RecyclerView) view.findViewById(R.id.recyclerView_history);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.setHasFixedSize(true);
configAdapter();*/
dataSaver.initializeDataSaver(getActivity());
// listScore = view.findViewById(R.id.list);
return view;
}
#Override
public void onActivityCreated( Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//dataSaver.setViewList("Hello", "Hola");
dataSaver.getDataList(this.getActivity());
/*try {
Bundle bundle = getActivity().getIntent().getExtras();
dataSaver.setViewList(bundle.getString("id"), bundle.getString("message"));
} catch (Exception e) {
e.printStackTrace();
}*/
}
#Override
public void onResume() {
super.onResume();
dataSaver.getDataList(this.getActivity());
}
#Override
public void onPause() {
super.onPause();
Bundle arguments = getArguments();
if (arguments != null) {
handleArguments(arguments);
}
Bundle extras = getActivity().getIntent().getExtras();
if (extras != null) {
handleExtras(extras);
}
}
#Override
public void onStop() {
super.onStop();
Bundle arguments = getArguments();
if (arguments != null) {
handleArguments(arguments);
}
Bundle extras = getActivity().getIntent().getExtras();
if (extras != null) {
handleExtras(extras);
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
Bundle arguments = getArguments();
if (arguments != null) {
handleArguments(arguments);
}
Bundle extras = getActivity().getIntent().getExtras();
if (extras != null) {
handleExtras(extras);
}
Toast.makeText(getActivity(), "Destroyed", Toast.LENGTH_LONG).show();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle arguments = getArguments();
}
private void handleArguments(Bundle arguments) {
// TODO
try {
String id =arguments.getString("id");
String message = arguments.getString("message");
dataSaver.setViewList(id, message);
} catch (Exception e) {
e.printStackTrace();
}
}
ListView Adapter
private ArrayList<TransDetails> scores;
TransDetails transDetails;
private MySharedPreference sharedPreference;
private ListView listScore;
private HashSet<String> scoreset;
private Gson gson;
public void initializeDataSaver(Activity activity){
transDetails = new TransDetails();
scores = new ArrayList<>();
gson = new Gson();
sharedPreference = new MySharedPreference(activity);
getHighScoreListFromSharedPreference();
}
/*public void setGson(Gson gson) {
this.gson = gson;
}*/
public Gson getGson() {
return gson;
}
/*public void setActivity(Activity activityf){
activityf = getActivity();
}
public Activity getActivity(){
return getActivity();
}*/
public void getHighScoreListFromSharedPreference() {
//retrieve data from shared preference
String jsonScore = sharedPreference.getHighScoreList();
Type type = new TypeToken<List<TransDetails>>(){}.getType();
scores = gson.fromJson(jsonScore, type);
if (scores == null) {
scores = new ArrayList<>();
}
}
public void saveScoreListToSharedpreference(ArrayList<TransDetails> scoresList) {
//convert ArrayList object to String by Gson
String jsonScore = gson.toJson(scoresList);
//save to shared preference
sharedPreference.saveHighScoreList(jsonScore);
}
public void upDateList(final String id, final String message){
transDetails.setId(id);
transDetails.setId(message);
scores.add(0, transDetails);
}
public void setViewList(String trans_id, String trans_amount){
if (trans_id != null) {
transDetails.setId(trans_id);
transDetails.setMessage(trans_amount);
scores.add(0,transDetails); //add to scores list
saveScoreListToSharedpreference(scores);
}
}
public void getDataList(Activity activity){
listScore = activity.findViewById(R.id.list);
if (scores.size() == 0) {
Toast.makeText(activity, "No data in sharedPreferences", Toast.LENGTH_SHORT).show();
} else {
getHighScoreListFromSharedPreference();
//get data
//set adapter for listview and visible it
ListViewAdapter adapter = new ListViewAdapter(activity, scores);
listScore.setAdapter(adapter);
}
}
Fragments can't work standalone and must be in an activity.
so first step is create an Activity and put your fragment in it.
then you must start that activity with an intent into your broadcast receiver. something like that:
context.startActivity(new Intent(this,ListActivity.class));
the other issue is that when new message receive your startActivity will launch again and create repeatedly. for avoid this issue you must add a flag to your Intent in this way:
context.startActivity(new Intent(this,ListActivity.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));
this flag is for avoid from recreating activity and bring to front existing one.
in this way the intent and data you passed to that will receive in onNewIntent() method of activity and you can handle your data there.
so instead of setArguments in fragment you must start intent with bundle:
context.startActivity(new Intent(this,ListActivity.class).putExtras(bundle).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));

Content Provider fault

In my app I use a content provider. As you know the content provider is the middle man between the client and SQLite. In my case I retrieve the data from a server using volley,store them in SQLite, and finally read them using the ContentResolver object and the LoaderManager interface(which has onCreateLoader,onLoadFinished,onLoaderReset). I also use a service, as I want to run my webservice, when the app is closed.
MyService
public class MyService extends IntentService {
private final String LOG_TAG = MyService.class.getSimpleName();
public MyService() {
super("My Service");
}
#Override
protected void onHandleIntent(Intent intent) {
updateCityList();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void updateCityList() {
cityList.clear();
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
// Request a string response from the provided URL.
JsonArrayRequest jsObjRequest = new JsonArrayRequest(Request.Method.GET,
API.API_URL, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
//hidePD();
// Parse json data.
// Declare the json objects that we need and then for loop through the children array.
// Do the json parse in a try catch block to catch the exceptions
try {
for (int i = 0; i < response.length(); i++) {
JSONObject post = response.getJSONObject(i);
MyCity item = new MyCity();
item.setName(post.getString("title"));
item.setImage(API.IMAGE_URL + post.getString("image"));
ContentValues imageValues = new ContentValues();
imageValues.put(MyCityContract.MyCityEntry._ID, post.getString("id"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_NAME, post.getString("title"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_ICON, post.getString("image"));
getContentResolver().insert(MyCityContract.MyCityEntry.CONTENT_URI, imageValues);
cityList.add(item);
cityList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Update list by notifying the adapter of changes
myCityAdpapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//hidePD();
}
});
queue.add(jsObjRequest);
}
static public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Intent sendIntent = new Intent(context, MyService.class);
context.startService(sendIntent);
}
}
}
MainActivityFragment
public class MainActivityFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{
static public ArrayList<MyCity> cityList;
public String [] MY_CITY_PROJECTIONS = {MyCityContract.MyCityEntry._ID,
MyCityContract.MyCityEntry.COLUMN_NAME,
MyCityContract.MyCityEntry.COLUMN_ICON};
private static final String LOG_TAG =
MainActivityFragment.class.getSimpleName();
public static MyCityAdpapter myCityAdpapter;
private static final int CURSOR_LOADER_ID = 0;
private GridView mGridView;
public MainActivityFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add this line in order for this fragment to handle menu events.
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.refresh, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_refresh) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// inflate fragment_main layout
final View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);
cityList = new ArrayList<>();
// initialize our FlavorAdapter
myCityAdpapter = new MyCityAdpapter(getActivity(), null, 0, CURSOR_LOADER_ID);
// initialize mGridView to the GridView in fragment_main.xml
mGridView = (GridView) rootView.findViewById(R.id.flavors_grid);
// set mGridView adapter to our CursorAdapter
mGridView.setAdapter(myCityAdpapter);
Cursor c =
getActivity().getContentResolver().query(MyCityContract.MyCityEntry.CONTENT_URI,
new String[]{MyCityContract.MyCityEntry._ID},
null,
null,
null);
if (c.getCount() == 0){
updateCityData();
}
// initialize loader
getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
super.onCreate(savedInstanceState);
return rootView;
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args){
return new CursorLoader(getActivity(),
MyCityContract.MyCityEntry.CONTENT_URI,
MY_CITY_PROJECTIONS,
null,
null,
null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
myCityAdpapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader){
myCityAdpapter.swapCursor(null);
}
public void updateCityData() {
Intent alarmIntent = new Intent(getActivity(), MyService.AlarmReceiver.class);
//Wrap in a pending intent which only fires once.
PendingIntent pi = PendingIntent.getBroadcast(getActivity(), 0,alarmIntent,PendingIntent.FLAG_ONE_SHOT);//getBroadcast(context, 0, i, 0);
AlarmManager am=(AlarmManager)getActivity().getSystemService(Context.ALARM_SERVICE);
//Set the AlarmManager to wake up the system.
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 5000, pi);
}
}
I just setup an alarm manager to make my service run after 5 seconds. This is just for testing really. Anyway,here is my problem. When I launch the app for the first time,nothing in shown in my screen. When I exit though,and launch it again,I can see all the images in my gridview. Why is this happening? To make more clear
When I launch the app for the first time:
10-16 12:07:00.799 16685-16685/theo.testing.androidcustomloaders D/ContentValues: [{"id":"15","title":"The Gate of Larissa","image":"larissa17.png"},{"id":"14","title":"Larissa Fair","image":"larissa14.png"},{"id":"13","title":"Larissa Fair","image":"larissa13.png"},{"id":"12","title":"AEL FC Arena","image":"larissa12.png"},{"id":"11","title":"AEL FC Arena","image":"larissa11.png"},{"id":"10","title":"Alcazar Park","image":"larissa10.png"},{"id":"9","title":"Alcazar Park","image":"larissa9.png"},{"id":"8","title":"Church","image":"larissa8.png"},{"id":"7","title":"Church","image":"larissa7.png"},{"id":"6","title":"Old trains","image":"larissa6.png"},{"id":"5","title":"Old trains","image":"larissa5.png"},{"id":"4","title":"Munipality Park","image":"larissa4.png"},{"id":"3","title":"Munipality Park","image":"larissa3.png"},{"id":"2","title":"Ancient Theatre - Larissa","image":"larissa2.png"},{"id":"1","title":"Ancient Theatre - Larissa","image":"larissa1.png"}]
In order to display the data I need to exit the app and launch it again. Why is this happening? Is there something wrong with my code?
LoadManager doesn't handle Your changes in database because it doesn't have any connection to it. You must register observer to handle that stuff.
In Your myCityProvider, in query(...) method is missing method setNotificationUri. It should be set at the end.
Here is modified Your query method:
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Cursor retCursor;
switch (sUriMatcher.match(uri)) {
// All Flavors selected
case MY_CITY: {
retCursor = myCityDbHelper.getReadableDatabase().query(
MyCityContract.MyCityEntry.TABLE_MY_CITY,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;
}
// Individual flavor based on Id selected
case MY_CITY_WITH_ID: {
retCursor = myCityDbHelper.getReadableDatabase().query(
MyCityContract.MyCityEntry.TABLE_MY_CITY,
projection,
MyCityContract.MyCityEntry._ID + " = ?",
new String[]{String.valueOf(ContentUris.parseId(uri))},
null,
null,
sortOrder);
break;
}
default: {
// By default, we assume a bad URI
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
if (retCursor != null) {
retCursor.setNotificationUri(getContext().getContentResolver(), uri);
}
return retCursor;
}
I've checked Your git repo and I think You should fix Your MainActivityFragment. You do everyting in onCreateView but You should do here all stuff related to view or just return inflated view. And after that, You can do the rest in onViewCreated.
You should do In this way:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_main_activity, container, false);
}
#Override
public void onViewCreated(View rootView, #Nullable Bundle savedInstanceState) {
super.onViewCreated(rootView, savedInstanceState);
myCityAdpapter = new MyCityAdpapter(getActivity(), null, 0);
mGridView = (GridView) rootView.findViewById(R.id.flavors_grid);
mGridView.setAdapter(myCityAdpapter);
getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case CURSOR_LOADER_ID:
return new CursorLoader(getActivity(),
MyCityContract.MyCityEntry.CONTENT_URI,
null,
null,
null,
null);
default:
throw new IllegalArgumentException("id not handled!");
}
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case CURSOR_LOADER_ID:
if (data == null || data.getCount() == 0) {
updateCityData();
} else {
myCityAdpapter.swapCursor(data);
}
break;
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
myCityAdpapter.swapCursor(null);
}
Thanks to that:
if app opens, loader will load all what he have (can be 0 items) but if there aren't any items it will call service to download more and store in db
if you add any data by service, onLoadFinished will be called again and refresh adapter

pass string from fragment main activity to fragments activity in viewpager

i wanna pass a string to all fragment(child) from fragment activity (main), may be this picture can explain what exactly what i want to do
https://dl.dropboxusercontent.com/u/57465028/SC20140205-163325.png
so, from above picture...i wanna pass a string from edittext by press a button to all activity in viewpager....how could i do that?
i tried to follow this code https://stackoverflow.com/a/12739968/2003393 but it can't solved my problem..
please help me...i'm stuck
thank in advance.
here is my code from fragment activity (MainActivity)
public class Swipe_Menu extends FragmentActivity {
//String KeyWord;
//private static final String KEYWORD = "keyword";
private ViewPager _mViewPager;
private ViewPagerAdapter _adapter;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.swipe_menu_image);
Button Back = (Button)findViewById(R.id.account);
ImageButton Search = (ImageButton)findViewById(R.id.search);
EditText Keyword = (EditText)findViewById(R.id.keyword);
final String KeyWord = Keyword.getText().toString();
/**
* Back button click event
* */
Back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
finish();
}
});
setUpView();
setTab();
}
protected void sendValueToFragments(String value) {
// it has to be the same name as in the fragment
Intent intent = new Intent("my_package.action.UI_UPDATE");
intent.putExtra("UI_KEY", KeyWord );
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
and here is my fragment (Child Activity)
public class Store_Swipe extends Fragment {
public static final String ACTION_INTENT = "my_package.action.UI_UPDATE";
String KeyWord;
private TextView kata_keyword;
protected BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION_INTENT.equals(intent.getAction())) {
String value = intent.getStringExtra("UI_KEY");
updateUIOnReceiverValue(value);
}
}
};
private void updateUIOnReceiverValue(String value) {
// you probably want this:
KeyWord = value;
}
public static Fragment newInstance(Context context) {
Store_Swipe f = new Store_Swipe();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION_INTENT);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
super.onDestroy();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/*Bundle bundle = this.getArguments();
KeyWord = bundle.getString("keyword");*/
View view = inflater.inflate(R.layout.store_swipe, container, false);
init(view);
return view;
}
void init(View view) {
kata_keyword = (TextView) view.findViewById(R.id.keyword);
//ImageView image = (ImageView) view.findViewById(R.id.image_error);
kata_keyword.setText(KeyWord);
}
}
You don't have access directly to your fragments that reside in ViewPager so you can't reference them directly.
What I am doing in these cases is send a broadcast message from Activity to Fragments. For this reason register a BroadcatReceiver in the fragment (either in onCreate or onCreateView - your decision)m, set a custom action for that receiver (ex. "my_package.actions.internal.BROADCAST_ACTION"), don't forget to unregister the receiver from complementary method.
When you want to send a message from activity, create an intent with above mentioned action, add the string in intent extra and send the broadcast.
In your receiver's onReceive method (within the fragment), get the String from intent paramter and there you have the string.
Makes sense?
EDIT: To provide some code, below are the changes that I would make for fragment:
public class Store_Swipe extends Fragment {
public static final String ACTION_INTENT = "my_package.action.UI_UPDATE";
protected BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(ACTION_INTENT.equals(intent.getAction())) {
String value = intent.getStringExtra("UI_KEY");
updateUIOnReceiverValue(value);
}
}
};
private void updateUIOnReceiverValue(String value) {
// you probably want this:
kata_keyword.setText(value);
}
String KeyWord;
private TextView kata_keyword;
public static Fragment newInstance(Context context) {
Store_Swipe f = new Store_Swipe();
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(ACTION_INTENT);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(receiver);
super.onDestroy();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Bundle bundle = this.getArguments();
KeyWord = bundle.getString("keyword");
View view = inflater.inflate(R.layout.store_swipe, container, false);
init(view);
return view;
}
void init(View view) {
kata_keyword = (TextView) view.findViewById(R.id.keyword);
ImageView image = (ImageView) view.findViewById(R.id.image_error);
kata_keyword.setText(KeyWord);
}
}
And this code I would have from activity, the parameter is the value from EditText:
protected void sendValueToFragments(String value) {
// it has to be the same name as in the fragment
Intent intent = new Intent("my_package.action.UI_UPDATE");
intent.putExtra("UI_KEY", value);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
You would call this from the click listener that you would set in onCreate:
findViewById(R.id.button_id).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String valueThatYouWantToSend = null; /// just the value
sendValueToFragments(valueThatYouWantToSend);
}
});
// I think this solution will solved your issue
// In Main activity put your code -----------------------------------
public void onPageSelected(int position)
{
System.out.println("nilesh");
PageOneFragment f = new PageOneFragment();
f.getText();
PageTwoFragment ff = new PageTwoFragment();
ff.setText();
}
//in General Class ------------------------------------------------
public class General
{
public static String name="";
}
// first Fragment ---------------------------------------------
public void getText()
{
General.name = edittext.getText().toString();
}
// second Fragment ----------------------------------------------
public void setText()
{
System.out.println("name**" + General.name);
tv.setText(General.name);
}

Displaying data from an Intent in a fragment

I have an activity that receives intents and then should display contents of the intents in a nested fragment. My code is the same as the Implement Effective Navigation tutorial which is here with a few modifications detailed below
As in the example the fragments are nested in the main activity with
public static class DummySectionFragment extends Fragment {
....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_section_dummy, container, false);
...
public void updateFragUI() {
if(rootView!=null){
((TextView) rootView.findViewById(R.id.example)).setText(mData.getSomething());
}
I am having difficulties getting an instance of a fragment so that I can update the UI after the MainActivity receives an intent. The code to receive the intent and update the fragment is
public class uiReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
mData = getIntent().getParcelableExtra(ExampleService.EXAMPLE_INTENT);
updateUI(mData);
}
}
public void updateUI() {
DummySectionFragment dummyFrag = (DummySectionFragment)
getSupportFragmentManager().findFragmentById(dummyFragId);
if(dummyFrag==null) {
Log.v(TAG,"Dummy frag is null");
} else {
if(dummyFrag.isVisible()) {
Log.v(TAG,"Dummy frag is visable ");
dummyFrag.updateFragUI();
} else {
Log.v(TAG,"Dummy frag is not visable");
}
}
}
I have tried a number of approaches playing with the variable dummyFragId but I always find dummyFrag is always null. So far I've tried:
Experimenting with tags and ids in the XML code for the fragment. i.e. dummFragId is written as R.id.dummy_fragment_id (or Tag) with a corresponding property in <FrameLayout ...
Getting the fragment tag from the fragment transaction, but this is not done explicitly in the effective navigation code i.e.
getting the fragment id using dummyFragId = dummySectionFragment.getId() i.e.
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
// The first section of the app is the most interesting -- it offers
// a launchpad into the other demonstrations in this example application.
return new LaunchpadSectionFragment();
case 1:
Fragment dummySectionFragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
dummySectionFragment.setArguments(args);
return dummySectionFragment;
Registering a receiver in the fragment. (The receiver is an external class that I cannot update the UI from)
I am open minded to the solution, I just want to know the best way of displaying information from an intent in a fragment.
I think I've found a good solution by creating a register method in the fragment. There is no relevant code in the activity, it's all in the fragment. Hope this helps someone.
public static class DummySectionFragment extends Fragment {
public void updateFragUI() {
Log.v(TAG, "updateFragUI received");
((TextView) getView().findViewById(R.id.example_field))
.setText(Double.toString(mData.getSomething()));
}
private IntentFilter filter = new IntentFilter(
TransmittingService.STATE_UPDATE);
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
mData = intent
.getParcelableExtra(TransmittingService.STATE_VALUES);
updateFragUI();
}
};
#Override
public void onResume() {
super.onResume();
Log.v(TAG, "registering Receiver");
getActivity().registerReceiver(mReceiver, filter);
}
#Override
public void onPause() {
super.onPause();
Log.v(TAG, "unregistering receiver");
getActivity().unregisterReceiver(mReceiver);
}
...
}

keeping a variable value across all android activities

I have a database with one row of data that will be used across a number of activities. I need to be able to keep the row id available in all activites so I can read and write data across different activites with my DB adapter. I have successfully used putExtra (Overthelimit.java) via an intent to pass a row id to the next activity. mRowId variable is then given the row id using getExtra (Profile.java). The problem I now have is making mRowId available to other activities i.e. MyUsual and DrinksList so I can update data as I go.
You can see I have tried putExtras, putSerializable but can't get it to work. I think I am missing some understanding.
So for my profile menu option in the activity below I can send the value of the cursor row id to Profile class:
public class Overthelimit extends ListActivity {
private OverLimitDbAdapter dbHelper;
private Cursor cursor;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.getListView();
dbHelper = new OverLimitDbAdapter(this);
dbHelper.open();
fillData();
registerForContextMenu(getListView());
}
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}
private void fillData() {
cursor = dbHelper.fetchAllUserDrinks();
startManagingCursor(cursor);
//cursor.getCount();
String[] from = new String[] { OverLimitDbAdapter.KEY_USERNAME };
int[] to = new int[] { R.id.label };
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.user_row, cursor, from, to);
setListAdapter(notes);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (dbHelper != null) {
dbHelper.close();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.profile:
Intent myIntent1 = new Intent(this, Profile.class);
if(cursor.getCount() != 0) {
//Toast.makeText(getApplicationContext(), "no profile",Toast.LENGTH_SHORT).show();
myIntent1.putExtra(OverLimitDbAdapter.KEY_ROWID, cursor.getString(cursor.getColumnIndexOrThrow(OverLimitDbAdapter.KEY_ROWID)));
}
startActivityForResult(myIntent1, 0);
return true;
case R.id.myusual:
Intent myIntent2 = new Intent(this, MyUsual.class);
startActivityForResult(myIntent2, 0);
return true;
case R.id.trackme:
Intent myIntent3 = new Intent(this, TrackMe.class);
startActivityForResult(myIntent3, 0);
return true;
case R.id.moreinfo:
Intent myIntent4 = new Intent(this, MoreInfo.class);
startActivityForResult(myIntent4, 0);
return true;
}
return super.onOptionsItemSelected(item);
}
}
Then make it available as mRowId in my Profile activity below:
mRowId = (bundle == null) ? null :
(Long) bundle.getSerializable(OverLimitDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null ? Long.parseLong(extras.getString(OverLimitDbAdapter.KEY_ROWID))
: null;
}
I then need to make this mRowId available to another activity called DrinkList from MyUsual. so I have MyUsual below with a drink1 button onClickListener to try and send the row id to DrinksList:
public class MyUsual extends Activity {
private Long mRowId;
private OverLimitDbAdapter mDbHelper;
private Cursor cursor;
private TextView mDrink1Label;
private TextView mDrink1Units;
/** Called when the activity is first created. */
#Override
public void onCreate(final Bundle bundle) {
super.onCreate(bundle);
mDbHelper = new OverLimitDbAdapter(this);
mDbHelper.open();
setContentView(R.layout.my_usual);
mDrink1Label = (TextView) findViewById(R.id.drink1Label);
mDrink1Units = (TextView) findViewById(R.id.drink1Units);
Button drink1 = (Button) findViewById(R.id.drink1Button);
// get intent data i.e. which drink button pressed and mRowId
mRowId = (bundle == null) ? null :
(Long) bundle.getSerializable(OverLimitDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null ? Long.parseLong(extras.getString(OverLimitDbAdapter.KEY_ROWID))
: null;
}
//populateFields();
drink1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
setResult(RESULT_OK);
//finish();
Intent myIntent1 = new Intent(view.getContext(), DrinksList.class);
myIntent1.putExtra("drinkButton", "drink1");
if(cursor.getCount() != 0) {
myIntent1.putExtra(OverLimitDbAdapter.KEY_ROWID, cursor.getString(cursor.getColumnIndexOrThrow(OverLimitDbAdapter.KEY_ROWID)));
}
startActivityForResult(myIntent1, 0);
}
});
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//saveState();
outState.putSerializable(OverLimitDbAdapter.KEY_ROWID, mRowId);
}
}
From DrinksList I select a drink and I need to use the mRowId write the data to the database via the onListItemclick:
public class DrinksList extends ListActivity {
private ProgressDialog m_ProgressDialog = null;
private ArrayList<CreateDrinkOption> m_drinks = null;
private DrinkAdapter m_adapter;
private Runnable viewDrinks;
private String drinkButton;
private Long mRowId;
private OverLimitDbAdapter mDbHelper;
private String databaseRow;
private Cursor cursor;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.drinks_list);
mDbHelper = new OverLimitDbAdapter(this);
mDbHelper.open();
m_drinks = new ArrayList<CreateDrinkOption>();
this.m_adapter = new DrinkAdapter(this, R.layout.drink_row, m_drinks);
setListAdapter(this.m_adapter);
viewDrinks = new Runnable(){
#Override
public void run() {
getDrinks();
}
};
Thread thread = new Thread(null, viewDrinks, "MagentoBackground");
thread.start();
m_ProgressDialog = ProgressDialog.show(DrinksList.this,
"Please wait...", "Retrieving data ...", true);
// get intent data i.e. which drink button pressed and mRowId
mRowId = (bundle == null) ? null :
(Long) bundle.getSerializable(OverLimitDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
drinkButton = extras.getString(drinkButton);
mRowId = extras != null ? Long.parseLong(extras.getString(OverLimitDbAdapter.KEY_ROWID))
: null;
}
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//saveState();
outState.putSerializable(OverLimitDbAdapter.KEY_ROWID, mRowId);
}
private Runnable returnRes = new Runnable() {
#Override
public void run() {
if(m_drinks != null && m_drinks.size() > 0){
m_adapter.notifyDataSetChanged();
for(int i=0;i<m_drinks.size();i++)
m_adapter.add(m_drinks.get(i));
}
m_ProgressDialog.dismiss();
m_adapter.notifyDataSetChanged();
}
};
#Override
protected void onListItemClick(ListView l, View v, int position, long id)
{
try
{
super.onListItemClick(l, v, position, id);
CreateDrinkOption bkg = (CreateDrinkOption)l.getItemAtPosition(position);
String drink1type = bkg.getDrinkType().toString();
float drink1units = (bkg.getPercentageByVolume() * bkg.getVolume());
//Toast.makeText(this, mRowId.toString(), Toast.LENGTH_LONG).show();
mDbHelper.updateDrink(mRowId, drink1type, drink1units);
finish();
}
catch(Exception ex)
{
Toast.makeText(this, "error", Toast.LENGTH_LONG).show();
}
}
private void getDrinks(){
try{
m_drinks = new ArrayList<CreateDrinkOption>();
CreateDrinkOption o1 = new CreateDrinkOption();
o1.setDrinkType("Beer - 1 pint");
o1.setPercentageByVolume((float) 4.5);
o1.setVolume((float) 0.5);
m_drinks.add(o1);
CreateDrinkOption o2 = new CreateDrinkOption();
o2.setDrinkType("Wine - small glass");
o2.setPercentageByVolume((float) 12);
o2.setVolume((float) 0.125);
m_drinks.add(o2);
CreateDrinkOption o3 = new CreateDrinkOption();
o3.setDrinkType("Spirit - single");
o3.setPercentageByVolume((float) 40);
o3.setVolume((float) 0.25);
m_drinks.add(o3);
CreateDrinkOption o4 = new CreateDrinkOption();
o4.setDrinkType("Alcopop - bottle");
o4.setPercentageByVolume((float) 5);
o4.setVolume((float) 0.275);
m_drinks.add(o4);
Thread.sleep(1000);
Log.i("ARRAY", ""+ m_drinks.size());
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
private class DrinkAdapter extends ArrayAdapter<CreateDrinkOption> {
private ArrayList<CreateDrinkOption> items;
public DrinkAdapter(Context context, int textViewResourceId, ArrayList<CreateDrinkOption> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.drink_row, null);
}
CreateDrinkOption o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.drinkdetail);
TextView bt = (TextView) v.findViewById(R.id.drinkunits);
if (tt != null) {
tt.setText("Type: "+o.getDrinkType());
}
if(bt != null){
bt.setText("Units: "+ String.valueOf(o.getPercentageByVolume() * o.getVolume()));
}
}
return v;
}
}
}
Sorry for the long post, but all I need to do is make this value for mRowId available to all activites so I can read/write data at any point. The data also needs to be there if the app is paused or interupted by say an incoming call, so I use onSaveInstanceState.
ok, thanks. So reply to great answers and I have done this, but it crashes trying to get the data. I have this as my Application class:
public class OverthelimitApplication extends Application {
private Long rowId;
public Long getRowId() {
return rowId;
}
public void setRowId(Long value) {
rowId = value;
}
}
then set value with this:
OverthelimitApplication app1 = (OverthelimitApplication)getApplicationContext();
app1.setRowId((long) cursor.getColumnIndexOrThrow(OverLimitDbAdapter.KEY_ROWID));
then try to get value with this and it crashes:
mRowId = ((OverthelimitApplication) getApplicationContext()).getRowId();
I have fixed it! using this the set and get:
app1.setRowId(Long.parseLong(cursor.getString(cursor.getColumnIndexOrThrow(OverLimitDbAdapter.KEY_ROWID))));
mRowId = (long)((OverthelimitApplication)getApplicationContext()).getRowId();
I still had to specify long when setting and getting. Thanks for all your input.
Another way is to create a application class which is available for all activities.
To do that, you have to extend you Manifest with
<application
..
android:name=".MyApplication" >
and create a new Class
public class MyApplication extends Application {
public int rowId = 0;
}
inside the activities, you can access the rowId by
int mRowId = ((MyApplication) getApplicationContext()).rowId;
There are two options that I think are fit for your purpose:
SharedPreferences: the added benefit is that your variables will kept and available next time you start the application. You can store primitive types easily in shared preferences, like your rowId.
Application: you can subclass the application class, something like MyApplication extends Application, declare in your manifest that you're using this class instead of the default application, and access it using getApplication from all your activities. The added benefit is you can store anything, even a complex data structure in the application, you define the member and access methods in your MyApplication class. For example you could store the whole row of data in your application, not just the rowId)
Personally, I use SharedPreferences to remember settings that I want to be saved for the user, and not having to set them again each time the application is started is nice. And I use application for all the temporary data that I want to live across all activities as long as the application is open.
I'll describe 2 ways.
1) Use a static variable in any one of the Activities. This is the quick, dirty and lazy way. You've been warned.
2) Create your Application class.
Create a Simple class MyApplication that extends Application
In the Android Manifest, there should be a field for Application, make sure you choose your Class.
Typical example.
public class MyApp extends Application
{
private Object myGloballyAccessibleObject; //make getter and setter
private static MyApp singleInstance = null;
public static MyApp getInstance()
{
return singleInstance;
}
#Override
public void onCreate() {
super.onCreate();
singleInstance = this;
}
}
In your activities,
Call this
MyApp myApp = MyApp.getInstance();
myApp.getMyAwesomeObject(); //Booyaah!
You can use the ApplicationContext too. In your Manifest, you should have something like this :
<application
...
android:name="xx.xx.MyApp"
...>
Now, you can access to the Application from any Activity thanks to :
MyApp application = (MyApp)this.getApplicationContext();
You can put your attributes in this class, it'll be accessible anywhere in your app. MyApp must extends Application. See Manifest and
Application
Here you want to get mRowId values from all activity and it is primitive types, So
Either use Shared Preferences for store data or make your member field as a static globally, Then you can use this data in your whole application life cycle..
EDIT: Also you can use Application class as a singleton for your application and create field mRowId in this class and also make getter setter method for this field..

Categories

Resources