I am working on an Android app with a steadily growing Code basis; the aim of the app is to scan and process QR Codes and Barcodes on Handheld Devices for Storages (not Smartphones). It hast two Activities that contain major parts of the programmatical logic; hence, I want to store major parts of the Code that contains the Functionality for processing the Scanner input in an external Service, called Scanner Service, implement the methods there and use the methods in other Activites;
however, I have a major issue with the use of Context, getApplicationContext() and the reference of the Activity in the Service and vice versa; although I think I have referenced and initialised the Textviews from the Activity in the Service, the app keeps on crashing with the following error message:
AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.app.Activity.findViewById(int)' on a null object reference
at com.xxxx.ScanService.<clinit>(ScanService.java:16)
I know what it means, but I donĀ“t know how I could access the View
private static TextView content = (TextView) a.findViewById(R.id.content_detail);
in such a way that I can use it in the Service and in the Activity and the app stops crashing.
Therefore, any hints or help would be very much appreciated, thank you in advance.
The MainDetailActivity:
package com.example.xxx_app;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
import android.view.MenuItem;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static com.xxx.ScanService.*;
import static com.xxx.SimpleItemRecyclerViewAdapter.TAGG;
/**
* An activity representing a single Main detail screen. This
* activity is only used on narrow width devices. On tablet-size devices,
* item details are presented side-by-side with a list of items
* in a {#link MainListActivity}.
*/
public class MainDetailActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,
PopupMenu.OnMenuItemClickListener {
Context context;
private RecyclerView recyclerView;
private RecyclerviewAdapter recyclerviewAdapter;
private RecyclerTouchListener touchListener;
private ListView listView;
public TextView textView4;
public String code;
public static final String TAG = "Barcode ist:" ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_detail);
context = this;
//TextView headerView = findViewById(R.id.txt1);
Spinner spinner = (Spinner) findViewById(R.id.spinner);
EditText editBarcode = (EditText) findViewById(R.id.editText);
TextView content = (TextView) findViewById(R.id.content_detail);
TextView editTextNumber = findViewById(R.id.editTextNumber);
Button addBooking = findViewById(R.id.button);
Button removeBooking = findViewById(R.id.button2);
removeBooking.setEnabled(false);
spinner.setOnItemSelectedListener(this);
//String selectedItem = spinner.getSelectedItem().toString();
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
R.array.mockdata, android.R.layout.simple_spinner_item);
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// Apply the adapter to the spinner
spinner.setAdapter(adapter);
String scannedCode = getIntent().getStringExtra("scannedCode");
Log.d(TAG, "scannedCode" + scannedCode);
if (scannedCode != null && (content.getText().toString().equals(""))) {
content.setText(scannedCode);
}
Button btn = findViewById(R.id.imageView4);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(MainDetailActivity.this, v);
popup.setOnMenuItemClickListener(MainDetailActivity.this);
popup.inflate(R.menu.popup_menu);
popup.show();
}
});
editBarcode.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
String code = editBarcode.getText().toString();
if (code.matches("")) //{ if(code.trim().isEmpty())
//|| editBarcode.getText().toString() > 100 )
{
Log.d(TAG, "Code ist leer");
}
if (keyCode == KeyEvent.KEYCODE_ENTER && code.length() > 0) {
editBarcode.setText("");
ScanService.checkEnteredCode(code);
return true;
}
return false;
}
});
recyclerView = findViewById(R.id.recyclerview);
recyclerviewAdapter = new RecyclerviewAdapter(this);
Intent newIntent = getIntent();
String receivedPalNo = newIntent.getStringExtra("palNo");
String receivedNo = newIntent.getStringExtra("no");
String receivedType = newIntent.getStringExtra("type");
String receivedRack = newIntent.getStringExtra("rack");
String receivedCountItems = newIntent.getStringExtra("count_items");
content.setText(receivedCountItems);
RestClient.getPaletteItems(getApplicationContext(),recyclerviewAdapter,receivedPalNo);
Log.d(TAGG,"Intent 1" + receivedPalNo);
Log.d(TAGG, "Intent 2" + receivedNo);
Log.d(TAGG, "Intent 3" + receivedType);
Log.d(TAGG,"Intent 4" + receivedRack);
Log.d(TAGG, "Intent 5" + receivedCountItems);
final ArrayList<Items> itemList = new ArrayList<>();
/*
Items[] items = new Items(12345,123456, 200, 500);
itemList.add(items);*/
recyclerviewAdapter.setItemList((ArrayList<Items>) itemList);
recyclerView.setAdapter(recyclerviewAdapter);
touchListener = new RecyclerTouchListener(this,recyclerView);
RecyclerviewAdapter finalRecyclerviewAdapter = recyclerviewAdapter;
touchListener
.setClickable(new RecyclerTouchListener.OnRowClickListener() {
#Override
public void onRowClicked(int position) {
//Toast.makeText(getApplicationContext(),itemList.get(position), Toast.LENGTH_SHORT).show();
}
#Override
public void onIndependentViewClicked(int independentViewID, int position) {
}
})
.setSwipeOptionViews(R.id.delete_task,R.id.edit_task)
.setSwipeable(R.id.rowFG, R.id.rowBG, new RecyclerTouchListener.OnSwipeOptionsClickListener() {
#Override
public void onSwipeOptionClicked(int viewID, int position) {
switch (viewID){
case R.id.delete_task:
itemList.remove(position);
finalRecyclerviewAdapter.setItemList(itemList);
break;
case R.id.edit_task:
Toast.makeText(getApplicationContext(),"Edit Not Available",Toast.LENGTH_SHORT).show();
break;
}
}
});
recyclerView.addOnItemTouchListener(touchListener);
class StableArrayAdapter extends ArrayAdapter<String> {
HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
public StableArrayAdapter(Context context, int textViewResourceId,
List<String> objects) {
super(context, textViewResourceId, objects);
for (int i = 0; i < objects.size(); ++i) {
mIdMap.put(objects.get(i), i);
}
}
#Override
public long getItemId(int position) {
String item = getItem(position);
return mIdMap.get(item);
}
#Override
public boolean hasStableIds() {
return true;
}
}
// savedInstanceState is non-null when there is fragment state
// saved from previous configurations of this activity
// (e.g. when rotating the screen from portrait to landscape).
// In this case, the fragment will automatically be re-added
// to its container so we don"t need to manually add it.
// For more information, see the Fragments API guide at:
//
// http://developer.android.com/guide/components/fragments.html
//
String text = getIntent().getStringExtra("palNo");
//headerView.setText(text);
if (receivedType != null && receivedType.equals("FE")) {
ImageView mImgView = findViewById(R.id.id_col_code);
mImgView.setBackgroundResource(R.drawable.backgroun_blue);
}
if (receivedType != null && receivedType.equals("UFE")) {
ImageView mImgView = findViewById(R.id.id_col_code);
mImgView.setBackgroundResource(R.drawable.backgroun_yellow);
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(this, "Selected Item: " +item.getTitle(), Toast.LENGTH_SHORT).show();
switch (item.getItemId()) {
case R.id.search_item:
// do your code
return true;
case R.id.upload_item:
// do your code
return true;
case R.id.copy_item:
// do your code
return true;
/* case R.id.print_item:
// do your code
return true;*/
case R.id.share_item:
// do your code
return true;
/*case R.id.bookmark_item:
// do your code
return true;*/
default:
return false;
}
}
public void newDialog(Activity activity) {
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true);
dialog.setContentView(R.layout.sortiment_layout);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
Button okButton = dialog.findViewById(R.id.ok);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Toast.makeText(getApplicationContext(),"Ok" ,Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
Button cancelButton = dialog.findViewById(R.id.cancel);
cancelButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Toast.makeText(getApplicationContext(),"Abbrechen" ,Toast.LENGTH_SHORT).show();
dialog.cancel();
}
});
dialog.show();
}
public void showDialog(Activity activity) {
final Dialog dialog = new Dialog(activity);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true);
dialog.setContentView(R.layout.newcustom_layout);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
Button okButton = dialog.findViewById(R.id.ok);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Toast.makeText(getApplicationContext(),"Ok" ,Toast.LENGTH_SHORT).show();
dialog.dismiss();
}
});
dialog.show();
}
public void onItemSelected(AdapterView<?> parent, View view,
int pos, long id) {
// An item was selected. You can retrieve the selected item using
// parent.getItemAtPosition(pos)
}
public void onNothingSelected(AdapterView<?> parent) {
// Another interface callback
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
// This ID represents the Home or Up button. In the case of this
// activity, the Up button is shown. For
// more details, see the Navigation pattern on Android Design:
//
// http://developer.android.com/design/patterns/navigation.html#up-vs-back
//
navigateUpTo(new Intent(this, MainListActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onResume() {
super.onResume();
recyclerView.addOnItemTouchListener(touchListener);
}
#Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
}
The ScanService Class:
package com.example.xxx;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.widget.TextView;
public class ScanService {
private static final String TAG = "Scan Service Tag";
private static Context mContext;
private static Activity a = (MainDetailActivity)mContext;
private static TextView content = (TextView)
a.findViewById(R.id.content_detail);
private static TextView editTextNumber = (TextView)
a.findViewById(R.id.editTextNumber);
public ScanService (Context mContext) {
this.mContext = mContext;
}
public static void checkEnteredCode(String code, Activity a) {
content.setText("");
//PSP-H1-EA-F3
if
(code.matches("PSP-\\p{Upper}\\d\\p{Punct}\\p{Upper}\\" +
"p{Upper}\\p{Punct}\\p{Upper}\\p{Digit}")) {
content.setText("");
content.setText(code);
Log.d(TAG, "xxx");
}
if (code.matches("LF-[0-9]*")) {
///LF-(\d+)/gi
content.setText("");
content.setText(code);
Log.d(TAG, "xxx");
}
if (code.matches("PAL-[0-9][0-9][0-9]")) {
content.setText("");
content.setText(code);
Log.d(TAG, "xxx");
}
if (code.matches("P-[0-9][0-9][0-9]")) {
content.setText("");
content.setText(code);
Log.d(TAG, "Palette");
}
if (code.matches("[0-9][0-9][0-9][0-9].[0-9][0-9].+DB")) {
if(editTextNumber == null) {
Log.d(TAG, "xxx");
}
else {
editTextNumber.setText(code);
Log.d(TAG, "xxx");
}
Log.d(TAG, "xxx");
}
if (code.matches("[0-9A-Z]*[0-9]*")) {
//editBarcode.setText("");
//editBarcode.setText(keyCode);
Log.d(TAG, "xxx");
}
if (code.matches("\\d{13}")) {
//newDialog(MainDetailActivity.this);
//editBarcode.setText("");
//editBarcode.setText(keyCode);
if(editTextNumber == null) {
Log.d(TAG, "xxx");
}
else {
editTextNumber.setText(code);
Log.d(TAG, "xxx");
}
Log.d(TAG, "xxx");
}
else {
Log.d(TAG, "xxx");
};
//editBarcode.setText("");
//editBarcode.setText(code);
/* String code = editBarcode.getText().toString();
if (code.matches("")) //{ if(code.trim().isEmpty())
//|| editBarcode.getText().toString() > 100 )
{
Log.d(TAG, "xxx");
}
//}
checkEnteredCode(code);
//editBarcode.setText("");
return Boolean.parseBoolean(code);*/
Log.d(TAG, code);
}
public static void checkEnteredCode(String code) {
}
}
You cannot access any Views from a Service! Views belong to the Activity. This is the wrong application architecture. A Service performs background processing (file I/O, network I/O, computation, etc.). The Activity is responsible for interacting with the user (inputs, display, etc.). If your Service wants to put data on the screen, you've broken the division of responsibilities. Your Service should simply notify your Activity (or any other component that is interested) when data has changed, and the Activity can then update the View itself. You can share data between the Service and your other components in a number of ways, including: event bus, publish/subscribe, shared preferences, broadcast Intents, SQLite database, etc.
Related
I'm developing a Grade/GPA Calculator app on Android during my free time. What the app basically does until now is let the user add Semesters in the Main Activity and when the user clicks on a certain Semester the user is redirected to another Activity where the user can add new Courses for that specific semester. The problem I'm having is that when the user hits on the back button to go to to the Main Activity where the Semesters are located the courses that were added in that semester are erased. The same happens when I go to the phone's homepage and re-launch the app, everything that the user had created has been deleted.
I'm pretty sure my problem is that I'm not saving the data that the user creates to the phone's storage/app's storage, but I can't seem to figure out on how to do this. If anyone can point me in the right direction I would appreciate it. Thanks!
This is my MainActivity class's code: (My MainActivity is where Semesters are added)
package com.example.gradecalculator;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import java.util.ArrayList;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
// Private Fields
private Dialog d;
private EditText semesterName;
private ListView semesterListView;
private ArrayList<String> semesterArray = new ArrayList<String>();
private SemesterAdapter customSemesterAdapter;
private ArrayList<Semester> mySemesters = new ArrayList<>();
private ArrayList<String> semesterBackgrounds = new ArrayList<String>();
private String getSemesterName;
private int randomBackground[] = new int[7];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initiating toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Making a new dialog
d = new Dialog(this);
// Initializing variables
semesterName = (EditText) d.findViewById(R.id.editTextSemesterName);
semesterListView = (ListView) findViewById(R.id.semesterList);
// Calling the removeSemesters() method
removeSemesters();
// Adding backgrounds to the backgrounds ArrayList
semesterBackgrounds.add("orange_background");
semesterBackgrounds.add("green_background");
semesterBackgrounds.add("aqua_background");
semesterBackgrounds.add("blue_background");
semesterBackgrounds.add("pink_background");
semesterBackgrounds.add("purple_background");
semesterBackgrounds.add("red_background");
semesterBackgrounds.add("yellow_background");
}
// Creating a custom Menu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.top_menu, menu);
return true;
}
// Buttons in the custom Menu
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.editButton:
Toast.makeText(this, "Delete the desired Semesters by clicking on the trash button located to the right of each Semester", Toast.LENGTH_LONG).show();
return true;
}
return super.onOptionsItemSelected(item);
}
// When user clicks on "+New Semester" button open a popup where the user is prompted to
// type in the Semester Name and when "Done" is clicked the new semester appears in the Main
// Activity
public void newSemesterPopup(View v) {
TextView closePopup;
ImageButton doneButton;
d.setContentView(R.layout.new_semester_popup);
semesterName = (EditText) d.findViewById(R.id.editTextSemesterName);
semesterListView = (ListView) findViewById(R.id.semesterList);
doneButton = (ImageButton) d.findViewById(R.id.doneButton);
doneButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addSemesters();
}
});
closePopup = (TextView) d.findViewById(R.id.exitButton);
closePopup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
d.dismiss();
}
});
d.show();
}
// Adds semesters to Main Activity
public void addSemesters() {
getSemesterName = semesterName.getText().toString();
if (semesterArray.contains(getSemesterName)) {
Toast.makeText(getBaseContext(), "Semester Name Already Exists", Toast.LENGTH_SHORT).show();
} else if (getSemesterName == null || getSemesterName.trim().equals("")) {
Toast.makeText(getBaseContext(), "Cannot Add Empty Semester Name", Toast.LENGTH_SHORT).show();
} else {
semesterArray.add(getSemesterName);
mySemesters.add(new Semester(getSemesterName, semesterBackgrounds.get(new Random().nextInt(randomBackground.length))));
customSemesterAdapter = new SemesterAdapter(getApplicationContext(), R.layout.semester_row, mySemesters);
semesterListView.setAdapter(customSemesterAdapter);
d.dismiss();
}
}
// Removes unwanted semesters from Main Activity
public void removeSemesters() {
semesterListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
AlertDialog.Builder deleteAlert = new AlertDialog.Builder(MainActivity.this);
deleteAlert.setTitle("Semester Deletion Process");
deleteAlert.setMessage("Are you sure you want to delete the selected Semesters?");
deleteAlert.setNegativeButton("No! Cancel", null);
deleteAlert.setPositiveButton("Yes! Delete", new AlertDialog.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
customSemesterAdapter.remove(customSemesterAdapter.getItem(position));
semesterArray.remove(position);
customSemesterAdapter.notifyDataSetChanged();
Toast.makeText(MainActivity.this, "Semester Deleted Successfully.", Toast.LENGTH_SHORT).show();
}
});
deleteAlert.show();
return false;
}
});
openSemestersActivity();
}
// Open the SemesterActivity and uses .putExtra to pass data to the SemesterActivity to tell it what semester to render
// data accordingly
public void openSemestersActivity() {
final Intent semester = new Intent(this, SemesterActivity.class);
semesterListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
semester.putExtra("semester", semesterName.getText().toString());
startActivity(semester);
}
});
}
}
This is my SemesterActivity code: (My SemestersActivity is where Courses are added)
package com.example.gradecalculator;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import java.util.ArrayList;
import java.util.Random;
public class SemesterActivity extends AppCompatActivity {
// Private Fields
private Dialog d;
private EditText courseName;
private EditText courseCode;
private EditText courseCredits;
private ListView courseListView;
private ArrayList<String> courseArray = new ArrayList<String>();
private CourseAdapter customCourseAdapter;
private ArrayList<Course> myCourses = new ArrayList<>();
private ArrayList<String> coursesBackgrounds = new ArrayList<String>();
private String getCourseName;
private String getCourseCode;
private String getCourseCredits;
private int randomBackground[] = new int[7];
private TextView courseNameView;
private TextView courseCodeView;
private TextView courseCreditsView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_semester);
d = new Dialog(this);
courseNameView = (TextView) d.findViewById(R.id.editTextCourseName);
courseCodeView = (TextView) d.findViewById(R.id.editTextCourseCode);
courseCreditsView = (TextView) d.findViewById(R.id.editTextCourseCredits);
courseListView = (ListView) findViewById(R.id.coursesList);
// Retrieving the Extra and determining the semester we want to load
Intent myIntent = getIntent();
String semester = myIntent.getStringExtra("semester");
removeCourses();
// Initiating toolbar
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Adding backgrounds to the backgrounds ArrayList
coursesBackgrounds.add("orange_background_big");
coursesBackgrounds.add("green_background_big");
coursesBackgrounds.add("aqua_background_big");
coursesBackgrounds.add("blue_background_big");
coursesBackgrounds.add("pink_background_big");
coursesBackgrounds.add("purple_background_big");
coursesBackgrounds.add("red_background_big");
coursesBackgrounds.add("yellow_background_big");
}
// Creating a custom Menu
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.top_menu, menu);
return true;
}
// Buttons in the custom Menu
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.editButton:
Toast.makeText(this, "Delete the desired Courses by clicking on the trash button located to the right of each Semester", Toast.LENGTH_LONG).show();
return true;
}
return super.onOptionsItemSelected(item);
}
// New course popup
public void newCoursePopup(View v) {
TextView closePopup;
ImageButton doneButton;
d.setContentView(R.layout.new_course_popup);
courseName = (EditText) d.findViewById(R.id.editTextCourseName);
courseCode = (EditText) d.findViewById(R.id.editTextCourseCode);
courseCredits = (EditText) d.findViewById(R.id.editTextCourseCredits);
doneButton = (ImageButton) d.findViewById(R.id.doneButton);
doneButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addCourses();
}
});
closePopup = (TextView) d.findViewById(R.id.exitButton);
closePopup.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
d.dismiss();
}
});
d.show();
}
// Adding courses to the Semester
public void addCourses() {
getCourseName = courseName.getText().toString();
getCourseCode = courseCode.getText().toString();
getCourseCredits = courseCredits.getText().toString();
if(courseArray.contains(getCourseName)) {
Toast.makeText(getBaseContext(), "Course Name Already Exists", Toast.LENGTH_SHORT).show();
}
else if(getCourseName == null || getCourseName.trim().equals("")) {
Toast.makeText(getBaseContext(), "Cannot Add Empty Course Name", Toast.LENGTH_SHORT).show();
}
else {
courseArray.add(getCourseName);
myCourses.add(new Course(getCourseName, getCourseCode, getCourseCredits, coursesBackgrounds.get(new Random().nextInt(randomBackground.length))));
customCourseAdapter = new CourseAdapter(getApplicationContext(), R.layout.course_row, myCourses);
courseListView.setAdapter(customCourseAdapter);
d.dismiss();
}
}
// Removing courses from the Semester
public void removeCourses() {
courseListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
AlertDialog.Builder deleteAlert = new AlertDialog.Builder(SemesterActivity.this);
deleteAlert.setTitle("Course Deletion Process");
deleteAlert.setMessage("Are you sure you want to delete the selected Courses?");
deleteAlert.setNegativeButton("No! Cancel", null);
deleteAlert.setPositiveButton("Yes! Delete", new AlertDialog.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
customCourseAdapter.remove(customCourseAdapter.getItem(position));
courseArray.remove(position);
customCourseAdapter.notifyDataSetInvalidated();
Toast.makeText(SemesterActivity.this, "Course Deleted Successfully", Toast.LENGTH_SHORT).show();
}
});
deleteAlert.show();
return false;
}
});
}
}
There are a couple of databases you can look into; You can use Room or Realm. You can also check out online DBs like Firestore by Firebase. The beauty about having an online db a user(Student) can access their data from a different phone if they lose or replace their current one. A recommended way to go is to have both to cover both scenarios.
I am trying to create a BLE android app, and I've been having a lot of trouble with null pointers that I can't figure out even when using androids sample apps of android-BluetoothAdvertisements and android-BluetoothLEGatt.
This is my code:
import android.app.Activity;
import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.NavigationView;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.support.v4.widget.DrawerLayout;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import java.util.List;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private LeDeviceListAdapter mLeDeviceListAdapter;
private BluetoothLeScanner mBluetoothLeScanner;
private boolean mScanning;
private ScanCallback mScanCallback;
private Handler mHandler;
private BluetoothDevice mBluetoothGatt;
private String mDeviceName;
private String mDeviceAddress;
private ScanResultAdapter mAdapter;
private BluetoothGattDescriptor mDescriptor;
private BluetoothGattCharacteristic mBluetoothCharacteristic;
private BluetoothDevice device;
private int mConnectionState = STATE_DISCONNECTED;
private BluetoothLeScanner btScanner;
private BluetoothDevice mbluetoothDevice;
Button button;
DrawerLayout dLayout;
private Button ble_scan;
private final static int REQUEST_ENABLE_BT = 1;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
private final String LIST_NAME = "NAME";
private final String LIST_UUID = "UUID";
public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static String EXTRA_DATA =
"com.example.bluetooth.le.EXTRA_DATA";
// Stops scanning after 5 seconds.
private static final long SCAN_PERIOD = 5000;
//On entering app protocols
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
//Set View and new Handler
setContentView(R.layout.activity_main);
mHandler = new Handler();
mAdapter = new ScanResultAdapter(this.getApplicationContext(),
LayoutInflater.from(this));
// Use this check to determine whether BLE is supported on the device. Then you can
// selectively disable BLE-related features.
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
//sets up variables to initialize Bluetooth Manager and our Adapter settings
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
//Initializes Navigation Drawer
setNavigationDrawer();
//Checks if Bluetooth adapter is enabled and requests to enable it
if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
//Initializes Scan Button
//addListenerOnButton();
//startScanning();
TextView txtView = (TextView) findViewById(R.id.ScanOut);
txtView.setText(BluetoothDevice.EXTRA_NAME);
//Initializing floating action button
FloatingActionButton fab = (FloatingActionButton) 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();
}
});
}
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
#Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
/**
* Custom ScanCallback object - adds to adapter on success, displays error on failure.
*/
private class SampleScanCallback extends ScanCallback {
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
for (ScanResult result : results) {
mAdapter.add(result);
}
mAdapter.notifyDataSetChanged();
}
#Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
mAdapter.add(result);
mAdapter.notifyDataSetChanged();
}
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Toast.makeText(MainActivity.this, "Scan failed with error: " + errorCode, Toast.LENGTH_LONG)
.show();
}
}
/**
* Start scanning for BLE Advertisements (& set it up to stop after a set period of time).
*/
public void startScanning() {
if (mScanCallback == null) {
// Will stop the scanning after a set time.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
stopScanning();
}
}, SCAN_PERIOD);
// Kick off a new scan.
mScanCallback = new SampleScanCallback();
mBluetoothLeScanner.startScan(mScanCallback);
Toast.makeText(MainActivity.this, "Started Scan", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Already Scanning", Toast.LENGTH_SHORT);
}
}
/**
* Stop scanning for BLE Advertisements.
*/
public void stopScanning() {
// Stop the scan, wipe the callback.
mBluetoothLeScanner.stopScan(mScanCallback);
mScanCallback = null;
// Even if no new results, update 'last seen' times.
mAdapter.notifyDataSetChanged();
}
/* private void scanLeDevice(final boolean enable) {
//mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mScanning = false;
mBluetoothLeScanner.stopScan(mScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothLeScanner.startScan(mScanCallback);
} else {
mScanning = false;
mBluetoothLeScanner.stopScan(mScanCallback);
}
}*/
private void GattConnect() {
BluetoothGatt mBluetoothGatt = mbluetoothDevice.connectGatt(this, false, mGattCallback);
mBluetoothGatt.discoverServices();
List<BluetoothGattService> services = mBluetoothGatt.getServices();
for (BluetoothGattService service : services) {
List<BluetoothGattCharacteristic> characteristics = service.getCharacteristics();
}
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
#Override
public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
// this will get called anytime you perform a read or write characteristic operation
}
#Override
public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
// this will get called when a device connects or disconnects
}
#Override
public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
// this will get called after the client initiates a BluetoothGatt.discoverServices() call
}
};
// Adapter for holding devices found through scanning.
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
mInflator = MainActivity.this.getLayoutInflater();
}
public void addDevice(BluetoothDevice device) {
if(!mLeDevices.contains(device)) {
mLeDevices.add(device);
}
}
public BluetoothDevice getDevice(int position) {
return mLeDevices.get(position);
}
public void clear() {
mLeDevices.clear();
}
#Override
public int getCount() {
return mLeDevices.size();
}
#Override
public Object getItem(int i) {
return mLeDevices.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
// General ListView optimization code.
if (view == null) {
view = mInflator.inflate(R.layout.listitem_device, null);
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
BluetoothDevice device = mLeDevices.get(i);
final String deviceName = device.getName();
if (deviceName != null && deviceName.length() > 0)
viewHolder.deviceName.setText(deviceName);
else
viewHolder.deviceName.setText("Unknown Device");
viewHolder.deviceAddress.setText(device.getAddress());
return view;
}
}
/*
Setting up Navigational Drawer that creates other fragments
*/
private void setNavigationDrawer() {
Intent intent = null;
dLayout = (DrawerLayout) findViewById(R.id.drawer_layout); // initiate a DrawerLayout
NavigationView navView = (NavigationView) findViewById(R.id.navigation); // initiate a Navigation View
// implement setNavigationItemSelectedListener event on NavigationView
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
Fragment frag = null; // create a Fragment Object
int itemId = menuItem.getItemId(); // get selected menu item's id
// check selected menu item's id and replace a Fragment Accordingly
if (itemId == R.id.nav_home){
frag = new HomeFragment();
} else if (itemId == R.id.nav_alarms) {
frag = new AlarmFragment();
} else if (itemId == R.id.nav_cues) {
frag = new CueFragment();
} else if (itemId == R.id.nav_data) {
frag = new DataFragment();
} else if (itemId == R.id.nav_settings){
frag = new SettingFragment();
} else if (itemId == R.id.nav_help){
frag = new HelpFragment();
}
// display a toast message with menu item's title
Toast.makeText(getApplicationContext(), menuItem.getTitle(), Toast.LENGTH_SHORT).show();
if (frag != null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame, frag); // replace a Fragment with Frame Layout
transaction.commit(); // commit the changes
dLayout.closeDrawers(); // close the all open Drawer Views
return true;
}
return false;
}
});
}
public void addListenerOnButton() {
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
//scanLeDevice(true);
}
});
}
static class ViewHolder {
TextView deviceName;
TextView deviceAddress;
}
//What happens on resuming the app
#Override
protected void onResume() {
super.onResume();
// Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled,
// fire an intent to display a dialog asking the user to grant permission to enable it.
if (!mBluetoothAdapter.isEnabled()) {
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
// Initializes list view adapter.
mLeDeviceListAdapter = new LeDeviceListAdapter();
//setListAdapter(mLeDeviceListAdapter);
//scanLeDevice(true);
}
#Override
protected void onPause() {
super.onPause();
//scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// User chose not to enable Bluetooth.
if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) {
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
}
I am using the BluetoothLeService class from the Gatt example. Right now I am trying to get my scanning to work so I can find my BLE device to attempt to set up a Gatt connection with it.
I have tried implementing many parts of the examples, and since startLeScan() and stopLeScan() are depreciated, I am attempting to merge the BLE scanning from the bluetooth advertisements example with the BLE Gatt example. The apps examples work fine, but I get a bunch of null pointers when I try to do it myself.
On my onResume function I will get this error: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.bluetooth.BluetoothAdapter.isEnabled()' on a null object reference
Which is weird because I invoke the same method during onCreate without problems.
The thing that hasn't been working at all no matter how I try to invoke it is my startScanning method. I always get this error: 'java.lang.NullPointerException: Attempt to invoke virtual method void android.bluetooth.le.BluetoothLeScanner.startScan(android.bluetooth.le.ScanCallback)' on a null object reference because it seems like the startScan method never actually works. Maybe I am just doing something horribly wrong.
It's called in a fragment in the example, but I don't think that should affect it and I should be able to use it in my main activity for a base level connection for debugging if I'm not mistaken.
Does anyone have any advice on what I'm doing glaringly wrong?
The image moves perfectly the first time into its place i.e detail activity image view and also returns perfectly back to the main activity but when I click the same image next time the transition animation moves the image to an incorrect (too high) offset in the detail activity and once the animation completes the image will appear to "warp" into the correct position.
Here is my DetailActivity.java file:
package com.akshitjain.popularmovies;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
public class DetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
postponeEnterTransition();
}
ImageView backdropImageView = (ImageView) findViewById(R.id.detail_image_view);
final ImageView posterImageView = (ImageView) findViewById(R.id.detail_poster);
TextView overviewTextView = (TextView) findViewById(R.id.overview_text_view);
TextView releaseDateTextView = (TextView) findViewById(R.id.release_date);
TextView userRatingTextView = (TextView) findViewById(R.id.user_rating);
TextView genreTextView = (TextView) findViewById(R.id.genre);
genreTextView.setText("");
Genre genreObject = new Genre();
String genreName;
Intent intent = getIntent();
if (intent != null && intent.hasExtra(Constants.MOVIE_OBJECT_PARCELABLE_EXTRA)) {
Movies movies = intent.getParcelableExtra(Constants.MOVIE_OBJECT_PARCELABLE_EXTRA);
int[] genre;
genre = movies.genre;
for (int i = 0; i < genre.length; ++i) {
genreName = genreObject.getGenreName(genre[i]);
genreTextView.append(genreName);
if (i < genre.length - 1) {
genreTextView.append(", ");
}
}
setTitle(movies.originalTitle);
Picasso.with(getApplicationContext())
.load((Constants.IMAGE_BASE_URL + Constants.POSTER_SIZE_LARGE).trim() + movies.backdropPath)
.into(backdropImageView);
Picasso.with(getApplicationContext())
.load((Constants.IMAGE_BASE_URL + Constants.POSTER_SIZE_SMALL).trim() + movies.posterPath)
.into(posterImageView, new Callback() {
#Override
public void onSuccess() {
posterImageView.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
posterImageView.getViewTreeObserver().removeOnPreDrawListener(this);
startPostponedEnterTransition();
}
return true;
}
}
);
}
#Override
public void onError() {
}
}
);
overviewTextView.setText(movies.overview);
releaseDateTextView.setText(movies.releaseDate);
userRatingTextView.setText(movies.userRating);
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#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_detail, menu);
return true;
}
#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();
switch (id) {
case android.R.id.home:
supportFinishAfterTransition();
return true;
case R.id.action_settings:
return true;
}
return super.onOptionsItemSelected(item);
}
}
Try this.
posterImageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Picasso.with(getApplicationContext())
.load((Constants.IMAGE_BASE_URL + Constants.POSTER_SIZE_SMALL).trim() + movies.posterPath)
.into(posterImageView, new Callback() {
#Override
public void onSuccess() {
startPostponedEnterTransition();
}
#Override
public void onError() {
}
});
}
}
I've been following this tutorial Android Search Filter ListView Images and Texts Tutorial
with success. I'm trying to implement it in my own activity and get data from the server.
When I'm typing inside the search field, the grid view becomes empty. It's like the List at custom adapter becomes null.
my activity Class
package com.danz.tensai.catalog;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.danz.tensai.catalog.app.MyApplication;
import com.danz.tensai.catalog.helper.Product;
import com.danz.tensai.catalog.helper.SwipeListAdapter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class MainActivity extends ActionBarActivity {
private String TAG = MainActivity.class.getSimpleName();
private String URL_TOP_250 = "http://danztensai.hostoi.com/imdb_top_250.php?offset=";
private SwipeRefreshLayout swipeRefreshLayout;
//private ListView listView;
private GridView gridView;
private SwipeListAdapter adapter;
private List<Product> productList;
private ProgressBar spinner;
EditText editsearch;
private int offSet = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = (GridView)findViewById(R.id.gridViewListProduct);
productList = new ArrayList<>();
fetchProduct();
adapter = new SwipeListAdapter(this, productList);
gridView.setAdapter(adapter);
editsearch = (EditText)findViewById(R.id.search);
editsearch.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
String text = editsearch.getText().toString().toLowerCase(Locale.getDefault());
Log.d(TAG,"Text To Search : "+text);
adapter.filter(text);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
});
}
#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
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);
}
private void fetchProduct() {
spinner = (ProgressBar)findViewById(R.id.progressBar1);
// appending offset to url
String url = URL_TOP_250 + offSet;
// Volley's json array request object
JsonArrayRequest req = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
if (response.length() > 0) {
// looping through json and adding to movies list
for (int i = 0; i < response.length(); i++) {
try {
JSONObject movieObj = response.getJSONObject(i);
int rank = movieObj.getInt("rank");
String title = movieObj.getString("title");
String imageURL = movieObj.getString("imageURL");
Product m = new Product(rank, title,imageURL);
productList.add(0, m);
// updating offset value to highest value
if (rank >= offSet)
offSet = rank;
} catch (JSONException e) {
Log.e(TAG, "JSON Parsing error: " + e.getMessage());
}
}
// adapter.notifyDataSetChanged();
}
// stopping swipe refresh
// swipeRefreshLayout.setRefreshing(false);
spinner.setVisibility(View.GONE);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Server Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show();
// stopping swipe refresh
// swipeRefreshLayout.setRefreshing(false);
spinner.setVisibility(View.GONE);
}
});
// Adding request to request queue
Log.e(TAG,req.toString() );
MyApplication.getInstance().addToRequestQueue(req);
}
}
and my Custom Adapter
public class SwipeListAdapter extends BaseAdapter {
private Activity activity;
LayoutInflater inflater;
Context mContext;
private List<Product> productList;
private ArrayList<Product> arraylist;
private String TAG = SwipeListAdapter.class.getSimpleName();
//private String[] bgColors;
public SwipeListAdapter(Context context, List<Product> productList) {
//this.activity = activity;
mContext = context;
this.productList = productList;
inflater = LayoutInflater.from(mContext);
this.arraylist = new ArrayList<Product>();
this.arraylist.addAll(productList);
// bgColors = activity.getApplicationContext().getResources().getStringArray(R.array.movie_serial_bg);
}
public class ViewHolder{
ImageView productImage;
}
#Override
public int getCount() {
return productList.size();
}
#Override
public Object getItem(int location) {
return productList.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
if(convertView==null)
{
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.list_row,null);
holder.productImage = (ImageView) convertView.findViewById(R.id.productImage);
convertView.setTag(holder);
}else
{
holder
= (ViewHolder) convertView.getTag();
}
new DownloadImageTask((holder.productImage))
.execute(productList.get(position).imageURL);
return convertView;
}
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
productList.clear();
if (charText.length() == 0) {
productList.addAll(arraylist);
} else {
for (Product wp : arraylist) {
if (wp.getTitle().toLowerCase(Locale.getDefault())
.contains(charText)) {
productList.add(wp);
}
}
}
notifyDataSetChanged();
}
}
When you're creating the adapter, in its constructor, you add to the arraylist list the content of productList. At that point(the adapter constructor) the productList is most likely empty as the http request to fetch the json hasn't finished yet. So you end up with an empty arraylist and when you do any filtering on the adapter you'll not see anything because there' nothing to filter.
Don't forget to update the arraylist(from the adapter) when the data finally comes in the onResponse() callback so you have a reference to to it to use it for filtering.
I would advise you to follow other tutorials.
Edit:
Add a "add" method to the adapter to insert the new items:
//In the SwipeListAdapter class add
public void add(Product p) {
productList.add(0, p);
arraylist.add(0, p);
notifyDataSetChyanged();
}
Then in your activity, instead of:
productList.add(0, m);
call:
adapter.add(m);
I have an alert dialog that allows user to edit a TextView. Currently, once the alert dialog closes, the user has to hit the back button and then re-enter the activity for the TextView to update. I've tried many solutions on SO but none seem to work. When the user clicks 'Save Changes', the TextView should update.
Calling activity:
package com.group1.workouttracker;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
public class DayActivity extends Activity {
//does not extend ListActivity, so list functions must be called by myList object
private String buttonClicked;
private String thisSummary;
private Intent intent;
DatabaseHelper db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_day);
db = DatabaseHelper.getInstance(getApplicationContext());
intent = getIntent();
buttonClicked = intent.getStringExtra("Day");
Button buttonCreateExercise = (Button) findViewById(R.id.buttonAddExercise);
buttonCreateExercise.setOnClickListener(new OnClickListenerCreateExercise(buttonClicked));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void readSummary(String buttonClicked) {
TextView textViewSummary = (TextView) findViewById(R.id.textViewSummary);
textViewSummary.setOnLongClickListener(new OnLongClickListenerEditSummary(buttonClicked));
}
#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_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onResume() {
super.onResume();
thisSummary = db.readSummary(buttonClicked).getSummary();
TextView summary = (TextView) findViewById(R.id.textViewSummary);
summary.setOnLongClickListener(new OnLongClickListenerEditSummary(buttonClicked));
summary.setText(thisSummary);
}
}
Alert Dialog that activates on a long press:
package com.group1.workouttracker;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.widget.EditText;
import android.widget.NumberPicker;
import android.widget.Toast;
public class OnLongClickListenerEditSummary implements View.OnLongClickListener {
Context context;
String dayClicked = "";
#Override
public boolean onLongClick(View view) {
context = view.getContext();
final DatabaseHelper db = DatabaseHelper.getInstance(context);
ObjectDay objectDay = db.readSummary(dayClicked);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View formElementsView = inflater.inflate(R.layout.edit_summary_form, null, false);
final long dayId = objectDay.getId();
final String dName = objectDay.getDayName();
final EditText editTextSummary = (EditText) formElementsView.findViewById(R.id.editTextSummary);
final CharSequence[] items = { "Edit", "Delete" };
new AlertDialog.Builder(context).setTitle("Exercise");
new AlertDialog.Builder(context)
.setView(formElementsView)
.setTitle("Edit Summary for " + dayClicked + ":")
.setPositiveButton("Save Changes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ObjectDay objectDay = new ObjectDay();
objectDay.setId(dayId);
objectDay.setDayName(dName);
objectDay.setSummary(editTextSummary.getText().toString());
boolean updateSuccessful = DatabaseHelper.getInstance(context).updateSummary(objectDay);
if(updateSuccessful) {
Toast.makeText(context, "Summary was updated.", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(context, "Unable to update summary.", Toast.LENGTH_SHORT).show();
}
//dialog.cancel();
dialog.dismiss();
}
}).show();
return false;
}
public void editRecord(final String dName) {
final DatabaseHelper db = DatabaseHelper.getInstance(context);
ObjectDay objectDay = db.readSummary(dName);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View formElementsView = inflater.inflate(R.layout.edit_summary_form, null, false);
final EditText editTextDay = (EditText) formElementsView.findViewById(R.id.editTextSummary);
final EditText editTextSummary = (EditText) formElementsView.findViewById(R.id.editTextSummary);
editTextSummary.setText(objectDay.getSummary());
}
public OnLongClickListenerEditSummary(String dayClicked) {
this.dayClicked = dayClicked;
}
}
Edit: I was able to get this working correctly by adding the following code:
Activity:
public void passThrough(ObjectDay objDay) {
textViewSummary.setText(objDay.getSummary());
}
In .setpositive button:
((DayActivity) context).passThrough(objectDay);
Opening a dialog wont trigger the Activity's onPause/onResume (I'm not sure if that's true for dialog fragments). Instead you can apply an onDismissListener (which can be a member variable of the Activity or anonymous) to the dialog.
When the dialog is closed (by any means) you'll get some information and you can update your textfield. Alternatively you could do the same from the positive click listener.
Either
alert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//UPDATE FROM HERE (call a method or manipulate an Activity member var)
}
});
OR
alert.setOnDismissListener(new OnDismissListener() {
public void onDismiss(DialogInterface dialog) {
//UPDATE FROM HERE (Check DialogInterface for positive if you want)
}
});
Edit, for your example:
class Whatever extends Activity {
private TextView mTextView;
private MyPassThroughListener mPassThroughListener = new MyPassThroughListener() {
#Override
public function passThrough(ObjectDay objDay) {
mTextView.setText(objDay.getSummary());
}
}
protected void onCreate(Bundle savedInstanceState) {
....
buttonCreateExercise.setOnClickListener(new OnClickListenerCreateExercise(mPassThroughListener ));
}
}
class OnLongClickListenerEditSummary {
MyPassThroughListener mPassThroughListener;
...
public OnLongClickListenerEditSummary (MyPassThroughListener passThroughListener) {
mPassThroughListener = passThroughListener;
}
#Override
public boolean onLongClick(View view) {
....
new AlertDialog.Builder(context)
.setPositiveButton("Save Changes",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
ObjectDay objectDay = new ObjectDay();
objectDay.setId(dayId);
objectDay.setDayName(dName);
objectDay.setSummary(editTextSummary.getText().toString());
mPassThroughListener.passThrough(objectDay);
dialog.dismiss();
}
...
}
}
public interface MyPassThroughListener {
public function passThrough(ObjectDay objDay);
}