I have an activity which needs to trigger 4 different DialogFragments in which i trigger an intent do get images from camera or gallery.
I can retain the fragment state and continue to observe the "onActivityResult" and send it to the dialogfragmentx but when they recreate and i try to show again the images that i got from the gallery, when i use "addView" on the linearlayout it does nothing.
Here is my code from the activity:
private DFrag_room frag_room;
private DFrag_terrace frag_terrace;
private DFrag_garden frag_garden;
private DFrag_parking frag_parking;
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (frag_room != null) {
getSupportFragmentManager().putFragment(outState, "fragment_room", frag_room);
}
if (frag_terrace != null) {
getSupportFragmentManager().putFragment(outState, "fragment_terrace", frag_terrace);
}
if (frag_garden != null) {
getSupportFragmentManager().putFragment(outState, "fragment_garden", frag_garden);
}
if (frag_parking != null) {
getSupportFragmentManager().putFragment(outState, "fragment_parking", frag_parking);
}
}
#Override
public void onRestoreInstanceState(Bundle inState){
FragmentManager fm = getSupportFragmentManager();
frag_room = (DFrag_room) fm.getFragment(inState, "fragment_room");
frag_terrace = (DFrag_terrace) fm.getFragment(inState, "fragment_terrace");
frag_garden = (DFrag_garden) fm.getFragment(inState, "fragment_garden");
frag_parking = (DFrag_parking) fm.getFragment(inState, "fragment_parking");
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (frag_room != null) {
frag_room.onActivityResult(requestCode, resultCode, data);
}
if (frag_terrace != null) {
frag_terrace.onActivityResult(requestCode, resultCode, data);
}
if (frag_garden != null) {
frag_garden.onActivityResult(requestCode, resultCode, data);
}
if (frag_parking != null) {
frag_parking.onActivityResult(requestCode, resultCode, data);
}
}
and the code from one of the dialogfragments (the procedure is the same on every one)
private LinearLayout layout_images;
private ImageView img_add_image;
private File photoFile;
private ArrayList<Uri> images;
public DFrag_room() {
}
public interface DFrag_roomListener {
void onFinishRoom();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dfrag_room, container);
layout_images = (LinearLayout) view.findViewById(R.id.dfrag_room_imgs_layout);
img_add_image = (ImageView) view.findViewById(R.id.dfrag_room_img_add_img);
img_add_image.setOnClickListener(this);
if (savedInstanceState != null) {
images = (ArrayList<Uri>) savedInstanceState.getSerializable("images");
for (int i = 0; i < images.size(); i++) {
addImage(images.get(i));
}
}
setRetainInstance(true);
return view;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); // <-- must call this if you want to retain dialogFragment upon rotation
outState.putSerializable("images", images);
}
#Override
public void onDestroyView() {
if (getDialog() != null && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
#Override
public void onActivityResult(int reqCode, int resCode, Intent data) {
switch (reqCode) {
case CONF.REQ_PHOTO:
if (resCode == Activity.RESULT_OK) {
if ((photoFile != null)) {
Uri img = Uri.fromFile(photoFile);
images.add(img);
addImage(img);
}
}
break;
case CONF.REQ_GALLERY:
if (resCode == Activity.RESULT_OK) {
images.add(data.getData());
addImage(data.getData());
}
break;
}
super.onActivityResult(resCode, resCode, data);
}
public void addImage(Uri img_uri) {
int margin = getResources().getDimensionPixelOffset(R.dimen.padding_x_small);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(img_add_image.getWidth(), img_add_image.getHeight());
params.setMargins(0, 0, margin, 0);
RoundedImageView new_img = new RoundedImageView(getActivity());
new_img.setLayoutParams(params);
new_img.setScaleType(ImageView.ScaleType.CENTER_CROP);
new_img.setBackgroundResource(R.drawable.bg_white_stroke);
new_img.setCornerRadius((float) 6);
Glide.with(getActivity()).load(img_uri).thumbnail(0.8f).into(new_img);
layout_images.addView(new_img, 0);
}
When i get the image from the intent it works fine, but when i get it from the saved list of uris (onCreateView) it doesen't work
EDIT:
Sorry, the app doesen't crash, i don't see the image in my layout, it calls "addImage" but i don't see the images.
Solved, i tried to create an imageview with 0 width and 0 height beacusa I create it from the onCreate method where img_add_image.getWidth() is 0.
Related
I have fragments with a circleimageview inside used as a profile image that is saved later in a database correctly.
My problem is to save the state of the imageview with onSaveInstanceState and onPause/onStop to keep their state before saving them in the database and after, for example, performing a screen rotation.
This is my code
public class MyFragment extends Fragment implements View.OnClickListener {
private CircleImageView mPhoto;
private byte[] bytes = null;
private Bitmap photo = null;
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if(bytes!=null) {
outState.putByteArray("bytes", bytes);
}
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
LayoutInflater lf = getActivity().getLayoutInflater();
view = lf.inflate(R.layout.my_fragment,container,false);
mPhoto = (CircleImageView) view.findViewById(R.id.photo);
view.findViewById(R.id.photo).setOnClickListener(this);
if(savedInstanceState!=null){
if(savedInstanceState.containsKey("bytes")){
bytes = savedInstanceState.getByteArray("bytes");
if(bytes != null) {
//but with a screen rotation the image is not restored
photo = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mPhoto.setImageBitmap(photo);
}
}
}
return view;
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.photo:
Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
try {
startActivityForResult(Intent.createChooser(i, "Select Picture"), 0);
}catch (ActivityNotFoundException ex){
ex.printStackTrace();
}
break;
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==0 && resultCode == Activity.RESULT_OK) {
Uri path = data.getData();
Bitmap tmp = null;
try {
tmp = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), path);
} catch (IOException e) {
e.printStackTrace();
}
if(tmp != null) {
mPhoto.setImageBitmap(photo);
bytes = getBitmapAsByteArray(photo);
//tested, bytes is not null and the photo are restored correctly when saved on the database
}
}
}
#Override
public void onResume() {
super.onResume();
bytes = getActivity().getIntent().getByteArrayExtra("bytes");
if(bytes != null) {
//here bytes is null
photo = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mPhoto.setImageBitmap(photo);
}
}
#Override
public void onStop() {
super.onStop();
if(bytes!=null)
getActivity().getIntent().putExtra("bytes",bytes);
}
}
in this way the image is not maintained during a screen rotation, how to correctly implement onsavedInstanceState, onStop and onResume?
Put code before super() method.
#Override
public void onStop() {
if(bytes!=null)
getActivity().getIntent().putExtra("bytes",bytes);
super.onStop();
}
Easiest way Use ViewModel with your fragment.
Refer: https://developer.android.com/topic/libraries/architecture/viewmodel.html
Update:
Step1: Add View Model dependency in build.gradle
def lifecycle_version = "2.0.0"
implementation "androidx.lifecycle:lifecycle viewmodel:$lifecycle_version"
Step 2: Create a ViewModel for Fragment
public class MyFragmentViewModel extends ViewModel {
}
Step 3: Set ViewModel in MyFragment
public class MyFragment extends Fragment {
public void onStart() {
MyFragmentViewModel userModel = ViewModelProviders.of(getActivity()).get(MyFragmentViewModel.class);
}
}
I am using FlexboxLayout for showing chips in android but stuck at UI Where I want to show number of chips count at the end of second line as per below screenshot
As per above design I want to show chips until second line and the chips that not fit in second line should increase chip count at the end of chips
What I have check is
1- FlexboxLayout setMaxLine(2); But in this case UI only two line draw and second line is strech
2- FlexboxLayout getFlexLineInternel() - this API gives wrong result. Count of line is increases after 1 item added in the line then it gives getFlexLineInternel().size() == 2 it means view is already added in third line but I want to restrict only on 2 lines.
3- Try with Material Chip and ChipGroup - It didn't given me number of lines draw in chipGroup
4- Try with Flowlayout similar as ChipGroup. Didn't given me number of lines draw by layout so that I can show count at end of second line
Please give me suggestion what is helpful in my situation
Here is my code
activity_search_label.xml
<com.google.android.flexbox.FlexboxLayout
android:id="#+id/assetLabelsContainer"
android:layout_width="match_parent"
android:layout_marginLeft="#dimen/size_16"
android:layout_marginRight="#dimen/size_16"
android:layout_height="wrap_content"
app:flexWrap="wrap"/>
LabelSearchActivity.java
public class LabelSearchActivity extends SearchActivity {
#BindView(R.id.assetLabelsContainer)
public FlexboxLayout assetLabelsContainer;
private int COUNTER_LABEL_ID = -1;
private ArrayList<LabelModelParcelableItem> selectedLabels;
private ArrayList<LabelModelParcelableItem> visibleSelectedList;
private CompositeDisposable disposables;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ButterKnife.bind(this);
clearLabelList();
showSelectedLabel();
}
public void hideSearchTitleCountView() {
if (null != searchTitle) {
searchTitle.setVisibility(View.GONE);
}
}
private void clearLabelList() {
selectedLabels = new ArrayList<>();
visibleSelectedList = new ArrayList<>();
assetLabelsContainer.getFlexLinesInternal().clear();
assetLabelsContainer.removeAllViews();
}
private void showSelectedLabel() {
if (getIntent() != null) {
Bundle bundle = getIntent().getExtras();
if (bundle.getParcelableArrayList(SELECTED_LABEL_ITEMS) != null) {
ArrayList<LabelModelParcelableItem> selectedLabels = bundle
.getParcelableArrayList(SELECTED_LABEL_ITEMS);
showLabelList(selectedLabels);
}
}
}
public void addViewToFlex(final LabelModelParcelableItem labelModelParcelableItem) {
if (!selectedLabels.contains(labelModelParcelableItem)) {
selectedLabels.add(labelModelParcelableItem);
final View view = getChipView(labelModelParcelableItem);
if (shouldShowCount()) {
View countView = getCounterView();
if (null != countView) {
LabelModelParcelableItem tag = (LabelModelParcelableItem) countView.getTag();
LabelModelParcelableItem updatedTag =
new LabelModelParcelableItem(
tag.getLabelId(), String.valueOf(getInvisibleItemCount()), tag.getAssetCount());
TextView textView = (TextView) countView.findViewById(R.id.labelNameText);
textView.setText(" + " + updatedTag.getLabelName());
countView.setTag(updatedTag);
assetLabelsContainer.requestLayout();
} else {
addCounterView();
}
} else {
visibleSelectedList.add(labelModelParcelableItem);
assetLabelsContainer.addView(view);
}
}
}
public int getInvisibleItemCount() {
ArrayList<LabelModelParcelableItem> itemList = new ArrayList<>(selectedLabels);
itemList.removeAll(visibleSelectedList);
return itemList.size();
}
private void addCounterView() {
final View view =
LayoutInflater.from(LabelSearchActivity.this)
.inflate(R.layout.label, assetLabelsContainer, false);
LabelModelParcelableItem item =
new LabelModelParcelableItem(
COUNTER_LABEL_ID, String.valueOf(getInvisibleItemCount()), COUNTER_LABEL_ID);
view.setTag(item);
TextView textView = (TextView) view.findViewById(R.id.labelNameText);
textView.setText(" + " + item.getLabelName());
view.setOnClickListener(v -> showLabelContainerScreen(getSelectedLabels()));
if (getInvisibleItemCount() > 0) {
assetLabelsContainer.addView(view);
}
}
public View getChipView(final LabelModelParcelableItem item) {
final View view =
LayoutInflater.from(LabelSearchActivity.this)
.inflate(R.layout.label, assetLabelsContainer, false);
TextView textView = (TextView) view.findViewById(R.id.labelNameText);
textView.setText(item.getLabelName());
view.setOnClickListener(v -> removeViewFormFlex(view, item));
return view;
}
private boolean shouldShowCount() {
if (assetLabelsContainer.getFlexLinesInternal().size() > 2) {
return true;
}
return false;
}
private void updatedLabelAfterRemove() {
if (null != getCounterView()) {
if (getInvisibleItemCount() > 0) {
ArrayList<LabelModelParcelableItem> itemList = new ArrayList<>(selectedLabels);
itemList.removeAll(visibleSelectedList);
Collections.sort(itemList, (o1, o2) -> o2.getLabelName().compareTo(o1.getLabelName()));
if (!itemList.isEmpty()) {
addViewAfterRemove(itemList.get(0));
}
} else {
assetLabelsContainer.removeView(getCounterView());
}
}
}
private void addViewAfterRemove(LabelModelParcelableItem item) {
final View labelView = getChipView(item);
View countView = getCounterView();
if (countView != null) {
assetLabelsContainer.removeView(countView);
visibleSelectedList.add(item);
assetLabelsContainer.addView(labelView);
addCounterView();
} else {
visibleSelectedList.add(item);
assetLabelsContainer.addView(labelView);
}
}
private View getCounterView() {
View countView =
assetLabelsContainer.getFlexItemAt(assetLabelsContainer.getFlexItemCount() - 1);
if (null != countView) {
LabelModelParcelableItem item = (LabelModelParcelableItem) countView.getTag();
if (item != null && item.getLabelId() == -1) {
return countView;
}
}
return null;
}
private void showLabelList(ArrayList<LabelModelParcelableItem> selectedLabels) {
for (LabelModelParcelableItem item : selectedLabels) {
addViewToFlex(item);
assetLabelsContainer.post(() -> assetLabelsContainer.requestLayout());
}
}
public void addSelectedLabel(Parcelable label) {
addViewToFlex((LabelModelParcelableItem) label);
}
public ArrayList<LabelModelParcelableItem> getSelectedLabels() {
return selectedLabels;
}
public List<Parcelable> getUpdatedLabelList(List<? extends Parcelable> newParcelableList) {
if (null != newParcelableList && !newParcelableList.isEmpty()) {
newParcelableList.removeAll(getSelectedLabels());
return new ArrayList<>(newParcelableList);
} else {
return new ArrayList<>();
}
}
public void labelUpdateList(List dataList) {
getSearchAdapter().clearAndUpdateList(dataList);
}
#Override
public void onBackButtonPressed() {
setActivityResult(getSelectedLabels());
}
public void setActivityResult(ArrayList<? extends Parcelable> searchableItem) {
setResult(RESULT_OK, new Intent().putParcelableArrayListExtra(SEARCH_RESULT, searchableItem));
super.onBackButtonPressed();
}
public void addDisposable(Disposable disposable) {
if (null == disposables) {
disposables = new CompositeDisposable();
}
disposables.add(disposable);
}
#Override
public void onDestroy() {
if (disposables != null && !disposables.isDisposed()) {
disposables.clear();
}
super.onDestroy();
}
private void showLabelContainerScreen(List<? extends Parcelable> labels) {
Intent intent = new Intent(this, ViewLabelsActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(
LabelSelectionActivity.ARGUMENT_KEY, (ArrayList<? extends Parcelable>) labels);
intent.putExtras(bundle);
startActivityForResult(intent, LabelSelectionActivity.VIEW_ALL_LABEL_CODE);
}
#Override
public void onBackPressed() {
if (!getSelectedLabels().isEmpty()) {
Intent intent = new Intent();
intent.putParcelableArrayListExtra(
SELECTED_LABEL_ITEMS, (ArrayList<? extends Parcelable>) getSelectedLabels());
setResult(Activity.RESULT_OK, intent);
} else {
this.finish();
}
super.onBackPressed();
}
#OnClick(R.id.navBarBack)
public void onBackButton() {
onBackPressed();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != LabelSelectionActivity.VIEW_ALL_LABEL_CODE) {
return;
}
if (data == null) {
return;
}
if (resultCode != RESULT_OK) {
return;
}
if (!data.hasExtra(SELECTED_LABEL_ITEMS)) {
return;
}
clearLabelList();
ArrayList<LabelModelParcelableItem> selectedLabels =
data.getParcelableArrayListExtra(SELECTED_LABEL_ITEMS);
showLabelList(selectedLabels);
updateAfterViewAllLabels(selectedLabels);
}
private void updateAfterViewAllLabels(ArrayList<LabelModelParcelableItem> labelsAfterRemoved) {
ArrayList<LabelModelParcelableItem> listOfRemovedLabels = new ArrayList<>(getSelectedLabels());
listOfRemovedLabels.removeAll(labelsAfterRemoved);
for (LabelModelParcelableItem item : labelsAfterRemoved) {
//removeViewFormFlex(item);
}
}
public void removeViewFormFlex(View view, LabelModelParcelableItem item) {
if (selectedLabels.remove(item)) {
if (selectedLabels.isEmpty()) {
assetLabelsContainer.removeAllViews();
} else {
visibleSelectedList.remove(item);
assetLabelsContainer.removeView(view);
}
updatedLabelAfterRemove();
Comparator<LabelModelParcelableItem> compareByName =
(o1, o2) -> o1.getLabelName().compareTo(o2.getLabelName());
getSearchAdapter().addLabelItemToList(item, compareByName);
}
}
}
As per above code it look like below image
try to measure the height of FlexboxLayout after each flexboxLayout.addView(view) and if the width increased that is mean you are in second line.
I have written the following code to set the String of fragment. By using startActivityForResult I am getting the value and set the to fragment string i.e (firstString, secondString)
But the problem is that whenever I call startActivityForResult the fragment is recreated and the previous data is lost. For example when I set secondString than the value of firstString is lost.
I have referred to few answers to save and restore the fragment data, but unable to do so.
boolean isEditing = true;
LinearLayout first_layout, second_layout;
TextView first_textview, second_textview;
String firstString, secondString;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_profile);
if(savedInstanceState!=null)
{
if(savedInstanceState.getBoolean("isEditing",false))
{
Log.e("onSaveInstanceState","Restored");
isEditing=true;
firstString = savedInstanceState.getString(firstString);
secondString = savedInstanceState.getString(secondString);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.mf_postload, container, false);
// Linearlayout
first_layout = (LinearLayout) view.findViewById(R.id.payment_layout_MF_PostLoad);
second_layout = (LinearLayout) view.findViewById(R.id.remark_layout_MF_PostLoad);
// TextView
first_textview = (TextView) view.findViewById(R.id.payment_MF_PostLoad);
second_textview = (TextView) view.findViewById(R.id.remark_MF_PostLoad);
first_textview.setText(firstString);
second_textview.setText(firstString);
// Listner
first_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity().getApplicationContext(), Remark.class);
Integer requestCode = 1;
intent.putExtra("requestCode", requestCode);
startActivityForResult(intent, requestCode);
}
});
second_layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity().getApplicationContext(), Remark.class);
Integer requestCode = 2;
intent.putExtra("requestCode", requestCode);
startActivityForResult(intent, requestCode);
}
});
return view;
}
#Override
public void onSaveInstanceState(Bundle bundle)
{
super.onSaveInstanceState(bundle);
Log.e("onSaveInstanceState","Called");
try
{
if(isEditing)
{
bundle.putBoolean("isEditing",true);
bundle.putString("firstString",firstString);
bundle.putString("secondString",secondString);
Log.e("onSaveInstanceState","Called and Saved");
}
else
{
bundle.putBoolean("isEditing",false);
Log.e("onSaveInstanceState","Called and not Saved");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
// Call Back method to get the Message form other Activity
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// First
if (requestCode == 1) {
if (resultCode == Activity.RESULT_OK && data != null) {
firstString = data.getStringExtra("remark_string");
first_textview.setText(firstString);
}
}
// Second
if (requestCode == 2) {
if (resultCode == Activity.RESULT_OK && data != null) {
secondString = data.getStringExtra("remark_string");
second_textview.setText(secondString);
}
}
}
Here is the overriding of onSaveInstance
//Like you see here am using a boolean to determine if i need to save the variable of not
//because if i am finishing the activity normally and its not the case where system kills it
//so i dont need to save these and if case that this boolean is true than the system is
//killing my activity and i need to save the values
#Override
public void onSaveInstanceState(Bundle bundle)
{
super.onSaveInstanceState(bundle);
Log.e("onSaveInstanceState","Called");
try
{
if(isEditing)
{
bundle.putBoolean("isEditing",true);
bundle.putString("photoFile", photoFile.getAbsoluteFile()+"");
bundle.putString("birthday",birthdayText.getText().toString());
bundle.putString("phone",phoneText.getText().toString());
bundle.putString("gender",genderText.getText().toString());
bundle.putString("martial",martialText.getText().toString());
bundle.putString("email",emailText.getText().toString());
bundle.putString("first",editFirstName.getText().toString());
bundle.putString("last",editLastName.getText().toString());
Log.e("onSaveInstanceState","Called and Saved");
}
else
{
bundle.putBoolean("isEditing",false);
Log.e("onSaveInstanceState","Called and not Saved");
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
Here is the overriding of onCreate
//In onCreate am checking if i need to restore these values or not according
//to what i saved and in this way its like my activity never got killed
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
if(savedInstanceState!=null)
{
if(savedInstanceState.getBoolean("isEditing",false))
{
Log.e("onSaveInstanceState","Restored");
isEditing=true;
photoFile =new File(savedInstanceState.getString("photoFile"),"") ;
birthdayText.setText(savedInstanceState.getString("birthday","1/1/1980"));
phoneText.setText(savedInstanceState.getString("phone",""));
genderText.setText(savedInstanceState.getString("gender","Please specify gender"));
martialText.setText(savedInstanceState.getString("martial","Please specify marital"));
emailText.setText(savedInstanceState.getString("email",""));
editFirstName.setText(savedInstanceState.getString("first",""));
editLastName.setText(savedInstanceState.getString("last",""));
}
}
}
After some debugging I have solved, Thanks Haider.
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
Log.e("onSaveInstanceState", "Called");
bundle.putString("firstString", firstString);
bundle.putString("secondString", secondString);
Log.e("onSaveInstanceState", "Called and Saved" + firstString + " " + secondString);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.e("onSaveInstanceState", "Restored Called");
if (savedInstanceState != null) {
firstString = savedInstanceState.getString("firstString");
secondString = savedInstanceState.getString("secondString");
Log.e("onSaveInstanceState", "Restored" + firstString + " " + secondString);
}
}
I am using the ZXing library, fully integrated with jar files, in my Android app and have the following problem:
Problem:
After scanning a barcode, the scanned image stays on top on the live camera feed at about 50% transparency for about 1-2 seconds.
Question:
Is there any way to have just the scanned image appear at 0% transparency, instead of the strange overlay? Or, even better, can it show a custom fragment?
Thank you.
Code: [w/o unrelated parts]
public static void initiateScan(Fragment fragment) {
IntentIntegrator ii = new IntentIntegrator(fragment);
DisplayMetrics dm = fragment.getResources().getDisplayMetrics();
ii.addExtra("SCAN_WIDTH", dm.heightPixels);
ii.addExtra("SCAN_HEIGHT", dm.widthPixels / 4);
ii.addExtra("SCAN_MODE", "ONE_D_MODE");
List<String> c = new ArrayList<String>();
c.add("CODE_39");
ii.initiateScan(c, -1);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==IntentIntegrator.REQUEST_CODE) { // scan from ZXing
String raw_vin=null;
String vin = null;
boolean success=false;
IntentResult result = IntentIntegrator.parseActivityResult(requestCode,
resultCode, data);
if(result!=null)
{
String content = result.getContents();
if(content!=null)
{
raw_vin=content;
vin=raw_vin;
success=true;
}
}
}
}
Example:
Here is what I have in the build.gradle file for dependencies:
compile 'com.google.zxing:core:3.2.1'
compile 'com.journeyapps:zxing-android-embedded:3.0.3#aar'
Try this in the initiateScan method:
public static void initiateScan(Fragment fragment) {
IntentIntegrator ii = IntentIntegrator.forSupportFragment(fragment);
DisplayMetrics dm = fragment.getResources().getDisplayMetrics();
ii.addExtra("SCAN_WIDTH", dm.heightPixels);
ii.addExtra("SCAN_HEIGHT", dm.widthPixels / 4);
ii.addExtra("SCAN_MODE", "ONE_D_MODE");
ii.initiateScan(Collections.singletonList("CODE_39"));
}
Let me know how that works for you.
I am not able to explain why this problem happen, but I am using ZXing for my barcode scanner application without 50% transparent as you. The following is my solution:
Layout:
<com.journeyapps.barcodescanner.CompoundBarcodeView
android:id="#+id/barcode_scanner"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_margin="2dp">
</com.journeyapps.barcodescanner.CompoundBarcodeView>
In fragment:
private CompoundBarcodeView barcodeView;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
View v = inflater.inflate(R.layout.webservice_layout, container, false);
barcodeView = (CompoundBarcodeView) v.findViewById(R.id.barcode_scanner);
barcodeView.decodeContinuous(callback);
......
}
Callback function:
private BarcodeCallback callback = new BarcodeCallback() {
#Override
public void barcodeResult(BarcodeResult result) {
if (SOAP_ACTION.equals("") || SOAP_METHOD.equals("") || soapProperty.equals("")) {
barcodeView.pause();
} else {
if (result.getText() != null) {
barcodeView.setStatusText(result.getText());
barcodeView.pause();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
barcodeView.resume();
}
}, 1000);
}
}
}
};
Hope this help!
My approach is the following:
//start the scanning
public void startQRCodeScanning() {
IntentIntegrator integrator = IntentIntegrator.forFragment(this);
integrator.setCaptureActivity(ScanActivity);
integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES);
integrator.setBeepEnabled(false);
integrator.setOrientationLocked(true);
integrator.initiateScan();
}
//onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (result != null) {
if (result.getContents() == null) {
Log.d(TAG, "Cancelled scan");
//we want to finish the current activity
//as it does not make sense to do anything else
finishActivity();
} else {
Log.d(TAG, "Scanned " + result.getContents());
setConnectionString(result.getContents());
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
//next I have the QRCodeScanningActivity
public class QRCodeScannerActivity extends Activity {
private CaptureManager capture;
private CompoundBarcodeView barcodeScannerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_scanner);
if (getResources().getBoolean(R.bool.portrait_only)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
ActionBar actionBar = getActionBar();
if (actionBar != null) {
actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
}
barcodeScannerView = (CompoundBarcodeView)findViewById(R.id.zxing_barcode_scanner);
capture = new CaptureManager(this, barcodeScannerView);
capture.initializeFromIntent(getIntent(), savedInstanceState);
capture.decode();
}
#Override
protected void onResume() {
super.onResume();
capture.onResume();
}
#Override
protected void onPause() {
super.onPause();
capture.onPause();
}
#Override
protected void onDestroy() {
super.onDestroy();
capture.onDestroy();
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
capture.onSaveInstanceState(outState);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return barcodeScannerView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
}
//Next you need to define the layouts and everything.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black">
<com.journeyapps.barcodescanner.CompoundBarcodeView
android:id="#+id/zxing_barcode_scanner"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:zxing_scanner_layout="#layout/barcode_scanner_layout"/>
</FrameLayout>
</RelativeLayout>
Sorry for my English
This is not question. I post it because this is may be helpful for someone. My solution based on the solution which was placed here several months ago, but later its author removed it. But there were several bugs in his solution, and I tried to fix them.
My solution works fine even if you'll open another app while there is a long-executed task executed in your app, then change screen orientation in another app, and return to your app after task will be finished.
If you'll find a bug in my solution, please let me know.
Have a look:
public interface AbleToStartTask {
void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task);
void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task, Integer titleId);
}
public interface TaskResultReceiver {
void onTaskResult(int requestCode, int resultCode, Serializable result);
}
public abstract class TaskNotBeInterruptedDuringConfigurationChange extends AsyncTask<Void, Void, Serializable> {
private TaskFragment fragment;
final void setFragment(TaskFragment fragment) {
this.fragment = fragment;
}
#Override
protected final void onPostExecute(Serializable result) {
if (fragment != null) {
fragment.onTaskFinished(result);
}
}
}
public class TaskFragment extends android.support.v4.app.DialogFragment {
public static final Integer NO_TITLE_ID = null;
private boolean isNeedToReturnResult = false;
private boolean isResultReturned = false;
private TaskNotBeInterruptedDuringConfigurationChange task;
private int resultCode = Activity.RESULT_CANCELED;
private Serializable result = null;
private Integer titleId;
public void setTask(TaskNotBeInterruptedDuringConfigurationChange task) {
task.setFragment(this);
this.task = task;
}
public void setTitle(Integer titleId) {
this.titleId = titleId;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
if (savedInstanceState == null && task != null) {
task.execute();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
initDialog();
return inflater.inflate(R.layout.fragment_task, container);
}
private void initDialog() {
if (titleId == NO_TITLE_ID) {
getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);
} else {
getDialog().setTitle(titleId);
}
getDialog().setCanceledOnTouchOutside(false);
}
#Override
public void onDestroyView() {
if ((getDialog() != null) && getRetainInstance()) {
getDialog().setDismissMessage(null);
}
super.onDestroyView();
}
#Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (task != null) {
task.cancel(false);
}
tryReturnResult();
}
private void tryReturnResult() {
task = null;
if (isResultReturned) {
return;
}
if (getTargetFragment() != null) {
returnResult();
}
}
private void returnResult() {
isResultReturned = true;
FragmentAbleToStartTask ableToStartTask = (FragmentAbleToStartTask) getTargetFragment();
if (ableToStartTask.isAbleToReceiveResult()) {
ableToStartTask.onResult(FragmentAbleToStartTask.TASK_FRAGMENT_TARGET, resultCode, result);
isNeedToReturnResult = false;
finishFragment();
} else {
isNeedToReturnResult = true;
}
}
private void finishFragment() {
if (isResumed()) {
dismiss();
}
}
#Override
public void onResume() {
super.onResume();
if (task == null) {
dismiss();
}
}
public void onTaskFinished(Serializable result) {
setResult(Activity.RESULT_OK, result);
tryReturnResult();
}
private void setResult(int resultCode, Serializable result) {
this.resultCode = resultCode;
this.result = result;
}
public void getResultIfItReturnedDuringPause() {
if (isNeedToReturnResult) {
returnResult();
}
}
}
public abstract class FragmentAbleToStartTask extends android.support.v4.app.Fragment
implements AbleToStartTask, TaskResultReceiver {
public static final int TASK_FRAGMENT_TARGET = 123;
protected static final String TAG_TASK_FRAGMENT = FragmentAbleToStartTask.class.getName() + "TAG_TASK_FRAGMENT";
private static final String KEY_TASK_REQUEST_CODE = "KEY_TASK_REQUEST_CODE";
private FragmentManager fragmentManager;
private int taskRequestCode;
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_TASK_REQUEST_CODE, taskRequestCode);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
restoreState(savedInstanceState);
}
fragmentManager = getFragmentManager();
TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
taskFragment.setTargetFragment(this, TASK_FRAGMENT_TARGET);
}
}
private void restoreState(Bundle savedInstanceState) {
taskRequestCode = savedInstanceState.getInt(KEY_TASK_REQUEST_CODE);
}
private TaskFragment getTaskFragment() {
return (TaskFragment) fragmentManager.findFragmentByTag(TAG_TASK_FRAGMENT);
}
public void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task) {
startTask(requestCode, task, TaskFragment.NO_TITLE_ID);
}
public void startTask(int requestCode, TaskNotBeInterruptedDuringConfigurationChange task, Integer title) {
this.taskRequestCode = requestCode;
TaskFragment taskFragment = new TaskFragment();
taskFragment.setTitle(title);
taskFragment.setTask(task);
taskFragment.setTargetFragment(this, TASK_FRAGMENT_TARGET);
startFragment(taskFragment);
}
private void startFragment(TaskFragment taskFragment) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment previousTaskFragment = fragmentManager.findFragmentByTag(TAG_TASK_FRAGMENT);
if (previousTaskFragment != null) {
transaction.remove(previousTaskFragment);
}
transaction.add(taskFragment, TAG_TASK_FRAGMENT);
transaction.commit();
}
public final void onResult(int requestCode, int resultCode, Serializable result) {
if ((requestCode == TASK_FRAGMENT_TARGET)) {
onTaskResult(this.taskRequestCode, resultCode, result);
}
}
public abstract void onTaskResult(int requestCode, int resultCode, Serializable result);
public boolean isAbleToReceiveResult() {
return isResumed();
}
#Override
public void onResume() {
super.onResume();
TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
taskFragment.getResultIfItReturnedDuringPause();
}
}
}
So each inheritor of FragmentAbleToStartTask must implement onTaskResult(requestCode, resultCode, result). In onTaskResult() - requestCode is value that was passed to startTask(requestCode, ...). And note, that this fragment is able to execute only one task at the same time.
Example of TaskNotBeInterruptedDuringConfigurationChange's subclass:
public class SomeLongTask extends TaskNotBeInterruptedDuringConfigurationChange {
private final Context context;
private final Worker worker;
public SomeLongTask (Worker worker, Context context) {
this.worker= worker;
this.context = context;
}
#Override
protected Serializable doInBackground(Void... voids) {
return (Serializable) worker.work(context);
}
}
And example of FragmentAbleToStartTask's subclass:
public class NameListFragment extends FragmentAbleToStartTask {
private static final int TASK_REQUEST_CODE_RECEIVING_NAMES = 461;
private static final String KEY_PATTERN = "KEY_PATTERN";
private static final String KEY_NAMES = "KEY_NAMES";
private List<String> names;
private ListView listView;
public static Fragment newInstance(String patternToSearchNames) {
Fragment fragment = new NameListFragment();
Bundle args = new Bundle();
args.putString(KEY_PATTERN, patternToSearchNames);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.example_list_fragment, null);
listView = (ListView) root.findViewById(R.id.listView);
return root;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState == null) {
startTaskReceivingNames();
} else {
restoreState(savedInstanceState);
}
}
// !!! Key Point
private void startTaskReceivingNames() {
String pattern = getArguments().getString(KEY_PATTERN);
TaskNotBeInterruptedDuringConfigurationChange task = new NamesReceiverTask(getActivity(), pattern);
startTask(TASK_REQUEST_CODE_RECEIVING_NAMES, task);
}
private void restoreState(Bundle savedInstanceState) {
names = (List<String>) savedInstanceState.getString(KEY_NAMES);
if (names != null) {
initList();
}
}
private void initList() {
setEmptyListView();
ArrayList<String> adapter = new ArrayList<String>(getActivity(), android.R.layout.simple_list_item_1, names);
listView.setAdapter(adapter);
}
private void setEmptyListView() {
View emptyListView = getView().findViewById(R.id.emptyListView);
listView.setEmptyView(emptyListView);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(KEY_NAMES, (Serializable) names);
}
// !!! Key Point
#Override
public void onTaskResult(int requestCode, int resultCode, Serializable result) {
if (requestCode == TASK_REQUEST_CODE_RECEIVING_NAMES) {
onReceivingNamesFinished(resultCode, result);
}
}
private void onReceivingNamesFinished(int resultCode, Serializable result) {
if (resultCode != Activity.RESULT_OK) {
getActivity().finish();
return;
}
this.names = (List<String>) result;
initList();
}
}