When I press the search button for the second time the listview does not update.
When I rotate the phone from a horizontal position to a vertical one the app save the state, but when i rotate the app from a vertical position to a horizontal one it does not.
Can you help me?
MainActivity:
public class MainActivity extends AppCompatActivity implements LoaderCallbacks<List<Book>> {
private static final String LOG_TAG = MainActivity.class.getName();
private static final String GOOGLEBOOK_REQUEST_URL =
"https://www.googleapis.com/books/v1/volumes?q=";
private static final String URL_FIX = "&maxResults=10";
private static final int BOOK_LOADER_ID = 1;
private String googleBookRequest;
private BookAdapter mAdapter;
private ListView listView;
private EditText searchBar;
/** TextView that is displayed when the list is empty */
private TextView mEmptyStateTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list);
mEmptyStateTextView = (TextView) findViewById(R.id.empty_view);
listView.setEmptyView(mEmptyStateTextView);
mAdapter = new BookAdapter(this, new ArrayList<Book>());
final LoaderManager loaderManager = getLoaderManager();
listView.setAdapter(mAdapter);
searchBar = (EditText) findViewById(R.id.search_view);
ImageButton button = (ImageButton) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Get a reference to the ConnectivityManager to check state of network connectivity
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
googleBookRequest="";
// Get details on the currently active default data network
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
// If there is a network connection, fetch data
if (networkInfo != null && networkInfo.isConnected()) {
// Get a reference to the LoaderManager, in order to interact with loaders.
LoaderManager loaderManager = getLoaderManager();
googleBookRequest = createSearchUrl(searchBar);
// Initialize the loader. Pass in the int ID constant defined above and pass in null for
// the bundle. Pass in this activity for the LoaderCallbacks parameter (which is valid
// because this activity implements the LoaderCallbacks interface).
loaderManager.initLoader(BOOK_LOADER_ID, null, MainActivity.this);
} else {
// Otherwise, display error
// First, hide loading indicator so error message will be visible
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
// Update empty state with no connection error message
mEmptyStateTextView.setText(R.string.no_internet_connection);
}
}
});
}
#Override
public Loader<List<Book>> onCreateLoader(int i, Bundle bundle) {
// Create a new loader for the given URL
return new BookLoader(this, googleBookRequest);
}
#Override
public void onLoadFinished(Loader<List<Book>> loader, List<Book> books) {
// Hide loading indicator because the data has been loaded
View loadingIndicator = findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
mAdapter.clear();
if (books != null && !books.isEmpty()) {
mAdapter.addAll(books);
} else{
// Set empty state text to display "No earthquakes found."
mEmptyStateTextView.setText(R.string.no_books);}
}
#Override
public void onLoaderReset(Loader<List<Book>> loader) {
// Loader reset, so we can clear out our existing data.
mAdapter.clear();
}
private String createSearchUrl(EditText editText) {
String search = editText.getText().toString().toLowerCase().trim();;
StringBuilder url = new StringBuilder(GOOGLEBOOK_REQUEST_URL);
return url.append(search.replace(" ", "+")).append(URL_FIX).toString();
}
}
AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.booklistingapp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Related
I have the following code that tells when the phone is connected to EDGE or UMTS network. It works on Android 6 (API 23) but when I test
on Android 7 shows the network type only when I launch the app for first time, but there is no update when the phone changes from 2G to 3G and vice versa.
What is needed in order to make this code works updating the newtwork type in the moment that happens for Android 6 and 7+?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener ConnectionStateListener = new PhoneStateListener() {
#Override
public void onDataConnectionStateChanged(int state, int networkType) {
super.onDataConnectionStateChanged(state, networkType);
String sState = "";
switch (networkType) {
case TelephonyManager.NETWORK_TYPE_EDGE: sState = "EDGE (2G)"; break;
case TelephonyManager.NETWORK_TYPE_UMTS: sState = "UMTS (3G)"; break;
}
Toast.makeText(getApplicationContext(), sState, Toast.LENGTH_SHORT).show();
}
};
telephonyManager.listen(ConnectionStateListener,PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
}
}
I've added to Manifest file the READ_PHONE_STATE permission as shown below.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
As Lucas pointed out this is most likely due to the ConnectionStateListener being garbage collected. You can fix it simply by moving your listener out of the function to make it a class field:
public class MainActivity extends AppCompatActivity {
private PhoneStateListener ConnectionStateListener = new PhoneStateListener() {
#Override
public void onDataConnectionStateChanged(int state, int networkType) {
super.onDataConnectionStateChanged(state, networkType);
String sState = "";
switch (networkType) {
case TelephonyManager.NETWORK_TYPE_EDGE:
sState = "EDGE (2G)";
break;
case TelephonyManager.NETWORK_TYPE_UMTS:
sState = "UMTS (3G)";
break;
}
Toast.makeText(getApplicationContext(), sState, Toast.LENGTH_SHORT).show();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(ConnectionStateListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
}
}
This way you will keep the reference to the PhoneStateListener, preventing it from being garbage collected.
There was a change in PhoneStateListener in Android 7
I think your question is related to this Android Nougat PhoneStateListener is not triggered
You can use ConnectivityManagerCompat. Or you can also use below code
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
String subtype = activeNetwork.getSubtypeName();
if you want to keep observing it then register a dynamic broadcast receiver with intent filter "ConnectivityManager.CONNECTIVITY_ACTION". Please note static receiver might not work post android 6.0
For implementation details
mark this entry in manifest
<receiver
android:name=".receivers.ConnectivityBroadcastReceiver"
android:enabled="#bool/connectivity_change_receiver_enabled"
android:exported="false">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
And make sure that #bool/connectivity_change_receiver_enabled is true for <=6.0 and false for >=7.0
and then for 7.0 use below code in your Applicaiton class
Context.registerReceiver(new ConnectivityBroadcastReceiver(),
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION))
After that you will get all the network related chagnes notified in onReceive of ConnectivityBroadcastReceiver
inside values folder define a bools.xml file with following content
<resources>
<bool name="connectivity_change_receiver_enabled">true</bool>
now create another folder named values-v24 parallel to values with following content
<resources>
<bool name="connectivity_change_receiver_enabled">false</bool>
Now you will be able to use the boolean in manifest and then put the dynamic registration of ConnectivityBroadcastReceiver inside API level check
Full code for ConnectivityBroadcastReceiver:
public class ConnectivityBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "ConnectivityReceiver";
/**
* Informs the service that we have network connectivity.
*
* #param context
* The application context
* #param intent
* An Intent carrying information about the event
*/
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d(TAG, "inside method onReceive::ConnectivityBroadcastReceiver");
// if we are equal to or above API 23 then we can detect if device is in idle mode.
// so we will do nothing if device is in idle mode
if (Build.VERSION.SDK_INT >= 23) {
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if(powerManager.isDeviceIdleMode()) {
// log("returning since device is in idle/doze mode");
Log.d(TAG, "returning since device is in idle/doze mode");
return;
}
}
// Do nothing if this is received right after this broadcast is registered.
if (isInitialStickyBroadcast()) {
Log.d(TAG,"This is a initial sticky broadcast. Do nothing.");
return;
}
// either use conventional method
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
Intent notifyToActivity = new Intent("com.network.state.changed");
String netType = "unknown";
if(connectivityManager!= null) {
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
if(activeNetwork!= null) {
netType = activeNetwork.getSubtypeName();
Toast.makeText(context, "network state is " + netType, Toast.LENGTH_LONG).show();
}
}
notifyToActivity.putExtra("NET_TYPE",netType);
context.sendBroadcast(notifyToActivity);
}
}
Full Code for MainActivity:
ublic class MainActivity extends AppCompatActivity {
TextView textureView;
NetworkStateListener networkStateListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
textureView = (TextView) findViewById(R.id.network_type);
networkStateListener = new NetworkStateListener();
this.registerReceiver(networkStateListener, new IntentFilter("com.network.state.changed"));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
protected void onDestroy() {
super.onDestroy();
if(networkStateListener!= null) {
this.unregisterReceiver(networkStateListener);
}
}
#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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
class NetworkStateListener extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
if(intent!= null){
String type = intent.getExtras().getString("NET_TYPE");
textureView.setText(type);
}
}
}
}
Full Code for NetworkAppClass:
public class NetworkAppClass extends Application {
#Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
this.registerReceiver(new ConnectivityBroadcastReceiver(),
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
}
}
Full code for Manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".NetworkAppClass"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".ConnectivityBroadcastReceiver"
android:enabled="#bool/connectivity_change_receiver_enabled"
android:exported="false">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
</application>
Screenshot to change network dynamically from emulator
I am trying to implement simple quick settings tile with the help of google docs,
but my tile appears to be there but greyed out(intent activity)- I can't click or do anything with it and cant remove it either without restarting my phone(one plus 3T/oreo8.0.0).
and the same thing goes with sample code google provided.
what things do i need to keep in mind/ how to do it?
is there anything I am missing?
I saw one similar question but it was a bit over my head.
MANIFEST
<application
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".QSIntentService"
android:icon="#drawable/ic_android_black_24dp"
android:label="#string/qs_intent_tile_label"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<activity
android:name=".ResultActivity"
android:label="#string/result_label"/>
</application>
JAVA (Main ACtivity)
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
QSintentservice.java
public class QSIntentService extends TileService{
private static final String SERVICE_STATUS_FLAG = "serviceStatus";
private static final String PREFERENCES_KEY = "com.google.android_quick_settings";
#Override
public void onClick() {
updateTile();
boolean isCurrentlyLocked = this.isLocked();
if (!isCurrentlyLocked) {
Resources resources = getApplication().getResources();
Tile tile = getQsTile();
String tileLabel = tile.getLabel().toString();
String tileState = (tile.getState() == Tile.STATE_ACTIVE) ?
resources.getString(R.string.service_active) :
resources.getString(R.string.service_inactive);
Intent intent = new Intent(getApplicationContext(),
ResultActivity.class);
intent.putExtra(ResultActivity.RESULT_ACTIVITY_NAME_KEY,
tileLabel);
intent.putExtra(ResultActivity.RESULT_ACTIVITY_INFO_KEY,
tileState);
startActivityAndCollapse(intent);
}
}
private void updateTile() {
Tile tile = this.getQsTile();
boolean isActive = getServiceStatus();
Icon newIcon;
String newLabel;
int newState;
if (isActive) {
newLabel = String.format(Locale.US,
"%s %s",
getString(R.string.tile_label),
getString(R.string.service_active));
newIcon = Icon.createWithResource(getApplicationContext(), ic_android_black_24dp);
newState = Tile.STATE_ACTIVE;
} else {
newLabel = String.format(Locale.US,
"%s %s",
getString(R.string.tile_label),
getString(R.string.service_inactive));
newIcon =
Icon.createWithResource(getApplicationContext(),
android.R.drawable.ic_dialog_alert);
newState = Tile.STATE_INACTIVE;
}
tile.setLabel(newLabel);
tile.setIcon(newIcon);
tile.setState(newState);
tile.updateTile();
}
private boolean getServiceStatus() {
SharedPreferences prefs =
getApplicationContext()
.getSharedPreferences(PREFERENCES_KEY,
MODE_PRIVATE);
boolean isActive = prefs.getBoolean(SERVICE_STATUS_FLAG, false);
isActive = !isActive;
prefs.edit().putBoolean(SERVICE_STATUS_FLAG, isActive).apply();
return isActive;
}
}
Result.java
public class ResultActivity extends AppCompatActivity {
public static final String RESULT_ACTIVITY_INFO_KEY = "resultActivityInfo";
public static final String RESULT_ACTIVITY_NAME_KEY = "resultActivityName";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
if (getIntent() != null) {
Bundle extras = getIntent().getExtras();
assert extras != null;
String tileState = extras.getString(RESULT_ACTIVITY_INFO_KEY);
String tileName = extras.getString(RESULT_ACTIVITY_NAME_KEY);
TextView outputText = findViewById(R.id.result_info);
outputText.setText(String.format(Locale.US,
getString(R.string.result_output),
tileName,
tileState));
TextView returnHome = findViewById(R.id.result_return_main);
returnHome.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent goHome = new Intent(getApplicationContext(),
MainActivity.class);
startActivity(goHome);
}
});
}
}
}
This code works fine on other devices. However, there is an issue in one plus quick setting menu as its observed and brought to notice. Check the below link to verify,
https://forums.oneplus.net/threads/android-oreo-8-0-oxigenos-quick-settings-bug.690621/
I am trying to implement a spell checker service as described here called SampleSpellCheckerService but it seems the tutorial is incomplete and the source code for it does not seem to be available.
I am struggling with how to get a session from my spell checker service in the setSuggestionsFor() method of my activity, as highlighted here:
public class SpellCheckerSettingsActivity extends AppCompatActivity implements SpellCheckerSession.SpellCheckerSessionListener {
private static final String LOG_TAG = SpellCheckerSettingsActivity.class.getSimpleName();
private TextView textView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spell_checker_settings);
final EditText editText = (EditText)findViewById(R.id.editText);
textView = (TextView)findViewById(R.id.textView);
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fetchSuggestionsFor(editText.getText().toString());
}
});
startService(new Intent(this, SampleSpellCheckerService.class));
}
private void fetchSuggestionsFor(String input){
Log.d(LOG_TAG, "fetchSuggestionsFor(\"" + input + "\")");
/***************************************************
*
* This line is invalid. What do I replace it with?
*
***************************************************/
SpellCheckerSession session = SampleSpellCheckerService.getSession();
TextInfo[] textInfos = new TextInfo[]{ new TextInfo(input) };
int suggestionsLimit = 5;
session.getSentenceSuggestions(textInfos, suggestionsLimit);
}
#Override
public void onGetSuggestions(SuggestionsInfo[] results) {
Log.d(LOG_TAG, "onGetSuggestions(" + results + ")");
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText("Suggestions obtained (TODO - get from results[])");
}
});
}
#Override
public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
Log.d(LOG_TAG, "onGetSentenceSuggestions(" + results + ")");
if (results != null) {
final StringBuffer sb = new StringBuffer("");
for (SentenceSuggestionsInfo result : results) {
int n = result.getSuggestionsCount();
for (int i = 0; i < n; i++) {
int m = result.getSuggestionsInfoAt(i).getSuggestionsCount();
for (int k = 0; k < m; k++) {
sb.append(result.getSuggestionsInfoAt(i).getSuggestionAt(k))
.append("\n");
}
sb.append("\n");
}
}
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(sb.toString());
}
});
}
}
#Override
public void onDestroy() {
stopService(new Intent(this, SampleSpellCheckerService.class));
super.onDestroy();
}
}
So what is the correct way to get a session from SampleSpellCheckerService?
For completeness, here is my spell checker service class:
public class SampleSpellCheckerService extends SpellCheckerService {
public static final String LOG_TAG = SampleSpellCheckerService.class.getSimpleName();
public SampleSpellCheckerService() {
Log.d(LOG_TAG, "SampleSpellCheckerService");
}
#Override
public void onCreate() {
super.onCreate();
Log.d(LOG_TAG, "SampleSpellCheckerService.onCreate");
}
#Override
public Session createSession() {
Log.d(LOG_TAG, "createSession");
return new AndroidSpellCheckerSession();
}
private static class AndroidSpellCheckerSession extends SpellCheckerService.Session {
#Override
public void onCreate() {
Log.d(LOG_TAG, "AndroidSpellCheckerSession.onCreate");
}
#Override
public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) {
Log.d(LOG_TAG, "onGetSentenceSuggestionsMultiple");
SentenceSuggestionsInfo[] suggestionsInfos = null;
//suggestionsInfo = new SuggestionsInfo();
//... // look up suggestions for TextInfo
return suggestionsInfos;
}
#Override
public SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit) {
Log.d(LOG_TAG, "onGetSuggestions");
SuggestionsInfo suggestionsInfo = null;
//suggestionsInfo = new SuggestionsInfo();
//... // look up suggestions for TextInfo
return suggestionsInfo;
}
#Override
public void onCancel() {
Log.d(LOG_TAG, "onCancel");
}
}
}
Here is my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example">
<permission android:name="android.permission.BIND_TEXT_SERVICE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<service
android:name="com.example.SampleSpellCheckerService"
android:label="#string/app_name"
android:enabled="true"
android:permission="android.permission.BIND_TEXT_SERVICE">
<intent-filter>
<action android:name="android.service.textservice.SpellCheckerService" />
</intent-filter>
<meta-data
android:name="android.view.textservice.scs"
android:resource="#xml/spellchecker" />
</service>
<activity android:name="com.example.SpellCheckerSettingsActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
And here is my spellchecker.xml:
<?xml version="1.0" encoding="utf-8"?>
<spell-checker
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/spellchecker_name"
android:settingsActivity="com.example.SpellCheckerSettingsActivity">
<subtype
android:label="#string/subtype_generic"
android:subtypeLocale="en" />
/>
<subtype
android:label="#string/subtype_generic"
android:subtypeLocale="en_GB" />
/>
</spell-checker>
NB - I am testing with a Samsung device.
As far as I can see from the docs and some sample code, there seems to be some misconception of the android Spell Checking API, that result in your error.
As far as I can tell you can't call your service directly since the APIs goal is for you to define a spellchecker that the user has to select from the system settings first. Basically you mixed up the settings activity (that is displayed for service related settings) with a test activity for your service.
Some better tutorials are written in the android dev blog and here, some sample code for a testing client and an rudimentary example service could be found between the mirrored android samples on github.
What you got so far is the sample service (though the linked samples provide some more code to see how the methods could be implemented), you have your spellchecker.xml needed for locale definition and the spellchecker name appearing in the settings, you already have a settings activity (as defined in your spellchecker.xml, but not needed as long as you don't need any preferences) and you have an activity implementing your SpellCheckerSessionListener (although you named it as settings activity).
What you'd still need to do, is go to your settings -> Language & keyboard -> activate Spell checker and choose your spell checker.
To get a session from that spellchecker you can then make a call to the API with
final TextServicesManager tsm = (TextServicesManager) getSystemService(
Context.TEXT_SERVICES_MANAGER_SERVICE);
mScs = tsm.newSpellCheckerSession(null, null, this, true);
as seen in the samples.
Edit:
if you don't need any settings for your service, you can remove the xml attribute from your xml:
android:settingsActivity="com.example.SpellCheckerSettingsActivity"
My program is about calculating calories of some food. This is a practice for CS course. I'm beginner on Android OS and I do not know why my receiving process cannot be completed or shown on Activity.
I just write the relevant code pieces here. I had some items on sqlite database and I can check my items on database with Log.d method and they are okay.
App1:
Manifest:
<receiver android:name="ItemBroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.example.furkan.datagenerator" />
</intent-filter>
</receiver>
Received.class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.received);
ItemBroadcastReceiver br = new ItemBroadcastReceiver();
Cursor cursor = (Cursor) br.receivedItem;
ReceivedItemsAdapter adapter = new ReceivedItemsAdapter(this, cursor);
ListView listView = getListView();
listView.setAdapter(adapter);
}
Adapter:
public class ReceivedItemsAdapter extends CursorAdapter {
public ReceivedItemsAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View retView = inflater.inflate(R.layout.received, parent, false);
return retView;
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
//ImageView icon = (ImageView) view.findViewById(R.id.icon);
TextView name = (TextView) view.findViewById(R.id.name);
TextView cal = (TextView) view.findViewById(R.id.amountCal);
TextView unit = (TextView) view.findViewById(R.id.unit);
unit.setText(" cal");
name.setText(cursor.getString(cursor.getColumnIndex(cursor.getColumnName(1))));
cal.setText(cursor.getString(cursor.getColumnIndex(cursor.getColumnName(2))));
}}
Broadcast Receiver:
public class ItemBroadcastReceiver extends BroadcastReceiver {
Item receivedItem;
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
receivedItem = new Item(bundle.getString("name"),
Integer.parseInt(bundle.getString("calories")),
bundle.getString("category"),
null);
}}
App2:
MainActivity:
public class MainActivity extends AppCompatActivity {
final int DELAY = 60000;
ReceivedItem item;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ReceivedItemsDatabaseHelper dbHelper = new ReceivedItemsDatabaseHelper(this);
item = new ReceivedItem(dbHelper.fetchReceivedItem().getString(
dbHelper.fetchReceivedItem().getColumnIndex(
dbHelper.fetchReceivedItem().getColumnName(1))),
Integer.parseInt(dbHelper.fetchReceivedItem().getString(
dbHelper.fetchReceivedItem().getColumnIndex(
dbHelper.fetchReceivedItem().getColumnName(2)))),
dbHelper.fetchReceivedItem().getString(
dbHelper.fetchReceivedItem().getColumnIndex(
dbHelper.fetchReceivedItem().getColumnName(3))), null);
Thread thread = new Thread() {
public void run() {
synchronized (this) {
try {
Log.d("Response ", item.getName()+", "+item.getCategory()+", "+item.getCalories());
Intent intent = new Intent();
intent.setAction("com.example.furkan.datagenerator");
intent.putExtra("name", item.getName());
intent.putExtra("calories", item.getCalories());
intent.putExtra("category", item.getCategory());
sendBroadcast(intent);
sleep(DELAY);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
thread.start();
}}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.furkan.datagenerator");
ItemBroadcastReceiver br = new ItemBroadcastReceiver();
registerReceiver(br, filter);
You should read about BroadcastReceivers again.
ItemBroadcastReceiver br = new ItemBroadcastReceiver();
Cursor cursor = (Cursor) br.receivedItem;
ReceivedItemsAdapter adapter = new ReceivedItemsAdapter(this, cursor);
ListView listView = getListView();
listView.setAdapter(adapter);
This creates a new instance of the receiver and assigns the receivedItem to cursor. But receivedItem is null and since you never register br for broadcasts, it'll never be not null. Also I'm not sure, if Item could be cast to Cursor.
Considering the code you posted here and the title you used, using BroadcastReceiver might not be a good idea at all. You should try to pass data to Received via intent or load the data directly from persisted storage.
And at last your thread doesn't make any sense.
I have a wearable app that has a couple of fragments created with FragmentGridPagerAdapter. One of the fragments has a couple of CircularButtons and I want to update the backcolor of the button when a message is received from handheld phone. I have no problems in receiving the message. However, button's color (or anything in UI) doesn't update. Do you know how can I fix this?
public class UIPageAdapter extends FragmentGridPagerAdapter {
private final Context mContext;
MainControlFragment[] mainControlFragments;
private List mRows;
uiChangeListener mUIChangeListener = new uiChangeListener();
public UIPageAdapter(Context ctx, FragmentManager fm) {
super(fm);
Log.i("pageAdapter", "constructor");
mContext = ctx;
mainControlFragments = new MainControlFragment[2];
mainControlFragments[0] = new MainControlFragment();
mainControlFragments[1] = new MainControlFragment();
LocalBroadcastManager.getInstance(ctx).registerReceiver(mUIChangeListener,new IntentFilter(Constants.BROADCAST_CONTROL_HOME));
}
#Override
public Fragment getFragment(int row, int col) {
Log.i("PageAdapter","Fragment #" + col +"is asked");
return mainControlFragments[col];
}
public void changeStatus(int button, boolean status) {
mainControlFragments[0].setStatus(button,status);
// notifyDataSetChanged();
}
public class uiChangeListener extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
String act = intent.getAction();
if (act == Constants.BROADCAST_CONTROL_HOME) {
int key = intent.getIntExtra(Constants.CONTROL_HOME_KEY,-1);
String command = intent.getStringExtra(Constants.CONTROL_HOME_COMMAND);
changeStatus(key,command.equals("on"));
}
}
}
#Override
public int getRowCount() {
return 1;
}
#Override
public int getColumnCount(int i) {
return 2;
}
}
Basically when a message received from the handheld device a WearableListener class broadcasts an update message to the UIPageAdapter
This is the listener class
public class ListenerService extends WearableListenerService
{
String tag = "ListenerService";
#Override
public void onMessageReceived(MessageEvent messageEvent) {
final String message = (new String(messageEvent.getData()));
Log.i(tag,message);
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(Constants.BROADCAST_CONTROL_HOME)
.putExtra(Constants.CONTROL_HOME_KEY, messageEvent.getPath())
.putExtra(Constants.CONTROL_HOME_COMMAND,Integer.parseInt(message.substring(1)))
.putExtra("caller",tag));
}
#Override
public void onCreate() {
super.onCreate();
Log.i(tag, "onCreate");
}
}
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="smartstuff.com.tr.myautomationtool" >
<uses-feature android:name="android.hardware.type.watch" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.DeviceDefault" >
<uses-library
android:name="com.google.android.wearable"
android:required="false" />
<service android:name=".ListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.DeviceDefault.Light" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Finally the custom fragment
public class MainControlFragment extends Fragment{
ViewGroup container;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i("controlFragment","create");
this.container = container;
// Inflate the layout for this fragment
return inflater.inflate(R.layout.main_control, container, false);
}
public void setStatus(int button, boolean status) {
Log.i("controlFragment",button + " "+ status);
CircularButton[] btns = new CircularButton[4];
btns[0] = (CircularButton) container.findViewById(R.id.cbtnFront);
btns[1] = (CircularButton) container.findViewById(R.id.cbtnBack);
btns[2] = (CircularButton) container.findViewById(R.id.cbtnBed);
btns[3] = (CircularButton) container.findViewById(R.id.cbtnCoffee);
btns[button].setColor(status?Color.BLACK:Color.RED);
}
}
I also tried the notifyDataSetChanged(); method in UIPageAdapter however it it only calls onCreateView method in fragment. Any help is appreciated
I'm assuming you already resolved this but I had to add a call to invalidate() on the CircularButton after calling setColor():
_circularButton.setColor(ContextCompat.getColor(getActivity(), buttonColor));
_circularButton.invalidate();
Without the call to invalidate the UI only updated some of the time.