How do I retrieve an image from Firebase Storage and show it? Getting "No content provider" error - android-imageview

My app is saving images in Firebase Storage, but I'm having trouble retrieving and viewing them. Images are uploaded fine, into a folder called "images".
Each image is associated with a Box. The boxes collection in the database looks like this:
boxes > key1 > name: Box 1 name
> uid: xxxxxxxxx (user id of Box creator)
> image: "images/box1image.jpg"
> key2 > name: Box 2 name
> uid: yyyyyyyyy
> image: "images/box2image.jpg"
I want to retrieve the image and show it in a DialogFragment. Currently the fragment layout (dialog_fragment_show_box) looks like this (I've taken out layout_width etc for brevity):
<android.support.constraint.ConstraintLayout >
<ImageView
android:id="#+id/iv_box_image" />
<TextView
android:id="#+id/tv_box_name"
app:layout_constraintTop_toBottomOf="#id/iv_box_image" />
</android.support.constraint.ConstraintLayout>
Now, when the DialogFragment loads, I want to pass in the Box, and display its name and associated image. Box.java contains:
public class HybridBox {
private String name, uid, key, url;
// CONSTRUCTOR
public HybridBox() {}
// GETTERS
public String getName() { return name; }
public String getUrl() { return url; }
public String getUid() { return this.uid; }
public String getKey() { return key; }
// SETTERS
public void setName(String thisName) { this.name = thisName; }
public void setUrl(String thisUrl) { this.url = thisUrl; }
public void setUid(String thisUid) { this.uid = thisUid; }
public void setKey(String thisKey) { this.key = thisKey; }
}
The Box is retrieved from the database with no problems, and passed into the DialogFragment, which is:
public class DialogFragmentShowBox extends DialogFragment {
private Context mContext;
private EditText mBoxName;
private ImageView mBoxImage;
private HybridBox mBox;
public DialogFragmentShowBox() {}
public static DialogFragmentShowBox newInstance() {
return new DialogFragmentShowBox();
}
#Override
public View onCreateView(
#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(
R.layout.dialog_fragment_show_box, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mBoxImage = view.findViewById(R.id.iv_box_image);
mBoxName = view.findViewById(R.id.tv_box_name);
show_details();
draw_iv();
}
// Pass in Box object
public void setBox(HybridBox box) {
mBox = box;
show_details();
draw_iv();
}
// Set up Context
public void setContext(Context context) { mContext = context; }
// Show details of the Box (currently just name)
private void show_details() {
if(mBox == null) return;
if(mBoxName != null) {
mBoxName(mBox.getName());
}
}
// Draw the Box image
private void draw_iv() {
if(mBox == null) return;
if(mBoxImage != null) {
FirebaseStorage mStorage = FirebaseStorage.getInstance();
final StorageReference mStorageRef = mStorage.getReference();
final String drawableUrl = mBox.getUrl();
if(drawableUrl != null) {
mStorageRef.child(mBox.getUrl())
.getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
// Got the download URL
ContentResolver res = mContext.getContentResolver();
try {
Bitmap bitmap
= MediaStore.Images.Media.getBitmap(
res,
uri);
mBoxImage.setImageBitmap(bitmap);
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
}
}
}
}
When I run this, I get the following warning, and the Box Image is blank:
W/System.err: java.io.FileNotFoundException: No content provider: https://firebasestorage.googleapis.com/v0/b/tickybox-d8888.appspot.com/o/images%2F561e1408-3b17-4eaa-b0ff-d3b00479d1c0.jpg?alt=media&token=9656ea28-2493-447b-aa30-9dbc4c39b3fc
W/System.err: at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1396)
W/System.err: at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1247)
W/System.err: at android.content.ContentResolver.openInputStream(ContentResolver.java:967)
at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:888)
at sharongilmore.tickybox.fragments.dialogFragments.DialogFragmentShowBox$6.onSuccess(DialogFragmentShowBox.java:295)
W/System.err: at sharongilmore.tickybox.fragments.dialogFragments.DialogFragmentShowBox$6.onSuccess(DialogFragmentShowBox.java:288)
at com.google.android.gms.tasks.zzn.run(Unknown Source:4)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6494)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
The uri being passed into the success listener is in the form:
https://firebasestorage.googleapis.com/v0/b/tickybox-d8888.appspot.com/o/images%2F561e1408-3b17-4eaa-b0ff-d3b00479d1c0.jpg?alt=media&token=9656ea28-2493-447b-aa30-9dbc4c39b3fc
(I've changed some of the url to post here, but when I go to it in a browser it shows the correct image so I think it's ok).
The ContentResolver res is populated; not sure what it's meant to be, but in the variable list in the debugger the first line is:
res = {ContextImpl$ApplicationContentResolver#8456}
Any ideas what's going wrong here?

This answer can help your situation brother!
Presumably, currentTrack has a File object. If so, replace Uri.parse(currentTrack.getPath()) with currentTrack.getUri(), where you implement getUri() to return the value of Uri.fromFile() for the File.
This solves your immediate problem, which is that you have created an invalid Uri, as it has no scheme. It also sets you up to deal with Uri types that are not files (e.g., content Uri values) that you may wind up needing in the future.
Copied!

I achieved this as follows:
FirebaseStorage mStorage = FirebaseStorage.getInstance();
final StorageReference mStorageRef = mStorage.getReference();
mStorageRef.child(mBox.getUrl()).getDownloadUrl()
.addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Glide.with(getContext()).load(uri).into(mBoxImage);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});

