Tuesday, February 28, 2017

Android: WebView shouldInterceptRequest not adding RequestProperties in the WebView

Leave a Comment

I am intercepting requests from the webview using shouldInterceptRequest

below is my code for returning my WebResourceResponse

@TargetApi(Build.VERSION_CODES.LOLLIPOP)     private static WebResourceResponse handleRequestViaUrlOnly(WebResourceRequest webResourceRequest){         String url = webResourceRequest.getUrl().toString();         Log.i("intercepting req....!!!", url);         String ext = MimeTypeMap.getFileExtensionFromUrl(url);         String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext);          try {             HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();             conn.setRequestProperty("Sample-Header", "hello");             conn.setDoOutput(true);             conn.setDoInput(true);             conn.setUseCaches(false);             return new WebResourceResponse(mime, "UTF-8", conn.getInputStream());         } catch (IOException e) {             e.printStackTrace();         }          return null;     } 

I call this method inside my CustomWebViewClient

class CustomWebViewClient extends WebViewClient {      @TargetApi(Build.VERSION_CODES.LOLLIPOP)     @Override     public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {         return handleRequestViaUrlOnly(request);     } } 

However, when I check the Request Headers from the WebView remote debugger in chrome://inspect/#devices.

The additional RequestProperty that I added is not present.

conn.setRequestProperty("Sample-Header", "hello"); 

The Sample-Header is not present in the Request Headers in the WebView.

Am I missing something? I'll appreciate any help.

0 Answers

Read More

Jwt tokens authorization is not working

Leave a Comment

I'm trying to create Jwt token authorization. For this purpose I have issuer part with the code like that:

public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) {     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});     Users user;     using (var db = new UserStore())     {         user = Task.Run(()=> db.FindUser(context.UserName, context.Password, context.ClientId)).Result;     }     if (user == null)     {         context.SetError("invalid_grant", "The user name or password is incorrect");         return Task.FromResult<object>(null);     }     var identity = new ClaimsIdentity("JWT");     identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));     identity.AddClaim(new Claim("sub", context.UserName));     identity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.Name));      var props = new AuthenticationProperties(new Dictionary<string, string>     {         {             "audience", context.ClientId ?? string.Empty         }     });     var ticket = new AuthenticationTicket(identity, props);     context.Validated(ticket);     return Task.FromResult<object>(null); } 

And "resource" part that should accept bearer token:

public void ConfigureOAuth(IAppBuilder app) {     var issuer = SiteGlobal.Issuer;     var audience = SiteGlobal.Audience;     var secret = TextEncodings.Base64Url.Decode(SiteGlobal.Secret);     app.UseJwtBearerAuthentication(     new JwtBearerAuthenticationOptions     {         AuthenticationMode = AuthenticationMode.Active,         AllowedAudiences = new[] { audience },         IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]         {             new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)         }     }); } 

As far as I can see issued token are valid (I did validation on jwt.io), so the problem is somehwere else. When I'm sending token in Postman with the call to controller protected by [Authorize] attribute it always return 401 code. Could you please advise how to fix this?

P.S. This is how I implement custom Jwt fortmat:

public string Protect(AuthenticationTicket data) {     if (data == null)     {         throw new ArgumentNullException("data");     }     string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;     if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");     Audience audience;     using (var store = new AudienceStore())     {         audience = Task.Run(()=> store.FindAudience(audienceId)).Result;     }     var symmetricKeyAsBase64 = audience.Base64Secret;     var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(symmetricKeyAsBase64));     var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);     var issued = data.Properties.IssuedUtc;     var expires = data.Properties.ExpiresUtc;     var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials);     var handler = new JwtSecurityTokenHandler();     var jwt = handler.WriteToken(token);     return jwt; } 

P.S. Guys, I'm so sorry, but I forgot to explain that "issuer" part of code that's standalone application, meanwhile "audience" is protected web api. That's two different appliactions running independently.

2 Answers

Answers 1

In Postman ensure you are sending the authorization header using the following format:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 

Postman Authorization Header

Ensure that you leave the Authorization tab set to Type: No Auth.

If you continue to have issues, set a breakpoint in your GrantResourceOwnerCredentials and see if it gets to that point. Also consider overriding the ValidateClientAuthentication method of OAuthAuthorizationServerProvider which should get called prior to GrantResourceOwnerCredentials if you want to debug earlier in the chain of events.

Answers 2

I have just tried to run demo project mentioned in SON Web Token in ASP.NET Web API 2 using Owin and all worked as expected.

I noticed that your implementation of Protect method differs quite a bit. I would suggest you to compare your implementation to an example given in the article. Try make that work first.

Also please make sure that issuer, audience and secret are same on both servers.

If you provide complete source code I can try to investigate more.

Read More

Dynamically adding Views in a RecyclerView only to current item

Leave a Comment

I'm dynamically adding Views to my items in a RecyclerView. These added Views should only be related to the item which they're added to, but I'm having a problem when I scroll. It seems the View is recycled and a new item is loaded, but those previously added views are still there, only now on the wrong item.

I'm assuming that it's just because the ViewHolder is being reused, so the added items show up again with a new item, when loaded.

How would one go about solving this?

10 Answers

Answers 1

You need to track what views have been added based on the backing data. I would probably add any necessary extra views in onBindViewHolder(), and remove any that might be present in onViewRecycled(). Then when you want to make one appear dynamically, change whatever variable you have tracking whether it should be visible, and call notifyItemChanged().

Answers 2

Based on this:

but those previously added Views are still there, but now on the wrong item.

Basically, as per the RecyclerView documentation, You have to reset the views everytime inside the onBindViewHolder() method,

so let say, you have a method that sets a view param if its your profile, so the code for the same goes as follows,

if (list.get(position).getId()==PreferenceManager.getUserID()) {   // do some view change here setViewParam(true); }else {   // reset the view change here setViewParam(false); } 

So what you're doing here is giving recycled ViewHolder a chance to reset. Do comment if you need help!

Answers 3

You can use this! setItemViewCacheSize(int size) Check here RecyclerViewDocumentation.

The offscreen view cache stays aware of changes in the attached adapter, allowing a LayoutManager to reuse those views unmodified without needing to return to the adapter to rebind them.

Answers 4

Save Information by tags for items with new child each time the Add newView operation occur. (In shared preference for example) Tag: create with item position onBindViewHolder.

... SharedPreference  sharedPref = getSharedPreference("text" + position, context); SharedPreference.Editor editor = sharedPref.edit(); editor.putString("view", "ImageView"); ... 

when load Adapter get this value and put default as null. I am not sure about its efficiency but i will work.

... String viewType = sharedPref.getString("view", null); //it will return ImageView  

if you know some possible viewTypes for example always going to be ImageView & TextView so with some if statement it will be ok.

if(viewType.equals("ImageVIew")){ item(position).addView(new ImageVIew(context)); } 

Good Luck

Answers 5

In your adapter class of your recyclerView, in the onBindViewHolder method, create another adapter and do the same methods for your new adapter.

The hierarchy will be,

mainRecyclerView -> item1(->childRecyclerView1) , item2(->childRecyclerView2), item3(->childRecyclerView3)

This way you can achieve what you want without wrong values to be viewed on wrong items.

Answers 6

You should take any Empty Layout like Linearlayout in your child item layout XML and then add views into that LinearLayout of your particular item in this way when you scroll List all of you child views which you have added to LinearLayout also scroll with that item .

Answers 7

First of all, can you share some more code please?

Second, why would you want to dynamically add new views on fly? Why don't you use different VIEWTYPE or just have those view already on your layout and just make them visible/invisible or visible/gone? (I believe it will be more efficient this way).

Let me remind you something about RecyclerView, yes when user is scrolling viewHolder are being reused (few of them can be created, even more than it needs to fill the screen). So if it happened that you added some views on "item A" and user scroll to "item Z", that viewHolder can be reused for that "item Z", hence the show up of the previously added views.

How can you solve that?

Well always check on every items if you need to add new views, if yes add them if not already added, else always remove those views (if present) to return to default viewHolder state (or whatever you call it).

Hope this will help you.

Answers 8

This was an old question of mine. A bounty was placed on it, hence the surge of popularity and the multiple new and irrelevant answers.

As stated in both my comment to this answer and @CQM's comment below my original question, the answer is to override the onViewRecycled() method and perform any needed operations there. This method is called when a view is recycled, and any cleanup operations can be done here.

Documentation on this method can be found here.

In my case, it was a matter of deleting the invisible TextView's attached to the view. The text itself had been deleted, but the view remained. If many invisible TextView's accumulate on the view and aren't properly recycled when scrolling, the scroll will begin to lag.

Answers 9

After adding every view you should call to 'notifyDataSetChanged()' to notify the changes and update the items.

Add your code for a better response

Answers 10

If you want to dynamically add change the views based on your data, recyclerview provides getItemViewType() function. and you can add like below ..

public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapter.MainViewHolder> {  public static final int TYPE_YOU = 1; public static final int TYPE_ME = 2; private List<ConversationModel> listItems;  public ConversationAdapter(List<ConversationModel> listItems) {     this.listItems = listItems; }  @Override public MainViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {      switch (viewType) {         case TYPE_YOU:             ChatYouBinding youBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.chat_you, parent, false);             return new MyViewHolderHeader(youBinding);         case TYPE_ME:             ChatMeBinding meBinding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.chat_me, parent, false);             return new MyViewHolderContent(meBinding);     }     ChatMeBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.chat_me, parent, false);     return new MyViewHolderContent(binding);  }  @Override public void onBindViewHolder(MainViewHolder holder, int position) {     ConversationModel conversationModel = listItems.get(position);       switch (holder.getItemViewType()) {         case TYPE_YOU:             MyViewHolderHeader headerHolder = (MyViewHolderHeader) holder;             headerHolder.chatYouBinding.setConversationyou(conversationModel);             break;         case TYPE_ME:             MyViewHolderContent contentHolder = (MyViewHolderContent) holder;             contentHolder.chatMeBinding.setConversation(conversationModel);              break;     }  }  @Override public int getItemCount() {     return listItems.size(); }   @Override public int getItemViewType(int position) {     return listItems.get(position).getMessageType().equals(Constants.ME) ? TYPE_ME : TYPE_YOU; }  class MainViewHolder extends RecyclerView.ViewHolder {     private MainViewHolder(View v) {         super(v);     } }  private class MyViewHolderContent extends MainViewHolder {     TextView cstmTxtChatUserName, cstmTxtChatMessage, cstmTxtChatSentTime;     ChatMeBinding chatMeBinding;      MyViewHolderContent(ChatMeBinding chatMeBinding) {         super(chatMeBinding.getRoot());         View view = chatMeBinding.getRoot();         this.cstmTxtChatUserName = (TextView) view.findViewById(R.id.cstmTxtChatUserName);         this.cstmTxtChatMessage = (CustomTextView) view.findViewById(R.id.cstmTxtChatMessage);         this.cstmTxtChatSentTime = (CustomTextView) view.findViewById(R.id.cstmTxtChatSentTime);         this.chatMeBinding = chatMeBinding;     } }  private class MyViewHolderHeader extends MainViewHolder {     TextView cstmTxtChatUserName, cstmTxtChatMessage, cstmTxtChatSentTime;     ChatYouBinding chatYouBinding;      MyViewHolderHeader(ChatYouBinding chatYouBinding) {         super(chatYouBinding.getRoot());         View view = chatYouBinding.getRoot();         this.cstmTxtChatUserName = (TextView) view.findViewById(R.id.cstmTxtChatUserName);         this.cstmTxtChatMessage = (CustomTextView) view.findViewById(R.id.cstmTxtChatMessage);         this.cstmTxtChatSentTime = (CustomTextView) view.findViewById(R.id.cstmTxtChatSentTime);         this.chatYouBinding = chatYouBinding;     } }   } 
Read More

