I'm working on app that will use biometric as an option to login. Before I use the actual biometric prompt I need to check one thing from server - I use AsyncTask to do it. So, to sum up - I invoke AsyncTask from Parent Activity (login.java), and then AsyncTask uses biometricUtils.java class, that makes biometric prompt. The point is, I keep passing null instead of context to biometricUtils.java:
Attempt to invoke virtual method 'java.util.concurrent.Executor android.content.Context.getMainExecutor()' on a null object reference at biometricUtils.<init>(biometricUtils.java:34)
I have no idea to pass the context correctly.
Here's my code:
login.java
public class login extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
Bundle bundle = getIntent().getExtras();
final boolean flag = false;
final String androidID = bundle.getString("androidID");
final Activity thisActivity = this;
final Context context = getApplicationContext();
// login using biometrics
Button btnBiometricLogin = findViewById(R.id.btnBiometricLogin);
btnBiometricLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkAndroidID async = new checkAndroidID(context);
async.getParentActivity(thisActivity);
async.setFlag(flag);
async.execute(androidID);
}
});
}
}
checkAndroidID.java
public class checkAndroidID extends AsyncTask <String, Void, String> {
openHTTP openHTTP = new openHTTP();
requestHTTP requests = new requestHTTP();
Activity parentActivity;
private WeakReference<Context> contextRef;
Boolean flag;
public checkAndroidID(Context context){
contextRef = new WeakReference<>(context);
}
public void getParentActivity(Activity parentActivity){
this.parentActivity = parentActivity;
}
public void setFlag (Boolean flag){
this.flag = flag;
}
#Override
protected String doInBackground(String... strings) {
try {
HttpURLConnection httpConn = openHTTP.prepareConnection("url");
String json = "{ \"androidID\": \"" + strings[0] + "\" }";
requests.sendData(json, httpConn);
return requests.receiveData(httpConn);
} catch (Exception e){
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s) {
String[] result = s.split(";");
Context ctx = contextRef.get();
if (result[0].equals("TRUE")) flag = true;
if (!flag) Toast.makeText(parentActivity, "Biometric authentication is now unavailable." +
" Please login using username and password", Toast.LENGTH_SHORT).show();
else {
biometricUtils biometrics = new biometricUtils(ctx);
biometrics.getParentActivity(parentActivity);
biometrics.getUsername(result[1]);
biometrics.inovkeBiometricPrompt();
}
super.onPostExecute(s);
}
}
and biometricUtlis.java
public class biometricUtils {
Activity parentActivity;
String username;
Context context;
public void getParentActivity(Activity parentActivity){
this.parentActivity = parentActivity;
}
public void getUsername(String s){
this.username = s;
}
public biometricUtils(Context context){
this.context = context;
}
// creating a variable for our Executor
Executor executor = ContextCompat.getMainExecutor(context); // LINE 34
// this will give us result of AUTHENTICATION
final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) parentActivity, executor, new BiometricPrompt.AuthenticationCallback() {
#Override
public void onAuthenticationError(int errorCode, #NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
}
// THIS METHOD IS CALLED WHEN AUTHENTICATION IS SUCCESS
#Override
public void onAuthenticationSucceeded(#NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
Intent intent = new Intent(parentActivity.getApplicationContext(), tmp.class);
intent.putExtra("username", username);
parentActivity.startActivity(intent);
}
#Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
}
});
// creating a variable for our promptInfo
// BIOMETRIC DIALOG
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder().setTitle("Biometrical login")
.setDescription("Place your fingerprint on scanner to proceed").setNegativeButtonText("Cancel").build();
public void inovkeBiometricPrompt() {
biometricPrompt.authenticate(promptInfo);
}
}
Related
I am trying to update the UI depending on whether the data is being loaded or has loaded but it is not working properly. I am using enum class for different states.
Initially the error was
Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' on a null object reference
Then I passed an empty new MutableLiveData()<>. Now, it doesn't crashes the application, however, the getDataStatus() observer isn't working correctly. Kindly look at my implementations and see if they are right.
DataSource
public class ArticlesDataSource extends PageKeyedDataSource<Integer, NewsItem> {
private static final int FIRST_PAGE = 1;
private static final String TAG = "ArticlesDataSource";
public static final String SORT_ORDER = "publishedAt";
public static final String LANGUAGE = "en";
public static final String API_KEY = Utils.API_KEY;
public static final int PAGE_SIZE = 10;
private String mKeyword;
private MutableLiveData<DataStatus> dataStatusMutableLiveData = new MutableLiveData<>();
public ArticlesDataSource(String keyword) {
mKeyword = keyword;
dataStatusMutableLiveData = new MutableLiveData<>();
}
public MutableLiveData<DataStatus> getDataStatusMutableLiveData() {
return dataStatusMutableLiveData;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull LoadInitialCallback<Integer, NewsItem> callback) {
dataStatusMutableLiveData.postValue(DataStatus.LOADING);
NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, FIRST_PAGE, PAGE_SIZE);
call.enqueue(new Callback<RootJsonData>() {
#Override
public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
if (response.body() != null) {
callback.onResult(response.body().getNewsItems(), null, FIRST_PAGE + 1);
dataStatusMutableLiveData.postValue(DataStatus.LOADED);
}
}
#Override
public void onFailure(Call<RootJsonData> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
dataStatusMutableLiveData.postValue(DataStatus.ERROR);
}
});
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, NewsItem> callback) {
NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, FIRST_PAGE, PAGE_SIZE);
call.enqueue(new Callback<RootJsonData>() {
#Override
public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
// if the current page is greater than one
// we are decrementing the page number
// else there is no previous page
Integer adjacentKey = (params.key > 1) ? params.key - 1 : null;
if (response.body() != null) {
// passing the loaded data
// and the previous page key
callback.onResult(response.body().getNewsItems(), adjacentKey);
}
}
#Override
public void onFailure(Call<RootJsonData> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
}
});
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, NewsItem> callback) {
NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, params.key, PAGE_SIZE);
call.enqueue(new Callback<RootJsonData>() {
#Override
public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
dataStatusMutableLiveData.postValue(DataStatus.LOADED);
if (response.code() == 429) {
// no more results
List<NewsItem> emptyList = new ArrayList<>();
callback.onResult(emptyList, null);
}
if (response.body() != null) {
// if the response has next page
// incrementing the next page number
Integer key = params.key + 1;
// passing the loaded data and next page value
if (!response.body().getNewsItems().isEmpty()) {
callback.onResult(response.body().getNewsItems(), key);
}
}
}
#Override
public void onFailure(Call<RootJsonData> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
dataStatusMutableLiveData.postValue(DataStatus.ERROR);
}
});
}
}
DataSourceFactory
public class ArticlesDataSourceFactory extends DataSource.Factory {
private final MutableLiveData<ArticlesDataSource> itemLiveDataSource;
private String mQuery;
private final LiveData<DataStatus> dataStatusLiveData = Transformations.switchMap(itemLiveDataSource, (itemDataSource) -> {
return itemDataSource.getDataStatusMutableLiveData();
});
public ArticlesDataSourceFactory() {
mQuery = "news";
itemLiveDataSource = new MutableLiveData<>();
}
#Override
public DataSource<Integer, NewsItem> create() {
ArticlesDataSource itemDataSource = new ArticlesDataSource(mQuery);
itemLiveDataSource.postValue(itemDataSource);
// dataStatusMutableLiveData = itemDataSource.getDataStatusMutableLiveData();
return itemDataSource;
}
public MutableLiveData<ArticlesDataSource> getArticlesLiveDataSource() {
return itemLiveDataSource;
}
public void setQuery(String query) {
mQuery = query;
}
public MutableLiveData<DataStatus> getDataStatusMutableLiveData() {
return dataStatusMutableLiveData;
}
public void setDataStatusMutableLiveData(DataStatus dataStatus){
dataStatusMutableLiveData.postValue(dataStatus);
}
public LiveData<DataStatus> getDataStatusLiveData() {
return dataStatusLiveData;
}
}
ViewModel
public class ArticlesViewModel extends ViewModel {
public LiveData<PagedList<NewsItem>> itemPagedList;
private MutableLiveData<ArticlesDataSource> liveDataSource;
private ArticlesDataSourceFactory articlesDataSourceFactory;
private LiveData dataStatus = new MutableLiveData<>();
public ArticlesViewModel() {
articlesDataSourceFactory = new ArticlesDataSourceFactory();
liveDataSource = articlesDataSourceFactory.getArticlesLiveDataSource();
dataStatus = articlesDataSourceFactory.getDataStatusMutableLiveData();
PagedList.Config pagedListConfig =
(new PagedList.Config.Builder())
.setEnablePlaceholders(false)
.setPageSize(10).build();
itemPagedList = (new LivePagedListBuilder(articlesDataSourceFactory, pagedListConfig)).build();
}
public void setKeyword(String query) {
if (query.equals("") || query.length() == 0)
articlesDataSourceFactory.setDataStatusMutableLiveData(DataStatus.EMPTY);
else {
articlesDataSourceFactory.setQuery(query);
refreshData();
}
}
void refreshData() {
if (itemPagedList.getValue() != null) {
itemPagedList.getValue().getDataSource().invalidate();
}
}
public LiveData<DataStatus> getDataStatus() {
return dataStatus;
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_articles, container, false);
mContext = getActivity();
progressBar = rootView.findViewById(R.id.progress_circular);
emptyStateTextView = rootView.findViewById(R.id.empty_view);
swipeRefreshLayout = rootView.findViewById(R.id.swipe_refresh);
textViewTitle = rootView.findViewById(R.id.text_view_top_headlines);
recyclerView = rootView.findViewById(R.id.recycler_view);
if (savedInstanceState != null) {
keyword = savedInstanceState.getString("keyword");
}
initEmptyRecyclerView();
articlesViewModel = ViewModelProviders.of(this).get(ArticlesViewModel.class);
articlesViewModel.itemPagedList.observe(getViewLifecycleOwner(), new Observer<PagedList<NewsItem>>() {
#Override
public void onChanged(PagedList<NewsItem> newsItems) {
adapter.submitList(newsItems);
// TODO: Handle UI changes
// handleUIChanges(newsItems);
}
});
articlesViewModel.getDataStatus().observe(getViewLifecycleOwner(), new Observer<DataStatus>() {
#Override
public void onChanged(DataStatus dataStatus) {
switch (dataStatus) {
case LOADED:
progressBar.setVisibility(View.GONE);
emptyStateTextView.setVisibility(View.INVISIBLE);
swipeRefreshLayout.setRefreshing(false);
textViewTitle.setVisibility(View.VISIBLE);
break;
case LOADING:
progressBar.setVisibility(View.VISIBLE);
swipeRefreshLayout.setRefreshing(true);
textViewTitle.setVisibility(View.INVISIBLE);
emptyStateTextView.setVisibility(View.INVISIBLE);
break;
case EMPTY:
progressBar.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
textViewTitle.setVisibility(View.INVISIBLE);
emptyStateTextView.setVisibility(View.VISIBLE);
emptyStateTextView.setText(R.string.no_news_found);
break;
case ERROR:
progressBar.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
textViewTitle.setVisibility(View.INVISIBLE);
emptyStateTextView.setVisibility(View.VISIBLE);
emptyStateTextView.setText(R.string.no_internet_connection);
break;
}
}
});
swipeRefreshLayout.setOnRefreshListener(() -> {
articlesViewModel.setKeyword(keyword);
});
setHasOptionsMenu(true);
return rootView;
}
DataStatus
public enum DataStatus {
ERROR,
LOADING,
LOADED,
EMPTY
}
When you call invalidate(), a new datasource will be created by the factory. However, you are directly exposing the data status liveData of the "current" created datasource, without taking into consideration that more will be created in the future.
The solution is to store the current data source in the factory in a MutableLiveData, and expose the "most recent current data status" using switchMap.
public class ArticlesDataSourceFactory extends DataSource.Factory {
private final MutableLiveData<ArticlesDataSource> itemLiveDataSource = new MutableLiveData<>();
private String mQuery = "news";
private final LiveData<DataStatus> dataStatusLiveData = Transformations.switchMap(itemLiveDataSource, (itemDataSource) -> {
return itemDataSource.getDataStatusMutableLiveData();
});
public ArticlesDataSourceFactory() {
}
#Override
public DataSource<Integer, NewsItem> create() {
ArticlesDataSource itemDataSource = new ArticlesDataSource(mQuery);
itemLiveDataSource.postValue(itemDataSource);
...
public LiveData<DataStatus> getDataStatusLiveData() {
return dataStatusLiveData;
}
In my app, I use a Contacts database and display those contacts using a RecyclerView . When I click on a contact, I want to fetch its data from the tables in the DB, and load them in a new Activity, ContactCard. I have an AsyncTask() which fetches the PhoneNumber objects that match the selected contactId, but I will also need to retrieve the Address and Email objects from the other tables.
I would like to be able to start the activity after all the relevant data is fetched, and I tried doing this in the activity with the Contacts RecyclerView, but the application crashes as the data has not been fetched yet.
I can call the new activity using an intent, but how can I ensure data from different tables is fetched first, before I start the new activity (which effectively displays this data)?
Some of my code:
public class PhoneNumberRepository {
private WorksideDatabase worksideDatabase;
private List<PhoneNumber> returnedNumbers;
private Context mContext;
public PhoneNumberRepository(Context context) {
String DB_NAME = "workside_database";
worksideDatabase = Room.databaseBuilder(context, WorksideDatabase.class, DB_NAME).build();
mContext = context;
}
public List<PhoneNumber> fetchPhoneNumbers(final int id) {
new AsyncTask<Integer, Void, List<PhoneNumber>>() {
#Override
protected List<PhoneNumber> doInBackground(Integer... ids) {
returnedNumbers = worksideDatabase.phoneNumberDao().getPhoneNumbersById(id);
System.out.println(returnedNumbers);
for (PhoneNumber pn : returnedNumbers) {
System.out.println("Number: " + pn.getPhoneNumber());
}
return returnedNumbers;
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(List<PhoneNumber> result) {
super.onPostExecute(result);
System.out.println("Entered onPostExecute of fetchPhoneNumbers");
// for (PhoneNumber pn : result) {
// Toast.makeText(mContext, pn + "", Toast.LENGTH_SHORT).show();
// }
}
}.execute();
return returnedNumbers;
}
public List<PhoneNumber> getPhoneNumbers(int id) {
return fetchPhoneNumbers(id);
}
}
ContactsFragment:
adapter.setOnItemClickListener(
contact -> {
Intent viewContact = new Intent(getActivity(), WorksideContactCard.class);
viewContact.putExtra(WORKSIDE_CONTACT, contact);
PhoneNumberRepository phoneNumberRepository =
new PhoneNumberRepository(getActivity().getApplicationContext());
List<PhoneNumber> phoneNumberList;
phoneNumberList = phoneNumberRepository.getPhoneNumbers(contact.getId());
ArrayList<PhoneNumber> arrlistPhoneNumbers =
new ArrayList<>(phoneNumberList);
viewContact.putParcelableArrayListExtra(
WORKSIDE_CONTACT_PHONE_NO, arrlistPhoneNumbers);
startActivity(viewContact);
}
You can do this when you click on an item start the asyntask like this
adapter.setOnItemClickListener(
contact -> {
PhoneNumberRepository phoneNumberRepository =
new PhoneNumberRepository(getActivity().getApplicationContext());
List<PhoneNumber> phoneNumberList;
phoneNumberRepository.getPhoneNumbers(contact.getId());
}
and change your PhoneNumberRepository to this class
public class PhoneNumberRepository {
private WorksideDatabase worksideDatabase;
private List<PhoneNumber> returnedNumbers;
private Context mContext;
public PhoneNumberRepository(Context context) {
String DB_NAME = "workside_database";
worksideDatabase = Room.databaseBuilder(context, WorksideDatabase.class, DB_NAME).build();
mContext = context;
}
public void fetchPhoneNumbers(final int id) {
new AsyncTask<Integer, Void, List<PhoneNumber>>() {
#Override
protected List<PhoneNumber> doInBackground(Integer... ids) {
returnedNumbers = worksideDatabase.phoneNumberDao().getPhoneNumbersById(id);
System.out.println(returnedNumbers);
for (PhoneNumber pn : returnedNumbers) {
System.out.println("Number: " + pn.getPhoneNumber());
}
return returnedNumbers;
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(List<PhoneNumber> result) {
super.onPostExecute(result);
Intent viewContact = new Intent(context, WorksideContactCard.class);
ArrayList<PhoneNumber> arrlistPhoneNumbers =
new ArrayList<>(result);
viewContact.putParcelableArrayListExtra(
WORKSIDE_CONTACT_PHONE_NO, arrlistPhoneNumbers);
context.startActivity(viewContact);
System.out.println("Entered onPostExecute of fetchPhoneNumbers");
}
}.execute();
}
public void getPhoneNumbers(int id) {
return fetchPhoneNumbers(id);
}
}
store the contacts in a list in the doInBackground() method and start an intent to the new activity in the onPostExecute() method and with this intent pass the list of contacts as intent.extra() variables, retrieve and use them in the called activity.
Change your repository class to something like this
public class PhoneNumberRepository {
private WorksideDatabase worksideDatabase;
private List<PhoneNumber> returnedNumbers;
private Context mContext;
private boolean dataDownloaded;
public PhoneNumberRepository(Context context) {
String DB_NAME = "workside_database";
worksideDatabase = Room.databaseBuilder(context, WorksideDatabase.class, DB_NAME).build();
mContext = context;
}
public List<PhoneNumber> fetchPhoneNumbers(final int id) {
new AsyncTask<Integer, Void, List<PhoneNumber>>() {
#Override
protected List<PhoneNumber> doInBackground(Integer... ids) {
returnedNumbers = worksideDatabase.phoneNumberDao().getPhoneNumbersById(id);
System.out.println(returnedNumbers);
for (PhoneNumber pn : returnedNumbers) {
System.out.println("Number: " + pn.getPhoneNumber());
}
return returnedNumbers;
}
// This runs in UI when background thread finishes
#Override
protected void onPreExecute(List<PhoneNumber> result) {
//set flag to false when download starts
dataDownloaded = false;
}
// This runs in UI when background thread finishes
#Override
protected void onPostExecute(Object obj) {
super.onPostExecute(result);
//set flag to true once download completes, you can also check if response is null and update it accordingly
dataDownloaded = true;
System.out.println("Entered onPostExecute of fetchPhoneNumbers");
// for (PhoneNumber pn : result) {
// Toast.makeText(mContext, pn + "", Toast.LENGTH_SHORT).show();
// }
}
}.execute();
return returnedNumbers;
}
public List<PhoneNumber> getPhoneNumbers(int id) {
return fetchPhoneNumbers(id);
}
public boolean isDataDownloaded(int id) {
return dataDownloaded;
}
}
Use this function in onItemClick() whether your data is downloaded or not
if(phoneNumberRepository.isDataDownloaded()) {
//code to fetch data from phonenumberrepo and start activity
}
I'm new to Android programming, and I'd like to create a central database service class which will take care of user data exchange with an external database. For this, I created a service which is started after successful login. I created another class that extends AsyncTask to do the data retrieval.
Now, I wanted the methods for the data retrieval to be stored in the service. I would fire intents to the service from different activities, and with .setAction() I would determine which method to call, or which data to retrieve.
I also created an interface class for handling the AsyncTask results.
Now, from this question I thought that it would be possible to have multiple listeners to one and the same AsyncTask result. But now this seems impossible to achieve: I'd like to retrieve the AsyncTask results in the MainMenuActivity, but I can't create an instance of AsyncUserData there as a delegate for the UserData class. In my example below, the missing piece is a valid instance of AsyncUserData for the UserData class to work with. How could I do it?
Here's the example:
MainMenuActivity
public class MainMenuActivity extends ActionBarActivity implements AsyncUserData {
TextView tvUsername;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
tvUsername =
(TextView) findViewById(R.id.tvUsername);
TelephonyManager tManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
String uid = tManager.getDeviceId();
getDataFromUserSessionService(this, uid);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void retrieveResult(String result) throws JSONException {
JSONObject jsonObject = new JSONObject(result);
String joName;
joName = jsonObject.getJSONObject("name").toString();
user.setName(joName);
tvUsername.setText(joName);
}
public void getDataFromUserSessionService(Context context, String uid) {
Intent intent = new Intent(context, UserSession.class);
intent.setAction(UserSession.ACTION_FETCH_USER_DATA);
intent.putExtra(UserSession.UID, uid);
context.startService(intent);
}
UserSession Service
public class UserSession extends IntentService {
public static final String ACTION_FETCH_USER_DATA = "com.example.blahblah.services.action.read_user_data";
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
utils = new Utils(this);
final String action = intent.getAction();
uid = intent.getStringExtra(UID);
if (ACTION_FETCH_USER_DATA.equals(action)) {
handleUserDataFetch(uid);
}
}
}
private void handleUserDataFetch(String uid) {
String[] parameters = new String[2];
parameters[0] = uid;
parameters[1] = Constants.USER_DATA_FETCH;
UserData userData = new UserData(this);
userData.execute(parameters);
}
UserData AsyncTask Class (the Utils class just has another post method):
public class UserData extends AsyncTask < String, Void, String > {
public AsyncUserData delegate = null;
private Context myContext;
public UserData(Context context) {
myContext = context;
}
#Override
protected String doInBackground(String...params) {
String serverResponse = "";
String uid = params[0];
Utils utils = new Utils(myContext);
String phpName = params[1];
List < NameValuePair > nameValuePairs = new ArrayList < NameValuePair > ();
nameValuePairs.add(new BasicNameValuePair("uid", uid));
try {
serverResponse = utils.passDataToServer(phpName, nameValuePairs);
} catch (IOException e) {
e.printStackTrace();
}
return serverResponse;
}
protected void onPostExecute(String result) {
try {
delegate.retrieveResult(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
};
And the AsyncUserData interface:
public interface AsyncUserData {
void retrieveResult(String result) throws JSONException;
}
You can use a Singleton that stores a reference to the activity
public class ServiceToActivity
{
public ActionBarActivity mainactivity = null;
private static ServiceToActivity singleton = null;
public Class<?> cl = null;
private ServiceToActivity()
{
}
public static ActionBarActivity getSingleton()
{
if(singleton==null)
return null;
return singleton.mainactivity;
}
public static Class<?> getSingletonClass()
{
if(singleton==null)
return null;
return singleton.cl;
}
public static void setSingleton(ActionBarActivity mainactivity, Class<?> cl)
{
if(singleton==null)
singleton = new ServiceToActivity();
singleton.mainactivity = mainactivity;
singleton.cl = cl;
}
}
Then create the singleton before the service is started
public void getDataFromUserSessionService(Context context, String uid) {
Intent intent = new Intent(context, UserSession.class);
intent.setAction(UserSession.ACTION_FETCH_USER_DATA);
intent.putExtra(UserSession.UID, uid);
ServiceToActivity.setSingleton(this,this.getClass()); //create Singleton to store a reference to the activity
context.startService(intent);
}
In UserData retrieve data to the main activity by:
protected void onPostExecute(String result) {
try {
Class<?> cl = ServiceToActivity.getSingletonClass();
Method met = cl.getMethod("retrieveResult", String); //String because result is of type String: you can use result.getClass() instead
met.invoke(cl.cast(ServiceToActivity.getSingleton()), result); // compare it to this ServiceToActivity.getSingleton().retrieveResult(result);
} catch (JSONException e) {
e.printStackTrace();
}
}
It sounds like you might want to use an event bus such as otto
Hi I'm quite new to Java, I wonder how to call a void method from another activity, when I already moved to new activity. For example, I want to call
onCreate(Bundle state)
from PocketSphinxActivty.java
in my new activity SMSReaderMain.java
I already tried
PocketSphinxActivity ps = new PocketSphinxActivity();
ps.onCreate(null);
It gives no error, but when SMSReaderMain.java activity start it suddenly force close and not responding in the actual device.
I also try to change into ps.onCreate(this) or ps.onCreate(SMSReaderMain.this) but it gives
The method setupRecognizer(File) in the type PocketSphinxActivity is not applicable for the arguments
(SMSReaderMain)
Here's the complete code, and I want to call almost all of method there in my new activity SMSReaderMain.java
PocketSphinxActivity.java
package edu.cmu.pocketsphinx.demo;
public class PocketSphinxActivity extends Activity implements
RecognitionListener {
//keyword yang digunakan dalem program untuk set ke even2 tertentu
private static final String KWS_SEARCH = "wakeup";
private static final String FORECAST_SEARCH = "forecast";
private static final String DIGITS_SEARCH = "drive mode";
private static final String MENU_SEARCH = "menu";
private static final String KEYPHRASE = "ok";
private SpeechRecognizer recognizer;
private HashMap<String, Integer> captions;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
// Buat nyiapin User Interface
captions = new HashMap<String, Integer>();
captions.put(KWS_SEARCH, R.string.kws_caption);
captions.put(MENU_SEARCH, R.string.menu_caption);
//captions.put(DIGITS_SEARCH, R.string.digits_caption);
captions.put(FORECAST_SEARCH, R.string.forecast_caption);
setContentView(R.layout.main);
((TextView) findViewById(R.id.caption_text))
.setText("Preparing the recognizer");
// Recognizer initialization is a time-consuming and it involves IO,
// so we execute it in async task
new AsyncTask<Void, Void, Exception>() {
#Override
protected Exception doInBackground(Void... params) {
try {
Assets assets = new Assets(PocketSphinxActivity.this);
File assetDir = assets.syncAssets();
setupRecognizer(assetDir);
} catch (IOException e) {
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception result) {
if (result != null) {
((TextView) findViewById(R.id.caption_text))
.setText("Failed to init recognizer " + result);
} else {
switchSearch(KWS_SEARCH);
}
}
}.execute();
}
//nyocokin keyword dan pindah2 menu
#Override
public void onPartialResult(Hypothesis hypothesis) {
String text = hypothesis.getHypstr();
try {
Intent i= null;
if (text.equals(KEYPHRASE)) {
switchSearch(MENU_SEARCH);
}
if (text.equals(DIGITS_SEARCH)) {
//panggil class SMSReaderMain
recognizer.stop();
i = new Intent(getApplicationContext(),SMSReaderMain.class);
startActivity(i);
}
if (text.equals(FORECAST_SEARCH)) {
switchSearch(FORECAST_SEARCH);
}
//else
//((TextView) findViewById(R.id.result_text)).setText(text);
} catch (Exception e) {
e.printStackTrace();
}
}
//nge pop up keyword yang sesuai kita ucapin sama library yg udah ada
#Override
public void onResult(Hypothesis hypothesis) {
((TextView) findViewById(R.id.result_text)).setText("");
if (hypothesis != null) {
String text = hypothesis.getHypstr();
makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
}
#Override
public void onBeginningOfSpeech() {
}
//kembali ke menu utama
/*#Override
public void onEndOfSpeech() {
if (DIGITS_SEARCH.equals(recognizer.getSearchName())
|| FORECAST_SEARCH.equals(recognizer.getSearchName()))
switchSearch(KWS_SEARCH);
}**/
//nampilin caption yg di mau sesuai dengan keyword
public void switchSearch(String searchName) {
recognizer.stop();
recognizer.startListening(searchName);
String caption = getResources().getString(captions.get(searchName));
((TextView) findViewById(R.id.caption_text)).setText(caption);
}
//inisiasi recognizer di awal
public void setupRecognizer(File assetsDir) {
File modelsDir = new File(assetsDir, "models");
recognizer = defaultSetup()
.setAcousticModel(new File(modelsDir, "hmm/en-us-semi"))
.setDictionary(new File(modelsDir, "dict/cmu07a.dic"))
.setRawLogDir(assetsDir).setKeywordThreshold(1e-20f)
.getRecognizer();
recognizer.addListener(this);
// Create keyword-activation search.
recognizer.addKeyphraseSearch(KWS_SEARCH, KEYPHRASE);
// Create grammar-based searches.
File menuGrammar = new File(modelsDir, "grammar/mulai.gram");
recognizer.addGrammarSearch(MENU_SEARCH, menuGrammar);
//File digitsGrammar = new File(modelsDir, "grammar/digits.gram");
//recognizer.addGrammarSearch(DIGITS_SEARCH, digitsGrammar);
// Create language model search.
File languageModel = new File(modelsDir, "lm/weather.dmp");
recognizer.addNgramSearch(FORECAST_SEARCH, languageModel);
}
#Override
public void onEndOfSpeech() {
// TODO Auto-generated method stub
}
}
SMSReaderMAin.java
public class SMSReaderMain extends Activity {
private final int CHECK_CODE = 0x1;
private final int LONG_DURATION = 5000;
private final int SHORT_DURATION = 1200;
private Speaker speaker;
private ToggleButton toggle;
private OnCheckedChangeListener toggleListener;
private TextView smsText;
private TextView smsSender;
private BroadcastReceiver smsReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//PocketSphinxActivity ps = new PocketSphinxActivity();
//ps.setupRecognizer(null);
//ps.onPartialResult(null);
//ps.onResult(null);
//ps.switchSearch(null);
setContentView(R.layout.main_sms);
//recognizer.startListening(searchName);
toggle = (ToggleButton)findViewById(R.id.speechToggle);
smsText = (TextView)findViewById(R.id.sms_text);
smsSender = (TextView)findViewById(R.id.sms_sender);
toggleListener = new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) {
if(isChecked){
speaker.allow(true);
speaker.speak(getString(R.string.start_speaking));
}else{
speaker.speak(getString(R.string.stop_speaking));
speaker.allow(false);
}
}
};
toggle.setOnCheckedChangeListener(toggleListener);
checkTTS();
initializeSMSReceiver();
registerSMSReceiver();
}
private void checkTTS(){
Intent check = new Intent();
check.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(check, CHECK_CODE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == CHECK_CODE){
if(resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS){
speaker = new Speaker(this);
}else {
Intent install = new Intent();
install.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(install);
}
}
}
private void initializeSMSReceiver(){
smsReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if(bundle!=null){
Object[] pdus = (Object[])bundle.get("pdus");
for(int i=0;i<pdus.length;i++){
byte[] pdu = (byte[])pdus[i];
SmsMessage message = SmsMessage.createFromPdu(pdu);
String text = message.getDisplayMessageBody();
String sender = getContactName(message.getOriginatingAddress());
speaker.pause(LONG_DURATION);
speaker.speak("You have a new message from" + sender + "!");
speaker.pause(SHORT_DURATION);
speaker.speak(text);
smsSender.setText("Message from " + sender);
smsText.setText(text);
}
}
}
};
}
private void registerSMSReceiver() {
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(smsReceiver, intentFilter);
}
private String getContactName(String phone){
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phone));
String projection[] = new String[]{ContactsContract.Data.DISPLAY_NAME};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if(cursor.moveToFirst()){
return cursor.getString(0);
}else {
return "unknown number";
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(smsReceiver);
speaker.destroy();
}
}
This is a really wrong approach to the way of programming in Android. Activities are one of the main core components in an Android application that is managed directly by the OS, which means that the system creates them and are managed by the OS. The onCreate method is part of the lifecycle and it is automatically called by the system. Here you have the activity's lifecycle.
The way of starting a new activity is:
Intent intent = new Intent(mContext, MyActivity.class);
startActivity(intent);
As the activity is instanciated by the system, you cannot call directly to methods on it. The way of communicating between activities is by providing bundle objects in the intent, so in the new Activity you can get the data from:
getIntent().getExtras()
You can also provide backward information by using startActivityForResult instead of startActivity, receiving a result in onActivityResult.
You have the info you need here.
Activity corresponds to something you are going to display on screen. If you are not going to display anything, don't create activities.
In this example you do not need PocketsphinxActivity at all. You can move all the methods of PocketsphinxActivity into your SMSReaderMain activity.
If you want to separate speech recognition code into separate class you can create a separate PocketsphinxRecognizer class but inherit it from Object, not from the Activity.
I am trying to display a progress dialog in java 'A'. At the moment that am calling from 'A' a class from java 'B' which the certain java it download data from a webservice and save the data to a file. The progress dialog it does not show. The code I am using is:
ProgressDlg= ProgressDialog.show(Doctor.this, "","Loading. Please wait...", true);
String time_batch=mDataIntent.getExtras().getString("TIME_BATCH");
String patientid=mDataIntent.getExtras().getString("PatientId")
mGetHeartRate = new GetHeartRate(Doctor.this, mHandler);
mgetEcgAnalized = new getEcgAnalized(Doctor.this, mHandler);
mGetHeartRate.getHeart(patientid,time_batch);
mgetEcgAnalized.getECG(patientid, time_batch, "I".toString());
ProgressDlg.dismiss();
Are you executing the ProgressDialog in a AsyncTask? Something like this:
public class ExampleTask extends AsyncTask<String, Integer, String> {
private ProgressDialog progressDlg;
private Context context;
private Handler progressHandler;
public ExampleTask(Context context) {
this.context = context;
}
#Override
protected void onPreExecute() {
progressHandler = new Handler();
}
#Override
protected String doInBackground(String... params) {
//to do
}
#Override
protected void onPostExecute(String filePath) {
if (progressDlg != null) {
progressDlg.dismiss();
progressDlg = null;
}
}
#Override
protected void onProgressUpdate(final Integer... values) {
final int progress = values[0] / 1000;
if (progressDlg == null) {
progressHandler.post(new Runnable() {
#Override
public void run() {
final int max = values[1] / 1000;
progressDlg = new ProgressDialog(context);
progressDlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDlg.setMessage("Message");
progressDlg.setMax(max);
progressDlg.show();
}
});
} else {
progressDlg.setProgress(progress);
}
}
}
This works for me.
ProgressDialog dialog = ProgressDialog.show(activity, "", PopUpHelper.LOADING, true);
dialog.show();