Related

IndexOutOfBoundsException: Inconsistency detected error while scrolling

I have a list which is coming from an API which I'm storing in db. Now I'm fetching list from db and showing it in recyclerview. Then removing all data one-by-one from recyclerview listing. This process is being repeated every 10 seconds using JobScheduler. While I'm scrolling, I'm getting this error. I've tried many solutions given in various SO posts like this but it didn't worked.
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionMessageViewHolder{c2276c4 position=31 id=-1, oldPos=-1, pLpos:-1 no parent} androidx.recyclerview.widget.RecyclerView{5223262 VFED..... .F...... 0,0-720,1120 #7f0900d4 app:id/recycler}, adapter:com.sam.testapp.MessageAdapter#4b57ff3, layout:androidx.recyclerview.widget.LinearLayoutManager#735b4b0, context:com.sam.testapp.MainActivity#e780e56
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {
private List<Message> messageList;
public MessageAdapter(List<Message> messageList) {
this.messageList = messageList;
}
protected static class MessageViewHolder extends RecyclerView.ViewHolder {
private ConstraintLayout root;
private TextView umfiTXT, msgTXT;
MessageViewHolder(View view) {
super(view);
root = view.findViewById(R.id.root);
umfiTXT = view.findViewById(R.id.umfiTXT);
msgTXT = view.findViewById(R.id.msgTXT);
}
}
#NonNull
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MessageViewHolder((LayoutInflater.from(parent.getContext())).inflate(R.layout.row_msg_list, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MessageViewHolder holder, int position) {
try {
holder.umfiTXT.setText("UMFI: " + messageList.get(position).getMessageUMFI());
holder.msgTXT.setText("Message: " + messageList.get(position).getMessageTxt());
}catch(Exception e) {
e.printStackTrace();
}
}
#Override
public int getItemCount() {
try {
if(messageList.isEmpty())
return 0;
else
return messageList.size();
}catch(Exception e) {
return 0;
}
}
private void clearData() {
this.messageList.clear();
notifyDataSetChanged();
}
public void setData(List<Message> data) {
clearData();
this.messageList.addAll(data);
notifyDataSetChanged();
}
}
public class MainActivity extends AppCompatActivity {
private ArrayList<Message> messageList;
private RecyclerView recycler;
private AppCompatTextView emptyTxt;
private MessageAdapter messageAdapter;
private SqliteDatabase database;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
messageList = new ArrayList<>();
recycler = findViewById(R.id.recycler);
emptyTxt = findViewById(R.id.emptyTxt);
database = new SqliteDatabase(MainActivity.this);
recycler.setLayoutManager(new LinearLayoutManager(this));
messageAdapter = new MessageAdapter(messageList);
recycler.setAdapter(messageAdapter);
recycler.setItemAnimator(null);
RxBus.subscribe((Consumer<Object>) o -> {
if (o instanceof RxEvent) {
RxEvent data = (RxEvent) o;
System.out.println("SAM: status: " + data.getStatus());
if (data.getStatus() == 1) {
fetchMessageList();
}
}
});
}
private void fetchMessageList(){
messageList.clear();
AndroidNetworking.get(Util.url)
.setPriority(Priority.IMMEDIATE)
.build()
.getAsJSONArray(new JSONArrayRequestListener() {
#Override
public void onResponse(JSONArray jsonArray) {
try{
System.out.println("SAM: fetchMessageList jsonArray: "+jsonArray);
ArrayList<Message> templist = new ArrayList<>();
for(int i=0; i<jsonArray.length(); i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
templist.add(new Message(jsonObject.getString("umfi"), jsonObject.getString("msg_to"), jsonObject.getString("msg_text")));
}
storeListinDB(templist);
}catch(Exception e){
e.printStackTrace();
}
}
#Override
public void onError(ANError error) {
System.out.println("SAM: fetchMessageList onError: "+error.getErrorBody());
}
});
}
private void storeListinDB(ArrayList<Message> templist){
database.insertArrayData(templist);
showList();
}
private void showList(){
try{
//recycler.getRecycledViewPool().clear();
if(messageList.size()>0){
emptyTxt.setVisibility(View.GONE);
messageAdapter.notifyDataSetChanged();
}else{
emptyTxt.setVisibility(View.VISIBLE);
ArrayList<Message> templist = new ArrayList<>();
templist = database.fetchMessageList();
messageAdapter.setData(templist);
System.out.println("SAM: templist size: "+templist.size());
}
System.out.println("SAM: messageList size: "+messageList.size());
//removeAll();
}catch(Exception e){
e.printStackTrace();
}
}
}
You pass your messageList to the adapter, so the messageList in the adapter and in the activity are the same object references. Then, as I understand, somehow method fetchMessageList is called, it's where the problem appears. You call .clear() on your list and start an asynchronous operation to fetch a new list, to then synchronously post it to your adapter.
The thing is, after you have cleared your list, your adapter keeps the reference to an empty list now, without being notified about the changes. The adapter still "thinks" that your list is the same size as it was before, so when you scroll the RecyclerView, it tries to call at least onBindViewHolder for new appearing items. But, as the list is empty, it throws IndexOutOfBoundsException.
You could try to notify the adapter about the changes immediately after calling messageList.clear(), but it seems to me that just deleting this clearing will solve the problem.
private void fetchMessageList(){
//messageList.clear(); <- delete this
AndroidNetworking.get(Util.url)
...
}

Android volley singleton for JSON and image

Intially i was using volley mainly for JSONObject. the following was my singleton
package com.simha.yatras;
import android.app.Application;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
public class MyApplication extends Application {
private RequestQueue mRequestQueue;
private static MyApplication mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApplication getInstance() {
return mInstance;
}
public RequestQueue getReqQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToReqQueue(Request<T> req, String tag) {
getReqQueue().add(req);
}
public <T> void addToReqQueue(Request<T> req) {
getReqQueue().add(req);
}
public void cancelPendingReq(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
Now i want to use volley for bitmap imagerequest. I want the images to be cached so that i need not load them everytime.
So what should be the singleton code be.
You can use Volley provide ImageRequest class:
ImageView mImageView;
String url = "http://i.imgur.com/7spzG.png";
mImageView = (ImageView) findViewById(R.id.myImage);
// Retrieves an image specified by the URL, displays it in the UI.
ImageRequest request = new ImageRequest(url,
new Response.Listener<Bitmap>() {
#Override
public void onResponse(Bitmap bitmap) {
mImageView.setImageBitmap(bitmap);
}
}, 0, 0, null,
new Response.ErrorListener() {
public void onErrorResponse(VolleyError error) {
mImageView.setImageResource(R.drawable.image_load_error);
}
});
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(request);## Heading ##

Espresso match selected spinner text

Following the answer here, I try to check whether a certain spinner text is selected. The spinner appears in a dialog, so I tried:
onView(withId(R.id.package_spinner)).inRoot(isDialog()).check(matches(withSpinnerText(containsString("sachet"))));
However this does not work and I get the following error message:
android.support.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError:
'with text: a string containing "sachet"' doesn't match the selected
view.
Expected: with text: a string containing "sachet"
Got: "AppCompatSpinner{id=2131624039, res-name=package_spinner, visibility=VISIBLE, width=620, height=75, has-focus=false,
has-focusable=true, has-window-focus=true, is-clickable=true,
is-enabled=true, is-focused=false, is-focusable=true,
is-layout-requested=false, is-selected=false,
root-is-layout-requested=false, has-input-connection=false, x=0.0,
y=75.0, child-count=1}"
Does "is-selected=false" mean, that the spinner it found is not selected? This is running on a real device (not emulator) with API 18. During the Espresso run and also when testing manually, the spinner is correctly set to "sachet". Why does Espresso have a problem with it?
Not sure whether this is relevant, but the spinner is for objects of type:
public class PackageType {
private int id;
private String name;
private final Context ctx;
public PackageType(Context context) { this.ctx=context; }
public PackageType(String name, Context context) {
super();
this.ctx = context;
setName(name);
}
// setters
public void setId(int i) { this.id = i; }
public void setName(String u) {
this.name = u;
}
// getters
public int getId() { return id; }
public String getName() { return name; }
}
and the spinner adapter looks like:
class SpinnerPackageTypeAdapter extends ArrayAdapter<PackageType> {
private final List<PackageType> packageTypes;
private final Context mContext;
public SpinnerPackageTypeAdapter(Context context, int resource, List<PackageType> packageTypes) {
super(context, resource, packageTypes);
this.mContext = context;
this.packageTypes = packageTypes;
}
public PackageType getItem(int position) { return packageTypes.get(position); }
public long getItemId(int position) { return position; }
// this is for the passive state of the spinner
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// use dynamically created TextView, but could reference custom layout
TextView label = new TextView(mContext);
label.setTextColor(Color.BLACK);
label.setTextSize(mContext.getResources().getDimension(R.dimen.list_row_font_size));
label.setGravity(Gravity.CENTER);
label.setText(getItem(position).getName());
return label;
}
// this is for the chooser dropped down spinner
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
TextView label = (TextView) View.inflate(mContext,R.layout.row_spinner,null);
label.setText(getItem(position).getName());
return label;
}
}
I found the problem. In class PackageType I had to override the toString() method as (of course other versions are possible as long as "name" is in there):
#Override
public String toString() {
return "PackageType [id=" + id + ", name=" + name + "]";
}