How to correctly listen to navigation changes on UIWebView?

Leave a Comment

I noticed that the [UIWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:] is only called with traditional <a href="..."> links and not single page web app JavaScript navigations.

For example, if I go to m.facebook.com in a UIWebView and start tapping on the top nav (see screenshot below) it never triggers that delegate method.

The reason I want a method to hook into is because I want to add back and forward buttons above the UIWebView but I need to know when to enable/disable those buttons. Is there some other delegate method I should use to correctly listen to navigation changes?

Update: I should also note that mobile Safari correctly updates the back/forward button state on the Facebook mobile site, so I'd hope Apple exposes a way for developers to do this as well.

enter image description here

1 Answers

Answers 1

It seems like this is simply not supported by UIWebViewDelegate, nor WKNavigationDelegate (which I just tested with facebook). There are some options listed in this answer:

  1. javascript injection to capture the page changes (read up on history.pushState).
  2. KVO to watch for changes to the webview (like the scrollview resizing)
  3. watching for the title change, as above.
  4. checking for updates every time the user taps the view.

Update

I also tried this answer on facebook, which involves injecting javascript to catch XMLHTTPRequests during each new page load. It sort of does what you're asking for, but is a bit of a hack. Some of the facebook tabs don't work properly with a very simple implementation, but you may be able to work around the issues.

Read More

Sort Descriptor based on ordered to-many relationship

Leave a Comment

Description of my core data model:

  • Project and Issues entities
  • Project has an ordered one-to-many relationship to Issues named issues
  • Issue has one-to-one relationship with Project named parentProject

Here is my code to obtain issues:

let fetchRequest = NSFetchRequest(entityName: "Issue")     fetchRequest.predicate = NSPredicate(format: "parentProject CONTAINS[cd] %@", argumentArray: [project])     fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]      let frc = NSFetchedResultsController(         fetchRequest: fetchRequest,         managedObjectContext: dataManager.context,         sectionNameKeyPath: nil,         cacheName: nil)      return arc 

Even though I have all issues from the project object, I prefer to obtain issues using fetched results controller, so they will always be updated and I like the integration with tables. I also like that in navigation controller screen before the projects are displayed using FRC as well.

As you see in the code the Issues are sorted by the name parameter.

However I'd like them to be sorted by the order I keep them in the NSMutableOrderedSet of project.

AFAIK I cannot use NSSortDescriptor with comparator/selector when it's used to Core Data.

Do you know how to do it? Thanks in advance.

3 Answers

Answers 1

If you use the relationship keypath (in your case parentProject) it will sort according to the ordered set. so you can use

fetchRequest.sortDescriptors = [NSSortDescriptor(key: "parentProject.name", ascending: true),NSSortDescriptor(key: "parentProject", ascending: true)] 

This will first sort them by project, then inside each project group it will be sorted by the same order as the ordered set in the relationship. Optionally you can put each issue's project in a different section by using sectionNameKeyPath.

If you don't use parentProject.name (or something like it - like parentProject.lastUpdated) first then they will ONLY be sorted according to the order of orderedSet. In other words it will be all of the first issues, then all of the second issues etc. This is probably not what you want.

Answers 2

This may be a kluge, but anyway. It seems to me your first fetch is a filter.. e.g. show me issues for this project. Maybe you could perform a second fetch, on the selected issues, and this time not filtering them, but sorting them?

Regarding CoreData, I have a sorted fetch like this:

  func fetchItem() {         print(#function)          let sortDescriptor: NSSortDescriptor!         let defaults: UserDefaults = UserDefaults.standard         if defaults.integer(forKey: "sequenceSwitchValue") == 0 {             sortDescriptor = NSSortDescriptor(key: "itemName", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))         } else {             sortDescriptor = NSSortDescriptor(key: "itemName", ascending: false, selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))         }          let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext         let request = NSFetchRequest<NSFetchRequestResult>(entityName: itemEntity)         request.sortDescriptors = [sortDescriptor]         let predicate: NSPredicate = NSPredicate(format: "itemName == %@", incomingItemName)         request.predicate = predicate           do {             items = try context.fetch(request) as! [ItemEntity]         } catch let error as NSError {             print("Error While Fetching Data From DB: \(error.userInfo)")         }          if items.count > 0 {             let currentItem = items[0] 

You may be able to work a relationship value into the predicate..

Answers 3

The simplest way to keep order is to add a property for the "issue" entity. Something called position of type Int. And use sort Descriptor that would sort entities by this position property

Read More

Laravel 5.3 - Social login doubts

Leave a Comment

I am developing a mobile app and currently depending on JWT to maintain the statelessness of the API. The API is consumed by mobile and web devices. The users will use their email and password to register.

I am assigned to implement social login option in this API. I would like to clear my following doubts.

1) When Social Login is used, how can I generate a token [like JWT] which will be stored at the client's end? This token is supposed to send with all subsequent requests after login.

2) In case social platforms are not providing/sharing email address [which is one of our primary keys], what all information shall I store?

2 Answers

Answers 1

Once you "social login" a user, you get a list of data from the social network itself. User can disallow the retrieve of the email address (ex. from Facebook): in this case, you have to create a new user in you database, connect this user with the ID received and ask him to enter his email address. After the social login, if it is the first time, I suggest you to ask the user to confirm their email address or even change it: in this way, you have just one flow.

Pay attention that a user could register himself using email/password and then try to login using Facebook or Twitter: in this case you should try and check if you already have a user with that email address and just link this user with the new token. Otherwise, create a new user.

The token is created as you actually do, after a successful login.

Answers 2

Some social networks allow to delegate user authentication instead or requiring credentials in your own system. When user logs in, the external platform will provide you an access token that can be used to get some information of the user,

Use this data to register user into your own system. Attach the access token. Depending on the permissions you have requested, you can use the token to perform additional operation in the social platform.

Then issue a JWT to be used as authentication token in the web/mobile app where user log on. This JWT must be independent of the access token sent by authentication provider. For example

 {"sub": "userid",    "name": "User name"    "iss": "issuer",    "exp": 1300819380,    "login":"facebook"   } 

If you plan to use several authentication systems like Google or Facebook, do not use the email as unique identifier because it could different for the same user. You will need an additional register process to link the accounts that the user has in different networks. For example, letting user set the identifier that is using in other system or just launch the log in process in twitter when user is logged by Facebook

Read More

How to put views on top of an ImageView, in relation to the ImageView's content size?

Leave a Comment

Background

Suppose I want to show an image of the something using an ImageView, and I want to put new views on top of it (animated ImageViews that show pins on a world map image, for example, or a Switch view on top of a smartphone image).

This means that no matter how the ImageView shows the image, the views should be in it, inside correct spot, with the same size as specified, or in a size related to the imageView itself

The problem

As opposed to other views, the ImageView can have a certain size, but its content is something else (to keep aspect ratio).

What I tried

I tried to use ConstraintLayout, but this can't really help, because the ImageView can change its size (for example when changing orientation), and thus ruining the position I've given the views compared to the ImageView.

I've found some libraries that can handle a similar thing (like here) and I even asked a similar question before (here), but all those solutions are for a static image within the ImageView, yet what I search for is adding a view on top of an ImageView.

The question

How do I put the views on top of the ImageView's content correctly?

How do I also scale the views down/up compared to the size of the ImageView's content ?

Can ConstraintLayout be used to change the scale of the views according to the ImageView's size ?

7 Answers

Answers 1

Make FrameLayout with wrap_content around ImageView. Then you could set SwitchView on top of ImageView. You could align it to center, side or corners and using margins to get some fine position.

It still won't scale with image, but you can get pretty good results. If that doesn't fit you, you can programatically get width/height of ImageView and alter position (or margins) of SwitchView accordingly.

Answers 2

With below you can manage width of switch or any other view as per image view width

android:layout_alignLeft="@+id/imageView" android:layout_alignRight="@+id/imageView" 

<Switch     android:id="@+id/swi"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_alignLeft="@+id/imageView"     android:layout_alignRight="@+id/imageView" />  <ImageView     android:id="@+id/imageView"     android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:layout_below="@+id/swi"     android:src="@drawable/download" /> 

Answers 3

In Java,

        ImageView imgView = (ImageView) findViewById(R.id.imageView);         imageView.setBackgroundResource(R.drawable.yourDrawable);         int width = imgView.getDrawable().getIntrinsicWidth();          Switch switchKey = (Switch) findViewById(R.id.switchKey);         switchKey.setMinimumWidth(width); 

And in XML, align it with alignLeft and alignRight with ImageView.

Answers 4

As far as i get it, you need the image size displayed inside the image view and set that as the max width of your switch view right?

You need both Java and XML for this,

The XML file is basically as RelativeLayout with the view stacked as needed.

   <RelativeLayout         android:layout_width="wrap_content"         android:layout_height="wrap_content">         <ImageView             android:src="@drawable/nonet_icon"             android:id="@+id/iconView"             android:layout_width="wrap_content"             android:layout_height="wrap_content" />         <android.support.v7.widget.SwitchCompat             android:layout_width="wrap_content"             android:visibility="gone"             android:layout_centerInParent="true"             android:layout_height="wrap_content"             android:id="@+id/switchView"/>     </RelativeLayout> 

And the Java Code gets the imageWidth and sets it to the SwitchView.

        mSwitchCompat.setVisibility(View.VISIBLE); //        20% x 25% of Content in ImageView         final float x = mImageView.getDrawable().getIntrinsicWidth()*.2f;         final float y = mImageView.getDrawable().getIntrinsicHeight()*.25f; //        waiting for the view to be drawn         mSwitchCompat.post(new Runnable() {             @Override             public void run() { //        scale current view W.r.t. x and y values               mSwitchCompat.setScaleX((float)mSwitchCompat.getWidth()/x);                 mSwitchCompat.setScaleY((float)mSwitchCompat.getHeight()/y);             }         });         RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                 WindowManager.LayoutParams.WRAP_CONTENT); //        30% x 35% of content, for location         int xMargin  = Math.round(mImageView.getDrawable().getIntrinsicWidth()*.3f);         int yMargin = Math.round(mImageView.getDrawable().getIntrinsicHeight()*.35f); //      set margin values, can optionally add for top and bottom         layoutParams.setMargins(xMargin,0,yMargin,0);         mSwitchCompat.setLayoutParams(layoutParams); 

Ref: Getting Displayed image size of an ImageView Trying to get the display size of an image in an ImageView

Ref: Dynamic size values

Do comment if you need a detailed explaination.

Example: Check this image!

Scaled View on Image: Scaled View on Image!

Answers 5

You can use MarginLayoutParams with Relative Layout to set left and top position in ImageView.

    image = (ImageView) findViewById(R.id.imageID);     MarginLayoutParams marginParams = new MarginLayoutParams(image.getLayoutParams());     marginParams.setMargins(left_margin, top_margin, right_margin, bottom_margin);     RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams);     image.setLayoutParams(layoutParams); 

find complete information for this in below link :

MarginLayoutParams

Answers 6

Try this, may be it will help you.

<RelativeLayout     android:layout_width="wrap_content"     android:layout_height="wrap_content">      <ImageView         android:id="@+id/img_background"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:scaleType="centerCrop"/>      <RelativeLayout         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:background="@color/semi_transparent"         android:layout_margin="@dimen/spacing_small"         android:layout_alignTop="@+id/img_background"         android:layout_alignBottom="@id/img_background">          //this layout will expand according to your image size      </RelativeLayout>  </RelativeLayout> 

Answers 7

Do you want to show switch that lay on imageview ?

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout     xmlns:android="http://schemas.android.com/apk/res/android"     android:id="@+id/ll_download"     android:layout_width="100dp"     android:layout_height="60dp"     android:layout_centerInParent="true"     android:orientation="vertical">      <ImageView         android:src="@android:drawable/btn_star_big_on"         android:layout_width="match_parent"         android:layout_height="match_parent" />     <Switch         android:id="@+id/mySwitch"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:text="Switch" /> </RelativeLayout> 

enter image description here

Read More

Is it possible to use poison pill approach with bounded queues?

Leave a Comment

In Java Concurrency In Practice book (p.156), there's a statement regarding poison pill approach:

Poison pills work reliably only with unbound queues.

Does it mean that with a bounded queue I can get a deadlock, or is it about some other liveness problems? Is it connected with number of producers and customers?

3 Answers

Answers 1

With a bounded queue, you could be prevented from adding the poison pill.

One way to avoid this issue is to make the bounded queue allow one more when a poison pill is added.

Answers 2

The problem is that the queue may be full at close time.

It depends on how valuable the data in the queue is at the time of closure. Can you afford to throw everything in the queue away?

When the time comes to close the queue it should be effective to drain the queue first before adding the poison pill.