How can I get friends pictore using by android-simple-facebook libraries

I'm using latest android-simple-facebook library
(https://github.com/sromku/android-simple-facebook)
and, want to get friends list with name, picture(profile image).
but i cann't get friends picture at all..
below is my code...
At LoginListener
private OnLoginListener mOnLoginListener = new OnLoginListener() {
#Override
public void onFail(String reason) {
Log.w(TAG, "Failed to login");
}
#Override
public void onException(Throwable throwable) {
Log.e(TAG, "Bad thing happened", throwable);
}
#Override
public void onThinking() {
// show progress bar or something to the user while login is
// happening
}
#Override
public void onLogin() {
PictureAttributes pictureAttributes = Attributes.createPictureAttributes();
pictureAttributes.setType(PictureType.NORMAL);
pictureAttributes.setHeight(500);
pictureAttributes.setWidth(500);
// change the state of the button or do whatever you want
Properties properties = new Properties.Builder()
.add(Properties.ID)
.add(Properties.LAST_NAME)
.add(Properties.PICTURE, pictureAttributes)
.add(Properties.BIRTHDAY).build();
mSimpleFacebook.getFriends(properties, mOnFriendsListener);
}
#Override
public void onNotAcceptingPermissions(Permission.Type type) {
}
};
and the friends listener
// get friends listener
private OnFriendsListener mOnFriendsListener = new OnFriendsListener() {
#Override
public void onFail(String reason) {
// insure that you are logged in before getting the friends
Log.w(TAG, reason);
}
#Override
public void onException(Throwable throwable) {
Log.e(TAG, "Bad thing happened", throwable);
}
#Override
public void onThinking() {
// show progress bar or something to the user while fetching profile
Log.i(TAG, "Thinking...");
}
#Override
public void onComplete(List<Profile> friends) {
for (Profile profile : friends) {
mLists.add(new FriendItem(profile.getName(), profile.getPicture()));
}
mAdapter = new FriendsListAdapter(getActivity());
mFriendsList.setAdapter(mAdapter);
}
};
but the profile object only contains id and name.
should i call get method with async?
or whatever else i can do with getFriends() methods.
The permission lists is likes:
Permission[] permissions = new Permission[] {
Permission.BASIC_INFO,
Permission.USER_CHECKINS,
Permission.USER_EVENTS,
Permission.USER_GROUPS,
Permission.USER_LIKES,
Permission.USER_PHOTOS,
Permission.USER_VIDEOS,
Permission.FRIENDS_EVENTS,
Permission.FRIENDS_PHOTOS,
Permission.PUBLISH_STREAM };
For some reason you have to override onComplete() method inside onLogin to handle with the things that you asked for.
Response will have everything that you asked for in the permissions builder.
I spent a huge amount of time to figure out this. Hope it helps :)
final OnLoginListener onLoginListener = new OnLoginListener() {
#Override
public void onLogin(String accessToken, List<Permission> acceptedPermissions, List<Permission> declinedPermissions) {
OnProfileListener onProfileListener = new OnProfileListener() {
#Override
public void onComplete(final Profile response) {
super.onComplete(response);
.
. // Your code in here`enter code here`
.
});
}
Plz try these permissions:
Permission.PUBLIC_PROFILE,
Permission.USER_BIRTHDAY

SurfaceView Tutorial problems

I found a tutorial and it looks like this:
package com.djrobotfreak.SVTest;
public class Tutorial2D extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
private TutorialThread _thread;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
_thread = new TutorialThread(getHolder(), this);
}
#Override
public void onDraw(Canvas canvas) {
Bitmap _scratch = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(_scratch, 10, 10, null);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
_thread.setRunning(true);
_thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_thread.setRunning(false);
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
class TutorialThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
public TutorialThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
#Override
public void run() {
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
_panel.onDraw(c);
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
and it does not work, no matter what I do. I am trying to convert my code to surfaceview but I cant find any surfaceview programs that even work (besides the android-provided ones). Does anyone know what the error even is saying?
Here is my logcat info: http://shrib.com/oJB5Bxqs
If you get a ClassNotFoundException, you should check the Manifest file.
Click on the Application tab and look on the botton right side under "Attributes for".
If there is a red X mark under your Class Name, then click on the "Name" link and locate the correct class to load.