void close () throws InterruptedException {   do {     // Empty the queue.     while ( queue.poll(0,TimeUnit.MILLISECONDS) != null ) {       // Throw it away.     }     // Keep draining the queue 'till the pill is swallowed.   } while (!queue.offer(STOP, 0, TimeUnit.MILLISECONDS)) ; } 

but of course if the items in the queue are valuable you may wish to use drainto and preserve them.

Please also bear in mind that there may be more items added to the queue after the poison pill because not only might the queue be full but there may also be threads blocked waiting to post to it.

Answers 3

@gstackoverflow: The main issue of the bounded queue is that it has a maximum capacity, so if your bounded queue is full, you will be blocked when you want to add this "Poison pill".

Bear in mind that the Poison pill has to be placed immediately and cannot wait until the queue has some space, as this technique is used to shutdown gracefully consumers when an exception occurs (otherwise there exists nicer technique to shutdown consumers).

Edit: As an example speaks more than a thousand sentences let's see a simple example (all credits for the example go to Java Concurrency in Practice), with a Producer Thread and a Consumer Thread:

public class CrawlerThread extends Thread { //The Producer Thread   public void run() {     try {       crawl(root);     } catch (InterruptedException e) { /* fall through */ }     finally {       while (true) {         try {           queue.put(POISON);           break;         } catch (InterruptedException e1) { /* retry */ }       }     }   }   private void crawl(File root) throws InterruptedException {     //some code   } } public class IndexerThread extends Thread { //The consumer Thread   public void run() {     try {       while (true) {         File file = queue.take();         if (file == POISON)         break;         else         indexFile(file);       }     } catch (InterruptedException consumed) { }   } } 

Now when you examine the Producer Thread (CrawlerThread), you see the Poison pill is placed either at the end of the run, or in a more dire situation, when an exception occurs.

Now let's say you want to use a bounded queue as the interface between the producer and the consumer, let's assume the queue is full at time t, and an exception occurs in the producer at time t, the producer won't be able to place the Poison pill on the queue and instead of having the Consumer thread shut downs, the Consumer will still be waiting for elements to come into the queue. Thus that's why the Poison pill approach is not recommended if you use a bounded queue, because it could potentially lead to an unexpected result.

Read More

Monday, February 27, 2017

MVC 4: How to maintain sessions and cookies to be still valid after IIS restart?

Leave a Comment

It seems that my login session (using simple membership) and cookies (verification token) are not valid after IIS server restart. This is a problem for me, if a user in the middle of a transaction then the server restart, the user has to refill the form and do it again, also it can be some code issue when the transaction is interrupted in the middle of the process.

How to make them to be still valid after server restart?

Here is my web.config:

<membership /> ... <sessionState mode="InProc" cookieless="false" timeout="2880" /> ... <authentication mode="Forms">   <forms loginUrl="~/Account/Login" timeout="2880" /> </authentication>  ... <staticContent>   <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00" />   <remove fileExtension=".woff" />   <remove fileExtension=".woff2" />   <mimeMap fileExtension=".woff" mimeType="application/font-woff" />   <mimeMap fileExtension=".woff2" mimeType="application/font-woff2" /> </staticContent> 

Update

I tried to use SQLServer to store the session state. Then new problem arise, which I cannot use ViewBag because it is not Serializable.

Is there another way I can achieve this?

6 Answers

Answers 1

There is no way to achieve this AFAIK. You can always use Database or File to keep session and cookie values.

Idea could be you serialize the object that you want to keep in Session or Cookie. There are many tools that does serialization for you, I use newtonsoft. Then store it as string in DB along with session key.

For getting it back you can simply fire a query based on session key, get string and deserialize it and you are done :)

Answers 2

By default, Session data is store in memory. Hence, you lost it when IIS restarts. You may consider other out of proc sessionstate provider to store the data, e.g. database, sessionstate service.

Answers 3

Cookies are stored in the clients browser and sent on every request to the server. Therefore cookies are available across IIS restarts or AppDomain recyles.

Session data is by default not kept across AppDomain recycle or IIS restart. The only way to achieve this is to use a session state provider like the one for SQL server.

For this to work the session state provider needs to be able to serialize/deserilize your data in order to persist and restore it from the database, this means that you need to use types which is serializeable in your session.

You could change your code to use other types which are serializeable or store your data in a cookie instead.

Answers 4

May you have to store the sessions in database, hope this tutorial help you https://msdn.microsoft.com/en-us/library/ms178586(v=vs.140).aspx

Answers 5

If you get an error about viewbag when you try to persist your session means you are storing viewbag in session. Do you really need? I think you should avoid to store viewbag in session and use instead, if you really want to do, your own serializable custom class. May be a generic dictionary can already fit your needs as well... Then persist your session to the database or if you want re-inventing the wheel implement your custom Session-State Store Provider. In general using session to store information is never a good practice for many reasons, the main is your data are lost when the server restart. As far i can understand in your web app you are using session to store posted data, the correct way to do is relay to viewmodel class.

Answers 6

Keep sessions in a clustered database (master-master)

Read More

How to avoid “Invalid byte sequence” when looking for link with text using Nokogiri

Leave a Comment

I'm using Rails 5 with Ruby 4.2 and scanning a document that I parsed with Nokogiri, looking in a case insensitive way for a link with text:

a_elt = doc ? doc.xpath('//a').detect { |node| /link[[:space:]]+text/i === node.text } : nil  

After getting the HTML of my web page in content, I parse it into a Nokogiri doc using:

doc = Nokogiri::HTML(content)  

The problem is, I'm getting

ArgumentError invalid byte sequence in UTF-8 

on certain web pages when using the above regular expression.

2.4.0 :002 > doc.encoding  => "UTF-8"  2.4.0 :003 > doc.xpath('//a').detect { |node| /individual[[:space:]]+results/i === node.text } ArgumentError: invalid byte sequence in UTF-8     from (irb):3:in `==='     from (irb):3:in `block in irb_binding'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/nokogiri-1.7.0/lib/nokogiri/xml/node_set.rb:187:in `block in each'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/nokogiri-1.7.0/lib/nokogiri/xml/node_set.rb:186:in `upto'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/nokogiri-1.7.0/lib/nokogiri/xml/node_set.rb:186:in `each'     from (irb):3:in `detect'     from (irb):3     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/railties-5.0.1/lib/rails/commands/console.rb:65:in `start'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/railties-5.0.1/lib/rails/commands/console_helper.rb:9:in `start'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/railties-5.0.1/lib/rails/commands/commands_tasks.rb:78:in `console'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/railties-5.0.1/lib/rails/commands/commands_tasks.rb:49:in `run_command!'     from /Users/davea/.rvm/gems/ruby-2.4.0@global/gems/railties-5.0.1/lib/rails/commands.rb:18:in `<top (required)>'     from bin/rails:4:in `require'     from bin/rails:4:in `<main>'  

Is there a way I can rewrite the above to automatically account for the encoding or weird characters and not flip out?

1 Answers

Answers 1

Your question may have already been answered before. Have you tried the methods from "Is there any way to clean a file of "invalid byte sequence in UTF-8" errors in Ruby?"?

Specifically before the detect block, try to remove the invalid bytes and control characters except new line:

doc.scrub!("") doc.gsub!(/[[:cntrl:]&&[^\n\r]]/,"") 

Remember, scrub! is a Ruby 2.1+ method.

Read More

MvcBuildViews true causes “'/temp' is not a valid IIS application” error

Leave a Comment

After setting MvcBuildViews to true in my .csproj file in order to have the views compile during build, I get the following error:

'/temp' is not a valid IIS application

I presume that the '/temp' that this is referring to is the path where the views will be compiled. Here's the relevant section in the .csproj file:

<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">     <AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" /> </Target> 

I use full IIS to serve up this MVC 5 website on my local machine (haven't tried this on a remote server yet). Do I need to set something up in IIS to make MvcBuildViews work correctly?

1 Answers

Answers 1

See this, I guess you've to make IIS virtual directory names temp to point to this application.

Read More

Android VideoView starting lots of videos sequentially

Leave a Comment

I'm testing this for about three days nonstop.

Here's the simple code:

private VideoView videoView; 

--

videoView = (VideoView) findViewById(R.id.videoView);  videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {     @Override     public void onCompletion(MediaPlayer mediaPlayer) {             getNewVideo();         }     } });  getNewVideo(); 

--

private void getNewVideo(){     File file = //Any File. I have a list of files and they are executed in order     videoView.stopPlayback();     videoView.setVideoPath(file.getPath());     videoView.start(); } 

--

<VideoView     android:id="@+id/videoView"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:layout_alignParentBottom="true"     android:layout_alignParentLeft="true"     android:layout_alignParentRight="true"     android:layout_alignParentTop="true" /> 

I need to execute this code 24/7.

The thing is, independent of duration (in the very beggining, or after 20 minutes running), SOMETIMES, the video just freezes. There's no log, there's no exception, the only thing i know is the last thing that is running before freezes is onPrepared().

The log is the same to all attempts to call the video, the only difference is that the last attemps (the one that freezes), is just stops after on prepared is executed.

ANY tip is appreciated.

The build number im using is RKM MK902_ANDROID5.1.1-20151016.1805

with a RKM MK902II Android PC device, running in a TV Screen 42'

2 Answers

Answers 1

I don't have much experience playing local video files (I assume this because your code says you have a "list of files executed in order"), but.....

In my experience you shouldn't call videoView.start() until the media has been properly initialized by the VideoView.

When you call videoView.setVideoPath("path") the VideoView will do some initialization procedures to load the Media. After VideoView has loaded/initialized the media it will then invoke its onPreparedListener callback (if you've set one). Only when this callback has been invoked by the VideoView should you call VideoView.start() to start video playback.

So...when you set the onCompletionListener on your VideoView... you should also set an onPreparedListener. When the VideoView reports back to your class that it's prepared....call VideoView.start() to start playback.

videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {         @Override         public void onPrepared(MediaPlayer mp) {             videoView.start();         }     } }); 

Also, in my code I make a call to VideoView.suspend() before I re-use the VideoView to play a subsequent video. Try adding a call to VideoView.suspend() in the beginning of your getNewVideo() method.

Answers 2

add

   videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {             @Override             public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {                  getNewVideo();                 return true;             }         }); 
Read More

MySQL server slow to respond with Wordpress

Leave a Comment

I have a web server running Windows, IIS, PHP that is hosting a fully patched WordPress site. The database sits on a separate server inside the DMZ that is running Windows and MySQL 5.7.13.

When making a request to the WordPress site, it takes anywhere from 6 to 16 seconds to get back the first byte.

Executing this ridiculously un-optimized query from MySQL Workbench (on the web server) takes only 0.858 seconds.

SELECT * FROM wp_posts INNER JOIN wp_postmeta ON wp_postmeta.post_id = wp_posts.ID INNER JOIN wp_comments ON wp_comments.comment_post_id = wp_posts.ID INNER JOIN wp_commentmeta ON wp_commentmeta.comment_id = wp_comments.comment_ID 

This is my complete my.ini file:

# Other default tuning values # MySQL Server Instance Configuration File # ---------------------------------------------------------------------- # Generated by the MySQL Server Instance Configuration Wizard #  #  # Installation Instructions # ---------------------------------------------------------------------- #  # On Linux you can copy this file to /etc/my.cnf to set global options, # mysql-data-dir/my.cnf to set server-specific options # (@localstatedir@ for this installation) or to # ~/.my.cnf to set user-specific options. #  # On Windows you should keep this file in the installation directory  # of your server (e.g. C:\Program Files\MySQL\MySQL Server X.Y). To # make sure the server reads the config file use the startup option  # "--defaults-file".  #  # To run run the server from the command line, execute this in a  # command line shell, e.g. # mysqld --defaults-file="C:\Program Files\MySQL\MySQL Server X.Y\my.ini" #  # To install the server as a Windows service manually, execute this in a  # command line shell, e.g. # mysqld --install MySQLXY --defaults-file="C:\Program Files\MySQL\MySQL Server X.Y\my.ini" #  # And then execute this in a command line shell to start the server, e.g. # net start MySQLXY #  #  # Guildlines for editing this file # ---------------------------------------------------------------------- #  # In this file, you can use all long options that the program supports. # If you want to know the options a program supports, start the program # with the "--help" option. #  # More detailed information about the individual options can also be # found in the manual. #  # For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html #  #  # CLIENT SECTION # ---------------------------------------------------------------------- #  # The following options will be read by MySQL client applications. # Note that only client applications shipped by MySQL are guaranteed # to read this section. If you want your own MySQL client program to # honor these values, you need to specify it as an option during the # MySQL client library initialization. #  [client] no-beep=  # pipe= # socket=0.0 port=3306  [mysql]  default-character-set=utf8   # SERVER SECTION # ---------------------------------------------------------------------- #  # The following options will be read by the MySQL Server. Make sure that # you have installed the server correctly (see above) so it reads this  # file.= #  # server_type=3 [mysqld] # Skip reverse DNS lookup of clients skip-name-resolve   # The next three options are mutually exclusive to SERVER_PORT below. # skip-networking=  # enable-named-pipe=  # shared-memory=  # shared-memory-base-name=MYSQL  # The Pipe the MySQL Server will use # socket=MYSQL  # The TCP/IP Port the MySQL Server will listen on port=3306  # Path to installation directory. All paths are usually resolved relative to this. # basedir="C:/Program Files/MySQL/MySQL Server 5.7/"  # Path to the database root # datadir=C:/ProgramData/MySQL/MySQL Server 5.7\Data datadir=D:\MySQL\Data  # The default character set that will be used when a new schema or table is # created and no character set is defined character-set-server=utf8  # The default storage engine that will be used when create new tables when default-storage-engine=INNODB  # Set the SQL mode to strict sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"  # Enable Windows Authentication # plugin-load=authentication_windows.dll  # General and Slow logging. log-output=FILE   slow-query-log=1 slow_query_log_file="PRDMYSQL-slow.log" long_query_time=10  # Binary Logging. # log-bin=  # Error Logging.   # Server Id. server-id=1  # Secure File Priv. secure-file-priv="C:/ProgramData/MySQL/MySQL Server 5.7/Uploads"  # The maximum amount of concurrent sessions the MySQL server will # allow. One of these connections will be reserved for a user with # SUPER privileges to allow the administrator to login even if the # connection limit has been reached. max_connections=151  # Query cache is used to cache SELECT results and later return them # without actual executing the same query once again. Having the query # cache enabled may result in significant speed improvements, if your # have a lot of identical queries and rarely changing tables. See the # "Qcache_lowmem_prunes" status variable to check if the current value # is high enough for your load. # Note: In case your tables change very often or if your queries are # textually different every time, the query cache may result in a # slowdown instead of a performance improvement. query_cache_size=16M  # The number of open tables for all threads. Increasing this value # increases the number of file descriptors that mysqld requires. # Therefore you have to make sure to set the amount of open files # allowed to at least 4096 in the variable "open-files-limit" in # section [mysqld_safe] table_open_cache=2000  # Maximum size for internal (in-memory) temporary tables. If a table # grows larger than this value, it is automatically converted to disk # based table This limitation is for a single table. There can be many # of them. tmp_table_size=60M  # How many threads we should keep in a cache for reuse. When a client # disconnects, the client's threads are put in the cache if there aren't # more than thread_cache_size threads from before.  This greatly reduces # the amount of thread creations needed if you have a lot of new # connections. (Normally this doesn't give a notable performance # improvement if you have a good thread implementation.) thread_cache_size=10  # *** MyISAM Specific options # The maximum size of the temporary file MySQL is allowed to use while # recreating the index (during REPAIR, ALTER TABLE or LOAD DATA INFILE. # If the file-size would be bigger than this, the index will be created # through the key cache (which is slower). myisam_max_sort_file_size=100G  # If the temporary file used for fast index creation would be bigger # than using the key cache by the amount specified here, then prefer the # key cache method.  This is mainly used to force long character keys in # large tables to use the slower key cache method to create the index. myisam_sort_buffer_size=111M  # Size of the Key Buffer, used to cache index blocks for MyISAM tables. # Do not set it larger than 30% of your available memory, as some memory # is also required by the OS to cache rows. Even if you're not using # MyISAM tables, you should still set it to 8-64M as it will also be # used for internal temporary disk tables. key_buffer_size=16M  # Size of the buffer used for doing full table scans of MyISAM tables. # Allocated per thread, if a full scan is needed. read_buffer_size=64K read_rnd_buffer_size=256K  # *** INNODB Specific options *** # innodb_data_home_dir=0.0  # Use this option if you have a MySQL server with InnoDB support enabled # but you do not plan to use it. This will save memory and disk space # and speed up some things. # skip-innodb=  # If set to 1, InnoDB will flush (fsync) the transaction logs to the # disk at each commit, which offers full ACID behavior. If you are # willing to compromise this safety, and you are running small # transactions, you may set this to 0 or 2 to reduce disk I/O to the # logs. Value 0 means that the log is only written to the log file and # the log file flushed to disk approximately once per second. Value 2 # means the log is written to the log file at each commit, but the log # file is only flushed to disk approximately once per second. innodb_flush_log_at_trx_commit=1  # The size of the buffer InnoDB uses for buffering log data. As soon as # it is full, InnoDB will have to flush it to disk. As it is flushed # once per second anyway, it does not make sense to have it very large # (even with long transactions). innodb_log_buffer_size=1M  # InnoDB, unlike MyISAM, uses a buffer pool to cache both indexes and # row data. The bigger you set this the less disk I/O is needed to # access data in tables. On a dedicated database server you may set this # parameter up to 80% of the machine physical memory size. Do not set it # too large, though, because competition of the physical memory may # cause paging in the operating system.  Note that on 32bit systems you # might be limited to 2-3.5G of user level memory per process, so do not # set it too high. innodb_buffer_pool_size=2048M  # Size of each log file in a log group. You should set the combined size # of log files to about 25%-100% of your buffer pool size to avoid # unneeded buffer pool flush activity on log file overwrite. However, # note that a larger logfile size will increase the time needed for the # recovery process. innodb_log_file_size=48M  # Number of threads allowed inside the InnoDB kernel. The optimal value # depends highly on the application, hardware as well as the OS # scheduler properties. A too high value may lead to thread thrashing. innodb_thread_concurrency=8  # The increment size (in MB) for extending the size of an auto-extend InnoDB system tablespace file when it becomes full. innodb_autoextend_increment=64  # The number of regions that the InnoDB buffer pool is divided into. # For systems with buffer pools in the multi-gigabyte range, dividing the buffer pool into separate instances can improve concurrency, # by reducing contention as different threads read and write to cached pages. innodb_buffer_pool_instances=8  # Determines the number of threads that can enter InnoDB concurrently. innodb_concurrency_tickets=5000  # Specifies how long in milliseconds (ms) a block inserted into the old sublist must stay there after its first access before # it can be moved to the new sublist. innodb_old_blocks_time=1000  # It specifies the maximum number of .ibd files that MySQL can keep open at one time. The minimum value is 10. innodb_open_files=300  # When this variable is enabled, InnoDB updates statistics during metadata statements. innodb_stats_on_metadata=0  # When innodb_file_per_table is enabled (the default in 5.6.6 and higher), InnoDB stores the data and indexes for each newly created table # in a separate .ibd file, rather than in the system tablespace. innodb_file_per_table=1  # Use the following list of values: 0 for crc32, 1 for strict_crc32, 2 for innodb, 3 for strict_innodb, 4 for none, 5 for strict_none. innodb_checksum_algorithm=0  # The number of outstanding connection requests MySQL can have. # This option is useful when the main MySQL thread gets many connection requests in a very short time. # It then takes some time (although very little) for the main thread to check the connection and start a new thread. # The back_log value indicates how many requests can be stacked during this short time before MySQL momentarily # stops answering new requests. # You need to increase this only if you expect a large number of connections in a short period of time. back_log=80  # If this is set to a nonzero value, all tables are closed every flush_time seconds to free up resources and # synchronize unflushed data to disk. # This option is best used only on systems with minimal resources. flush_time=0  # The minimum size of the buffer that is used for plain index scans, range index scans, and joins that do not use # indexes and thus perform full table scans. join_buffer_size=256K  # The maximum size of one packet or any generated or intermediate string, or any parameter sent by the # mysql_stmt_send_long_data() C API function. max_allowed_packet=4M  # If more than this many successive connection requests from a host are interrupted without a successful connection, # the server blocks that host from performing further connections. max_connect_errors=100  # Changes the number of file descriptors available to mysqld. # You should try increasing the value of this option if mysqld gives you the error "Too many open files". open_files_limit=4161  # Set the query cache type. 0 for OFF, 1 for ON and 2 for DEMAND. query_cache_type=1  # If you see many sort_merge_passes per second in SHOW GLOBAL STATUS output, you can consider increasing the # sort_buffer_size value to speed up ORDER BY or GROUP BY operations that cannot be improved with query optimization # or improved indexing. sort_buffer_size=256K  # The number of table definitions (from .frm files) that can be stored in the definition cache. # If you use a large number of tables, you can create a large table definition cache to speed up opening of tables. # The table definition cache takes less space and does not use file descriptors, unlike the normal table cache. # The minimum and default values are both 400. table_definition_cache=1400  # Specify the maximum size of a row-based binary log event, in bytes. # Rows are grouped into events smaller than this size if possible. The value should be a multiple of 256. binlog_row_event_max_size=8K  # If the value of this variable is greater than 0, a replication slave synchronizes its master.info file to disk. # (using fdatasync()) after every sync_master_info events. sync_master_info=10000  # If the value of this variable is greater than 0, the MySQL server synchronizes its relay log to disk. # (using fdatasync()) after every sync_relay_log writes to the relay log. sync_relay_log=10000  # If the value of this variable is greater than 0, a replication slave synchronizes its relay-log.info file to disk. # (using fdatasync()) after every sync_relay_log_info transactions. sync_relay_log_info=10000  # Load mysql plugins at start."plugin_x ; plugin_y". plugin_load="mysqlx"  # MySQL server's plugin configuration. loose_mysqlx_port=33060   log-error = "D:/MySQL/Data/PRDMYSQL.err"  expire_logs_days = 3 log-tc-size = 10240 

2 Answers

Answers 1

Using the WordPress plugin Query Monitor, I discovered something was making 8000 !! extra queries per page call.

I found that a plugin we had been using for months received an update that introduced this behavior. I didn't realize that one of the content editors of the site had applied the update.

Disabling this plugin returned the site back to normal load times.

Answers 2

Turn on MySQL's "General log". Run briefly (until the issue occurs), then turn it off.

Then use pt-query-digest to see what queries were run, and who ran them. From that, you may be able to deduce what is causing it.

Read More

Creating a connection to a subscription site in python

Leave a Comment

I am looking to open a connection with python to http://www.horseandcountry.tv which takes my login parameters via the POST method. I would like to open a connection to this website in order to scrape the site for all video links (this, I also don't know how to do yet but am using the project to learn).

My question is how do I pass my credentials to the individual pages of the website? For example if all I wanted to do was use python code to open a browser window pointing to http://play.horseandcountry.tv/live/ and have it open with me already logged in, how do I go about this?

3 Answers

Answers 1

As far as I know you have two options depending how you want to crawl and what you need to crawl:

1) Use urllib. You can do your POST request with the necessary login credentials. This is the low level solution, which means that this is fast, but doesn't handle high level stuff like javascript codes.

2) Use selenium. Whith that you can simulate a browser (Chrome, Firefox, other..), and run actions via your python code. Then it is much slower but works well with too "sophisticated" websites.

What I usually do: I try the first option and if a encounter a problem like a javascript security layer on the website, then go for option 2. Moreover, selenium can open a real web browser from your desktop and give you a visual of your scrapping.

In any case, just goolge "urllib/selenium login to website" and you'll find what you need.

Answers 2

If you want to avoid using Selenium (opening web browsers), you can go for requests, it can login the website and grab anything you need in the background.

Here is how you can login to that website with requests.

import requests from bs4 import BeautifulSoup  #Login Form Data payload = {      'account_email': 'your_email',     'account_password': 'your_passowrd',     'submit':   'Sign In' }  with requests.Session() as s:     #Login to the website.     response = s.post('https://play.horseandcountry.tv/login/', data=payload)      #Check if logged in successfully     soup = BeautifulSoup(response.text, 'lxml')     logged_in = soup.find('p', attrs={'class': 'navbar-text pull-right'})     print s.cookies     print response.status_code     if logged_in.text.startswith('Logged in as'):         print 'Logged In Successfully!' 

If you need explanations for this, you can check this answer, or requests documentation

Answers 3

You could also use the requests module. It is one the most popular. Here are some questions that relate to what you would like to do.

Log in to website using Python Requests module

logging in to website using requests

Read More

How to add Text for some duration of video in iOS SDK

Leave a Comment

I have video having duration 4:00. Now I want to add text in video file as per the frames of video. Say for example from 00:30 to 1:50 duration I want to add text "Welcome". Now from 3:00 to 4:00 duration of video I want to add text "Awesome". How to achieve this functionality. I have referred below tutorial. It adds text in whole video not for some duration of video. https://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos

Any help will be appriciated.

I am adding lines of code for add text on whole video:

- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition *)composition size:(CGSize)size {     // 1 - Set up the text layer     CATextLayer *subtitle1Text = [[CATextLayer alloc] init];     [subtitle1Text setFont:@"Helvetica-Bold"];     [subtitle1Text setFontSize:36];     [subtitle1Text setFrame:CGRectMake(0, 0, size.width, 100)];     [subtitle1Text setString:_subTitle1.text];     [subtitle1Text setAlignmentMode:kCAAlignmentCenter];     [subtitle1Text setForegroundColor:[[UIColor whiteColor] CGColor]];      // 2 - The usual overlay     CALayer *overlayLayer = [CALayer layer];     [overlayLayer addSublayer:subtitle1Text];     overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);     [overlayLayer setMasksToBounds:YES];      CALayer *parentLayer = [CALayer layer];     CALayer *videoLayer = [CALayer layer];     parentLayer.frame = CGRectMake(0, 0, size.width, size.height);     videoLayer.frame = CGRectMake(0, 0, size.width, size.height);     [parentLayer addSublayer:videoLayer];     [parentLayer addSublayer:overlayLayer];      composition.animationTool = [AVVideoCompositionCoreAnimationTool                                  videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];  } 

2 Answers

Answers 1

Edit Does this answer work for you? You will have to add multiple text layers, and use a CABasicAnimation to show/hide each at the appropriate time (using setBeginTime:).

Original Answer Basically, just maintain a reference to the CATextLayer in this section of code, and use an NSTimer called every second to update your text:

// 1 - Set up the text layer CATextLayer *subtitle1Text = [[CATextLayer alloc] init];  self.textLayer = subtitle1Text; // ### Keep a reference to this object and update it in timerDidFire ...  - (void)viewDidLoad{     ...     // Add a timer at some point.  Don't forget to invalidate it later     NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerDidFire) userInfo:nil repeats:YES];     [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];     ... }  - (void)timerDidFire{     if (currentPlaybackPosition <= some_value){         [self.textLayer setText:@"Welcome"];     } else if (currentPlaybackPosition <= some_bigger_value){         [self.textLayer setText:@"Awesome"];     }     ... } 

Answers 2

Look at your linked website: https://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos Just use 2 CATextLayer's as shown there. Set their texts.

Set the first ones beginTime property to 30 seconds and its duration property to 80 seconds. The 2nd with a beginTime of 180 seconds and a duration of 60 seconds.

The result will be exported as it is shown in a video player.

Read More

JUnit test with Embedded tomcat server , how to specify automatic ports for both http and https connectors?

Leave a Comment

Description

I have made a JUnit test that focus on trying to test a call to a SOAP web service.

I am using an embedded tomcat server for my test in order to run my test with a mock server.

I am also using both http and https connectors.

I need to use automatic ports for both these connectors because the test is running on a Jenkins server and i can't just use port 443 or 8443 as they are already taken.

I understand that using the port 0 as standard port will result in tomcat using automatic port allocation but I can't manage to use it with both connectors.

Expected behavior

I'd like to use automatic port allocation also for my custom ssl connector.

Is it possible to do so in some way ?

Sample code

Here is the code for my tomcat instance :

@Before public void setup() throws Throwable {      File tomcatWorkingDir = new File(mWorkingDir);      //Empty the target/tomcat-working-dir directory if it exist     //Create the directory otherwise     if(tomcatWorkingDir.exists() && tomcatWorkingDir.isDirectory()){         LOGGER.info("cleaning tomcat-working-dir directory");         FileUtils.cleanDirectory(new File(mWorkingDir));      } else {         LOGGER.info("create tomcat-working-dir directory");         tomcatWorkingDir.mkdir();     }      LOGGER.info("disabling ssl certification validation");     //Disable JVM ssl sockets connection     disableJVMCertificate();      //Add server certificate     createServerCertificate();      //Custom SSL Connector     Connector SSLConnector = getSSLConnector();      mTomcat = new Tomcat();      //Standard http startup port     mTomcat.setPort(0);      //Set up base directory      //Otherwise, tomcat would use the current directory     mTomcat.setBaseDir(mWorkingDir);      LOGGER.info("setting the ssl connector in TOMCAT");     Service service = mTomcat.getService();     service.addConnector(SSLConnector);      //Redirect current port     Connector defaultConnector = mTomcat.getConnector();     defaultConnector.setRedirectPort(SERVER_HTTPS_PORT);      //Configure the way WAR are managed by the engine     mTomcat.getHost().setAutoDeploy(true);     mTomcat.getHost().setDeployOnStartup(true);      //Add mock server into our webApp     String servletName = "/server";     File webApp = new File(mWorkingDir,"../../../ws-mock-server/src/main/webapp");      mTomcat.addWebapp(mTomcat.getHost(), servletName, webApp.getAbsolutePath());      //start tomcat     LOGGER.info("starting TOMCAT");      mTomcat.start();   } 

and here for my custom ssl connector.

    private static Connector getSSLConnector(){     Connector connector = new Connector();     connector.setPort(SERVER_HTTPS_PORT);     connector.setSecure(true);      //Http protocol Http11AprProtocol     connector.setAttribute("protocol", "org.apache.coyote.http11.Http11AprProtocol");      //Maximum threads allowedd on this instance of tomcat     connector.setAttribute("maxThreads","200");     connector.setAttribute("SSLEnabled", true);      //No client Authentification is required in order to connect     connector.setAttribute("clientAuth", false);      //SSL TLSv1 protocol     connector.setAttribute("sslProtocol","TLS");      //Ciphers configuration describing how server will encrypt his messages     //A common cipher suite need to exist between server and client in an ssl     //communication in order for the handshake to succeed     connector.setAttribute("ciphers","TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");      LOGGER.info("setting keystore file");     //Here an absolute file path is needed in order to properly set up the keystore attribute     connector.setAttribute("keystoreFile",new File(".").getAbsolutePath().replace("\\", "/")+"/"+mWorkingDir+"/server.jks");      LOGGER.info("setting keystore pass");     connector.setAttribute("keystorePass","changeit");      return connector; } 

0 Answers

Read More

Sunday, February 26, 2017

Cache is not cleared in Google Chrome

Leave a Comment

When I deploy the version I will add the number as query string with the JavaScript and CSS file like following?

'app/source/scripts/project.js?burst=32472938' 

I am using the above to burst the cache in the browser.

But in Firefox, I am getting the latest script that I have modified. But in Chrome, I am not getting the latest script that I have modified. Instead of that I am getting the old one.

But in developer console, I am seeing the burst number which is modified in latest.

5 Answers

Answers 1

According to the Google documentation, the best way to invalidate and reload the file is to add a version number to the file name and not as a query parameter:
'app/source/scripts/project.32472938.js'

Here is a link to the documentation:
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#invalidating_and_updating_cached_responses

Another way is to use an ETag (validation token):
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching#validating_cached_responses_with_etags

Here is how you would set up an ETag with Nginx:
http://nginx.org/en/docs/http/ngx_http_core_module.html#etag

And lastly, a tutorial about browser caching with Nginx and ETag:
https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-centos-7#step-2-%14-checking-the-default-behavior

Answers 2

I'm uncertain of whether this still applies these days, but there were some cases in the past where proxies could cause a query-string value to be ignored for caching purposes. There's an article from 2008 that discussed the idea that query-string values weren't ideal for the purpose of breaking caching, and that it was better to revise the filename itself -- so, referencing project_32472938.js instead of using the query-string.

(I've also seen, in places, some discussion of unusual cases where certain clients were not seeing these updates, but it seemed to be inconsistent -- not tied to Chrome, necessarily, but more likely tied to a specific installation of Chrome on a specific machine. I'd certainly recommend checking the site on another computer to see if the issue is repeated there, as you could at least narrow down to whether it's Chrome in general, or your specific install of Chrome that is having problems.)

All that said, it's been quite a while since 2008, and that may not be applicable these days. However, if it continues to be a problem -- and you can't find a solution to the underlying problem -- it at least offers a method use to circumvent it.

Answers 3

I don't think that Chrome actually causes the problem, because it would break almost all web applications (eg: https://www.google.com/search?q=needle)

It could be that your deployment was a bit delayed, eg.

  1. Start install new scripts
  2. Check with Chrome (receives old version on new ID)
  3. Install finishes
  4. You try with Firefox (receives new version)
  5. Chrome still shows old version because it cached the old script with new ID

Or you have a CDN like Azure between your web server and your browser.

With standard settings Azure CDN ignores the query string for the caching hash.

Answers 4

try those meta tags:

<meta http-equiv="cache-control" content="max-age=0" /> <meta http-equiv="cache-control" content="no-cache" /> <meta http-equiv="expires" content="0" /> <meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" /> <meta http-equiv="pragma" content="no-cache" /> 

Answers 5

i not sure , but for try...

google crome always ignore it..

you need to add a '?random.number' or "?date.code" to every link each time a url is pressed on your website. eg if 'myhomepage.html?272772' is stored in the cache, then by generating a new random number eg 'myhomepage.html?2474789', google chrome will be forced to look for a new copy.

Read More

Django runserver - can't serve video files

Leave a Comment

When running Django in local mode using the runserver command video files are not loaded in the browser properly. I get the error

An error occurred trying to load the resource.

All other static files serve fine such as images, javascript and css.

3 Answers

Answers 1

I have found the answer finally, Django's runserver does not support byte range requests. See this thread:

https://groups.google.com/forum/#!msg/django-developers/NZ1qTkZ6vok/fhdz7rTtL1EJ

And this ticket:

https://code.djangoproject.com/ticket/22479

Answers 2

Try running

python manage.py collectstatic 

Of course you must have STATIC_ROOT and STATICFILES_DIRS set properly in your settings file.

Answers 3

You may want to try and change your <video> tags to <source> as follows:

<source src="{{ YOUR_MEDIA_FILE_URL }}*yourvideo*.*videoformat*" type="video/*videoformat*"></source>

  • YOUR_MEDIA_FILE_URL: Works like the STATIC_URL documented examples.
Read More

Authentication/access control module for reverse proxy NGINX

Leave a Comment

I am looking for a module which does the authentication/access control for reverse proxy (preferable nginx). This module should do:

1. user authentication using credential stored in database (such as postgres) 2. Monitoring the ongoing connection and take action if certain access credential is met. For example, time is expired 3. open source (allow customization) and nginx, ruby(rails) preferable.  

It seems that OpenResty with nginx can do the job. Here is an article talking about access control with Lua on nginx. Here is an example (nginx and Lua) giving me impression that a snippet of file could executed for access (access_by_lua_file):

server {     listen 8080;      location / {       auth_basic           "Protected Elasticsearch";       auth_basic_user_file passwords;        access_by_lua_file '../authorize.lua';  #<<<=====        proxy_pass http://elasticsearch;       proxy_redirect off;     }    } 

I am new to access control with reverse proxy. Any thought is appreciated.

1 Answers

Answers 1

Here is an interesting article on nginx website which answers the question above. https://www.nginx.com/blog/nginx-plus-authenticate-users/

Read More

OpenVPN routing outside IPV6 tunnel (windows)

Leave a Comment

I'm struggeling with a general OpenVPN configuration...

I've an established OpenVPN connection with IPv6 and I want to exclude an IP for that tunnel... On IPv4 this works by adding

--route IP MASK net_gateway default 

to the config, so for example if I want to exclude the google DNS from the tunnel

--route 8.8.8.8 255.255.255.255 net_gateway default 

does the trick. But how to do that with IPv6? I know there is a --route-ipv6 command to route over the tunnel, but I didn't find a way to exclude an IP from the tunnel (for example google)

--route-ipv6 2a00:1450:4001:820::200e/128 ????  

which gateway do I need to define here? And where do I get it from? Just writing the name of the interface/network card seems not to work

0 Answers

Read More

React stop other events on that element

Leave a Comment

I have a volume element that shows the volume bar when the user hovers over it. This all works great in desktop. However to get the same functionality on mobile, the user has clicks on the volume element which also toggles the mute click event.

I am wanting to stop that mute event when the user clicks (i.e taps) on that element on mobile.

I don't want to modify the Mute or VolumeBar classes to fix this because these are generic classes in my library that the developer uses.

https://jsfiddle.net/jwm6k66c/2145/

  • Actual: The mute click event gets fired and the volume bar opens.
  • Expected: The mute click event doesn't gets fired and the volume bar opens.

Open the console -> go into mobile view (CTRL + SHIFT + M on chrome) -> click the volume button and observe the console logs.

What I have tried:

Using volumeControlOnClick to stop propogation when the volume bar's height is 0 (i.e not visible), this does not cancel the onClick though.

What I want:

To cancel the mute click event if the user clicks on the volume icon for the first time in mobile. Instead it should only show the volume bar.

const volumeControlOnClick = (e) => {   const volumeBarContainer =     e.currentTarget.nextElementSibling.querySelector('.jp-volume-bar-container');   /* Stop propogation is for mobiles to stop     triggering mute when showing volume bar */   if (volumeBarContainer.clientHeight === 0) {     e.stopPropagation();     console.log("stop propogation")   } };  class Volume extends React.Component {   constructor(props) {     super(props);      this.state = {};   }     render() {     return (         <div className="jp-volume-container">         <Mute onTouchStart={volumeControlOnClick}><i className="fa fa-volume-up" /></Mute>         <div className="jp-volume-controls">           <div className="jp-volume-bar-container">             <VolumeBar />           </div>          </div>        </div>     );   } };  class Mute extends React.Component {     render() {     return (       <button className="jp-mute" onClick={() => console.log("mute toggled")} onTouchStart={this.props.onTouchStart}>         {this.props.children}       </button>     );   } };  class VolumeBar extends React.Component {     render() {     return (         <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>         {this.props.children}       </div>     );   } };  React.render(<Volume />, document.getElementById('container')); 

3 Answers

Answers 1

What you can do is use a flag to indicate you were in a touch event before being in your mouse event, as long as you are using bubble phase. So attach a listener to your container element like this:

let isTouch = false;  const handleContainerClick = () => isTouch = false;  const handleMuteClick = () => {   if (isTouch == false) {     console.log("mute toggled");   } };  const volumeControlOnClick = () => {   isTouch = true; };  class Volume extends React.Component {   constructor(props) {     super(props);      this.state = {};   }    render() {     return (       <div className="jp-volume-container" onClick={handleContainerClick}>         <Mute onTouchStart={volumeControlOnClick} onClick={handleMuteClick}><i className="fa fa-volume-up" /></Mute>         <div className="jp-volume-controls">           <div className="jp-volume-bar-container">             <VolumeBar />           </div>         </div>       </div>     );   } };  class Mute extends React.Component {   render() {     return (       <button className="jp-mute" onTouchStart={this.props.onTouchStart} onClick={this.props.onClick}>         {this.props.children}       </button>     );   } };  class VolumeBar extends React.Component {   render() {     return (       <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>         {this.props.children}       </div>     );   } };  render(<Volume />, document.getElementById('container')); 

If you are not using bubble phase so you can register a timeout of 100ms with the same logic above, where after 100ms you make your flag variable false again. Just add to your touchStart handler:

setTimeout(() => {isTouch = false}, 100); 

EDIT: Even though touch events are supposed to be passive by default in Chrome 56, you call preventDefault() from a touchEnd event to prevent the click handler from firing. So, if you can't modify the click handler of your Mute class in any way, but you can add a touchEnd event, than you could do:

const handleTouchEnd = (e) => e.preventDefault();  const volumeControlOnClick = () => console.log("volumeControlOnClick");  class Volume extends React.Component {   constructor(props) {     super(props);      this.state = {};   }    render() {     return (       <div className="jp-volume-container">         <Mute onTouchStart={volumeControlOnClick} onTouchEnd={handleTouchEnd}><i className="fa fa-volume-up" /></Mute>         <div className="jp-volume-controls">           <div className="jp-volume-bar-container">             <VolumeBar />           </div>         </div>       </div>     );   } };  class Mute extends React.Component {   render() {     return (       <button className="jp-mute" onTouchStart={this.props.onTouchStart} onTouchEnd={this.props.onTouchEnd} onClick={() => console.log("mute toggled")}>         {this.props.children}       </button>     );   } };  class VolumeBar extends React.Component {   render() {     return (       <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>         {this.props.children}       </div>     );   } };  render(<Volume />, document.getElementById('container')); 

Answers 2

Here's what I ended up with. It works because onTouchStart is always calld before onClick if it's a touch event and if not's then the custom logic gets called anyway. It also fires before the hover has happened. This preserves the :hover event. e.preventDefault() did not.

let isVolumeBarVisible;  const onTouchStartMute = e => (   isVolumeBarVisible = e.currentTarget.nextElementSibling     .querySelector('.jp-volume-bar-container').clientHeight > 0 );  const onClickMute = () => () => {   if (isVolumeBarVisible !== false) {     // Do custom mute logic   }   isVolumeBarVisible = undefined; };  <Mute   aria-haspopup onTouchStart={onTouchStartMute}   onClick={onClickMute} >   <i className="fa">{/* Icon set in css*/}</i> </Mute> 

Answers 3

Try this

 render() {         return (       <div className="jp-volume-container" onClick={handleContainerClick}>         <Mute onTouchStart={volumeControlOnClick} onClick={handleMuteClick}><i className="fa fa-volume-up" /></Mute>         <div className="jp-volume-controls">           <div className="jp-volume-bar-container">             <VolumeBar />           </div>         </div>       </div>     );   } };  class Mute extends React.Component {   render() {     return (       <button className="jp-mute" onTouchStart={this.props.onTouchStart} onClick={this.props.onClick}>         {this.props.children}       </button>     );   } };  class VolumeBar extends React.Component {   render() {     return (       <div className="jp-volume-bar" onClick={() => console.log("bar moved")}>         {this.props.children}       </div>     );   } };  render(<Volume />, document.getElementById('container')); 
Read More

RecyclerView onBindViewHolder called only once inside Tab layout

Leave a Comment

I've four tabs and four fragments (each one for each tab).

Each fragment has a vertical recycler view. Since all fragments view look similar I'm re-using the same layout file, same recycler view items and same adapter.

The issue is that only one item is loaded under the first tab and third tab and fourth tab, While the second tab successfully loads the entire data.

I hope image added below gives better understanding regarding the issue.

enter image description here

Here is my adapter code

public class OthersAdapter extends RecyclerView.Adapter<OthersAdapter.OthersViewHolder> {      private final Context context;     private final ArrayList<LocalDealsDataFields> othersDataArray;     private LayoutInflater layoutInflater;      public OthersAdapter(Context context, ArrayList<LocalDealsDataFields> othersDataArray) {         this.context = context;         this.othersDataArray = othersDataArray;         if (this.context != null) {             layoutInflater = LayoutInflater.from(this.context);         }     }      class OthersViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {         TextView othersSmallTitleTextView;         ImageView othersImageView;          OthersViewHolder(View itemView) {             super(itemView);             othersSmallTitleTextView = (TextView) itemView.findViewById(R.id.others_small_title);             othersImageView = (ImageView) itemView.findViewById(R.id.others_image);             itemView.setOnClickListener(this);         }          @Override         public void onClick(View view) {             Intent couponDetailsItem = new Intent(context, LocalDealsActivity.class);             Bundle extras = new Bundle();             extras.putString(Constants.SECTION_NAME, context.getString(R.string.local_deals_section_title));             // Add the offer id to the extras. This will be used to retrieve the coupon details             // in the next activity             extras.putInt(Constants.COUPONS_OFFER_ID, othersDataArray.get(                     getAdapterPosition()).getLocalDealId());             couponDetailsItem.putExtras(extras);             context.startActivity(couponDetailsItem);         }     }      @Override     public OthersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View view = layoutInflater.inflate(R.layout.others_items, parent, false);         return new OthersViewHolder(view);     }      @Override     public void onBindViewHolder(OthersViewHolder holder, int position) {         String lfImage = othersDataArray.get(position).getLocalDealImage();         String lfCategoryName = othersDataArray.get(position).getLocalDealSecondTitle();         if (lfCategoryName != null) {             // Set the second title             holder.othersSmallTitleTextView.setText(lfCategoryName);         }         if (lfImage != null) {             if (!lfImage.isEmpty()) {                 // Get the Uri                 Uri lfUriImage = Uri.parse(lfImage);                 // Load the Image                 Picasso.with(context).load(lfUriImage).into(holder.othersImageView);             }         }     }      @Override     public int getItemCount() {         return othersDataArray.size();     } } 

I like to point out couple of things -

  • I've checked other answers on Stack Overflow. They talk about setting the recycler view layout_height to wrap_content. This isn't the issue as the layout_height is already wrap_content and also the second tab loads all the data as expected.

  • And some others answers mentioned to used same versions for all support libraries and I'm already using 25.1.0 version for all the support libraries.

  • Size of the data array is 20 and returning 20 from the adapter's getItemCount() method.

  • The data array has the expected number of items in it and they are not null or empty.

  • Clean build, invalidate/caches doesn't work either.

  • Finally, I'm using FragmentStatePagerAdapter to load the fragments when the tabs are in focus.

EDIT:

This is how I'm parsing the JSON data received

private void parseLocalDeals(String stringResponse) throws JSONException {     JSONArray localJSONArray = new JSONArray(stringResponse);     // If the array length is less than 10 then display to the end of the JSON data or else     // display 10 items.     int localArrayLength = localJSONArray.length() <= 20 ? localJSONArray.length() : 20;     for (int i = 0; i < localArrayLength; i++) {         // Initialize Temporary variables         int localProductId = 0;         String localSecondTitle = null;         String localImageUrlString = null;         JSONObject localJSONObject = localJSONArray.getJSONObject(i);         if (localJSONObject.has(JSONKeys.KEY_LOCAL_DEAL_ID)) {             localProductId = localJSONObject.getInt(JSONKeys.KEY_LOCAL_DEAL_ID);         }         if (localJSONObject.has(JSONKeys.KEY_LOCAL_DEAL_CATEGORY)) {             localSecondTitle = localJSONObject.getString(JSONKeys.KEY_LOCAL_DEAL_CATEGORY);         }         if (localJSONObject.has(JSONKeys.KEY_LOCAL_DEAL_IMAGE)) {             localImageUrlString = localJSONObject.getString(JSONKeys.KEY_LOCAL_DEAL_IMAGE);         }          if (localImageUrlString != null) {             if (!localImageUrlString.isEmpty()) {                 // Remove the dots at the start of the Product Image String                 while (localImageUrlString.charAt(0) == '.') {                     localImageUrlString = localImageUrlString.replaceFirst(".", "");                 }                 // Replace the spaces in the url with %20 (useful if there is any)                 localImageUrlString = localImageUrlString.replaceAll(" ", "%20");             }         }          LocalDealsDataFields localDealsData = new LocalDealsDataFields();         localDealsData.setLocalDealId(localProductId);         localDealsData.setLocalDealSecondTitle(localSecondTitle);         localDealsData.setLocalDealImage(localImageUrlString);          localDealsDataArray.add(localDealsData);     }      // Initialize the Local Deals List only once and notify the adapter that data set has changed     // from second time. If you initializeRV the localDealsRVAdapter at an early instance and only     // use the notifyDataSetChanged method here then the adapter doesn't update the data. This is     // because the adapter won't update items if the number of previously populated items is zero.     if (localDealsCount == 0) {         if (localArrayLength != 0) {             // Populate the Local Deals list             // Specify an adapter             localDealsRVAdapter = new OthersAdapter(context, localDealsDataArray);             localDealsRecyclerView.setAdapter(localDealsRVAdapter);         } else {             // localArrayLength is 0; which means there are no rv elements to show.             // So, remove the layout             contentMain.setVisibility(View.GONE);             // Show no results layout             showNoResultsIfNoData(localArrayLength);         }     } else {         // Notify the adapter that data set has changed         localDealsRVAdapter.notifyDataSetChanged();     }     // Increase the count since parsing the first set of results are returned     localDealsCount = localDealsCount + 20;     // Remove the progress bar and show the content     prcVisibility.success(); } 

parseLocalDeals method is inside a helper class and it is called by using initializeHotels.initializeRV();

initializeRV() initializes the Recycler view, makes a network call to the server and the received data is passed to the parseLocalDeals method. initializeHotels being an instance variable of the Helper class.

EDIT 2:

For those who wants to explore the code in detail, I've moved the part of the code to another project and shared it on Github. Here is the link https://github.com/gSrikar/TabLayout and to understand the hierarchy check out the README file.

Can anyone tell me what I'm missing?

3 Answers

Answers 1

Not much of an answer but too long for a comment.

I have duplicated (almost) your adapter code and it fully works for me. I believe I have done the same as you. I'm using the same layout file, the same item & same adapter for all tabs. I think there are no problems with your adapter code.

I say 'almost' because I had to change a couple of things since I don't have access to your data. I changed your LocalDealsDataField model to include a BitmapDrawable & I changed onBindViewHolder() to handle it.

    BitmapDrawable lfImage = othersDataArray.get(position).getLocalDealImage();     holder.othersImageView.setBackground(lfImage); 

Since there seems to be no problem with your adapter, I would focus on getting the data or setting up the adapter as your problem. Sorry I can't be of help beyond that.

FYI, here's how I setup the adapter in onCreateView()

    rootView = inflater.inflate(R.layout.recycler_view, container, false);     mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview);     mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));     mAdapter = new OthersAdapter(this.getContext(), list);     mRecyclerView.setAdapter(mAdapter); 

Answers 2

I have looked at your code, problem is same as explained by @ardock

Solution i would like to propose,

You have to change your code at 3 place ::

  1. Inside all Fragment You are using in ViewPager Don't call initializeRESPECTIVEView() from onCreateView method.

  2. Inside LocalFragment make a list of Fragments you are going to use with ViewPager and pass it to BottomSectionsPagerAdapter. and return Fragment from that list from getItem(int position) of BottomSectionsPagerAdapter.

  3. Add Following code to LocalFragment inside useSlidingTabViewPager().

    tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {

       ` @Override     public void onTabSelected(TabLayout.Tab tab) {      }      @Override     public void onTabUnselected(TabLayout.Tab tab) {      }      @Override     public void onTabReselected(TabLayout.Tab tab) {      } });` 

    //Call Respective fragment initializeRESPECTIVEView() method from onTabSelected , you can get fragment instance from list you passed to BottomSectionsPagerAdapter

Answers 3

1. Proposed fix for Marshmallow and Nougat devices. Work in progress

Check your LocalFragment getItem() method using breakpoints.

If you select one page, next page is also initialised and you are sharing the recyclerView etc.

I would move the initialisation outside of getItem() as suggested here:

ViewPager is default to load the next page(Fragment) which you can't change by setOffscreenPageLimit(0). But you can do something to hack. You can implement onPageSelected function in Activity containing the ViewPager. In the next Fragment(which you don't want to load), you write a function let's say showViewContent() where you put in all resource consuming init code and do nothing before onResume() method. Then call showViewContent() function inside onPageSelected. Hope this will help

Read these related questions (the first has possible workarounds to hack the limit to zero):

ViewPager.setOffscreenPageLimit(0) doesn't work as expected

Does ViewPager require a minimum of 1 offscreen pages?

Yes. If I am reading the source code correctly, you should be getting a warning about this in LogCat, something like:

Requested offscreen page limit 0 too small; defaulting to 1

viewPager.setOffscreenPageLimit(couponsPagerAdapter.getCount());

public void setOffscreenPageLimit(int limit) {     if (limit < DEFAULT_OFFSCREEN_PAGES) {         Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "                 + DEFAULT_OFFSCREEN_PAGES);         limit = DEFAULT_OFFSCREEN_PAGES;     }     if (limit != mOffscreenPageLimit) {         mOffscreenPageLimit = limit;         populate();     } } 

2. You are loading a wrong page on Marshmallow and Nougat devices

FragmentStatePagerAdapter first call to getItem() wrong on Nougat devices

This ended up having nothing to do with the FragmentStatePagerAdapter code. Rather, in my fragment, I grabbed a stored object from an array using the string ("id") that I passed to the fragment in init. If I grabbed that stored object by passing in the position of the object in the array there was no problem. Only occurs in devices with Android 7.

FragmentStatePagerAdapter - getItem

A FragmentStatePager adapter will load the current page, and one page either side. That is why it logs 0 and 1 at the same time. When you switch to page 2, it will load page 3 and keep page 1 in memory. Then when you get to page 4 it will not load anything, as 4 was loaded when you scrolled to 3 and there is nothing beyond that. So the int that you're being given in getItem() is NOT the page that is currently being viewed, is the one being loaded into memory. Hope that clears things up for you

These comments are confirmed in this branch and commit

All pages load correctly on Lollipop emulator, last page has an extra issue, see OthersFragment:

enter image description here

enter image description here

Read More